@multiplayer-app/agent 0.1.20 → 0.1.21

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 (290) hide show
  1. package/README.md +14 -7
  2. package/dist/agent/definition.test.js +8 -3
  3. package/dist/agent/definition.test.js.map +1 -1
  4. package/dist/agent/profiles/coding.d.ts +1 -1
  5. package/dist/agent/profiles/coding.d.ts.map +1 -1
  6. package/dist/agent/profiles/coding.js +21 -4
  7. package/dist/agent/profiles/coding.js.map +1 -1
  8. package/dist/agent/profiles/index.js +1 -1
  9. package/dist/agent/profiles/index.js.map +1 -1
  10. package/dist/agent/profiles/research.d.ts.map +1 -1
  11. package/dist/agent/profiles/research.js +2 -2
  12. package/dist/agent/profiles/research.js.map +1 -1
  13. package/dist/agent/turn-history.d.ts.map +1 -1
  14. package/dist/agent/turn-history.js +7 -1
  15. package/dist/agent/turn-history.js.map +1 -1
  16. package/dist/agent/turn-runner.d.ts +8 -0
  17. package/dist/agent/turn-runner.d.ts.map +1 -1
  18. package/dist/agent/turn-runner.js +35 -10
  19. package/dist/agent/turn-runner.js.map +1 -1
  20. package/dist/app/app-host.d.ts +57 -0
  21. package/dist/app/app-host.d.ts.map +1 -0
  22. package/dist/app/app-host.js +252 -0
  23. package/dist/app/app-host.js.map +1 -0
  24. package/dist/app/app-host.test.d.ts +2 -0
  25. package/dist/app/app-host.test.d.ts.map +1 -0
  26. package/dist/app/app-host.test.js +639 -0
  27. package/dist/app/app-host.test.js.map +1 -0
  28. package/dist/app/config.d.ts +196 -0
  29. package/dist/app/config.d.ts.map +1 -0
  30. package/dist/app/config.js +362 -0
  31. package/dist/app/config.js.map +1 -0
  32. package/dist/app/config.test.d.ts +2 -0
  33. package/dist/app/config.test.d.ts.map +1 -0
  34. package/dist/app/config.test.js +224 -0
  35. package/dist/app/config.test.js.map +1 -0
  36. package/dist/app/detect.d.ts +68 -0
  37. package/dist/app/detect.d.ts.map +1 -0
  38. package/dist/app/detect.js +449 -0
  39. package/dist/app/detect.js.map +1 -0
  40. package/dist/app/detect.test.d.ts +2 -0
  41. package/dist/app/detect.test.d.ts.map +1 -0
  42. package/dist/app/detect.test.js +267 -0
  43. package/dist/app/detect.test.js.map +1 -0
  44. package/dist/app/env.d.ts +5 -0
  45. package/dist/app/env.d.ts.map +1 -0
  46. package/dist/app/env.js +22 -0
  47. package/dist/app/env.js.map +1 -0
  48. package/dist/app/functions-cli.d.ts +3 -0
  49. package/dist/app/functions-cli.d.ts.map +1 -0
  50. package/dist/app/functions-cli.js +27 -0
  51. package/dist/app/functions-cli.js.map +1 -0
  52. package/dist/app/functions-host.d.ts +15 -0
  53. package/dist/app/functions-host.d.ts.map +1 -0
  54. package/dist/app/functions-host.js +276 -0
  55. package/dist/app/functions-host.js.map +1 -0
  56. package/dist/app/functions-host.test.d.ts +2 -0
  57. package/dist/app/functions-host.test.d.ts.map +1 -0
  58. package/dist/app/functions-host.test.js +117 -0
  59. package/dist/app/functions-host.test.js.map +1 -0
  60. package/dist/app/functions-routes.d.ts +23 -0
  61. package/dist/app/functions-routes.d.ts.map +1 -0
  62. package/dist/app/functions-routes.js +85 -0
  63. package/dist/app/functions-routes.js.map +1 -0
  64. package/dist/app/functions-routes.test.d.ts +2 -0
  65. package/dist/app/functions-routes.test.d.ts.map +1 -0
  66. package/dist/app/functions-routes.test.js +40 -0
  67. package/dist/app/functions-routes.test.js.map +1 -0
  68. package/dist/app/manifest.d.ts +17 -0
  69. package/dist/app/manifest.d.ts.map +1 -0
  70. package/dist/app/manifest.js +64 -0
  71. package/dist/app/manifest.js.map +1 -0
  72. package/dist/app/manifest.test.d.ts +2 -0
  73. package/dist/app/manifest.test.d.ts.map +1 -0
  74. package/dist/app/manifest.test.js +173 -0
  75. package/dist/app/manifest.test.js.map +1 -0
  76. package/dist/app/release-artifacts.d.ts +39 -0
  77. package/dist/app/release-artifacts.d.ts.map +1 -0
  78. package/dist/app/release-artifacts.js +229 -0
  79. package/dist/app/release-artifacts.js.map +1 -0
  80. package/dist/app/release-artifacts.test.d.ts +2 -0
  81. package/dist/app/release-artifacts.test.d.ts.map +1 -0
  82. package/dist/app/release-artifacts.test.js +295 -0
  83. package/dist/app/release-artifacts.test.js.map +1 -0
  84. package/dist/app/route-pattern.d.ts +23 -0
  85. package/dist/app/route-pattern.d.ts.map +1 -0
  86. package/dist/app/route-pattern.js +339 -0
  87. package/dist/app/route-pattern.js.map +1 -0
  88. package/dist/app/route-pattern.test.d.ts +2 -0
  89. package/dist/app/route-pattern.test.d.ts.map +1 -0
  90. package/dist/app/route-pattern.test.js +187 -0
  91. package/dist/app/route-pattern.test.js.map +1 -0
  92. package/dist/app/rules.d.ts +61 -0
  93. package/dist/app/rules.d.ts.map +1 -0
  94. package/dist/app/rules.js +90 -0
  95. package/dist/app/rules.js.map +1 -0
  96. package/dist/app/rules.test.d.ts +2 -0
  97. package/dist/app/rules.test.d.ts.map +1 -0
  98. package/dist/app/rules.test.js +69 -0
  99. package/dist/app/rules.test.js.map +1 -0
  100. package/dist/app/runner.d.ts +109 -0
  101. package/dist/app/runner.d.ts.map +1 -0
  102. package/dist/app/runner.js +429 -0
  103. package/dist/app/runner.js.map +1 -0
  104. package/dist/app/site.d.ts +73 -0
  105. package/dist/app/site.d.ts.map +1 -0
  106. package/dist/app/site.js +161 -0
  107. package/dist/app/site.js.map +1 -0
  108. package/dist/app/site.test.d.ts +2 -0
  109. package/dist/app/site.test.d.ts.map +1 -0
  110. package/dist/app/site.test.js +291 -0
  111. package/dist/app/site.test.js.map +1 -0
  112. package/dist/app/static-server.d.ts +20 -0
  113. package/dist/app/static-server.d.ts.map +1 -0
  114. package/dist/app/static-server.js +145 -0
  115. package/dist/app/static-server.js.map +1 -0
  116. package/dist/persistence/conversation-store.d.ts +21 -0
  117. package/dist/persistence/conversation-store.d.ts.map +1 -0
  118. package/dist/persistence/conversation-store.js +59 -0
  119. package/dist/persistence/conversation-store.js.map +1 -0
  120. package/dist/persistence/conversation-store.test.d.ts +2 -0
  121. package/dist/persistence/conversation-store.test.d.ts.map +1 -0
  122. package/dist/persistence/conversation-store.test.js +98 -0
  123. package/dist/persistence/conversation-store.test.js.map +1 -0
  124. package/dist/persistence/git-sync.d.ts +14 -1
  125. package/dist/persistence/git-sync.d.ts.map +1 -1
  126. package/dist/persistence/git-sync.js +73 -17
  127. package/dist/persistence/git-sync.js.map +1 -1
  128. package/dist/persistence/git-sync.test.js +155 -6
  129. package/dist/persistence/git-sync.test.js.map +1 -1
  130. package/dist/persistence/snapshot-sync.d.ts +19 -2
  131. package/dist/persistence/snapshot-sync.d.ts.map +1 -1
  132. package/dist/persistence/snapshot-sync.js +194 -83
  133. package/dist/persistence/snapshot-sync.js.map +1 -1
  134. package/dist/persistence/snapshot-sync.test.js +145 -27
  135. package/dist/persistence/snapshot-sync.test.js.map +1 -1
  136. package/dist/persistence/workspace.d.ts +3 -0
  137. package/dist/persistence/workspace.d.ts.map +1 -1
  138. package/dist/persistence/workspace.js +1 -0
  139. package/dist/persistence/workspace.js.map +1 -1
  140. package/dist/research/extract-texts.d.ts.map +1 -1
  141. package/dist/research/extract-texts.js +6 -13
  142. package/dist/research/extract-texts.js.map +1 -1
  143. package/dist/research/filingramp/attachment-tools.d.ts.map +1 -1
  144. package/dist/research/filingramp/attachment-tools.js +7 -4
  145. package/dist/research/filingramp/attachment-tools.js.map +1 -1
  146. package/dist/research/filingramp/shared.d.ts.map +1 -1
  147. package/dist/research/filingramp/shared.js +5 -5
  148. package/dist/research/filingramp/shared.js.map +1 -1
  149. package/dist/runtime/app-mode.d.ts +10 -0
  150. package/dist/runtime/app-mode.d.ts.map +1 -0
  151. package/dist/runtime/app-mode.js +172 -0
  152. package/dist/runtime/app-mode.js.map +1 -0
  153. package/dist/runtime/app-mode.test.d.ts +2 -0
  154. package/dist/runtime/app-mode.test.d.ts.map +1 -0
  155. package/dist/runtime/app-mode.test.js +130 -0
  156. package/dist/runtime/app-mode.test.js.map +1 -0
  157. package/dist/runtime/app-rehearsal.d.ts +2 -0
  158. package/dist/runtime/app-rehearsal.d.ts.map +1 -0
  159. package/dist/runtime/app-rehearsal.js +56 -0
  160. package/dist/runtime/app-rehearsal.js.map +1 -0
  161. package/dist/runtime/build-mode.d.ts +12 -0
  162. package/dist/runtime/build-mode.d.ts.map +1 -0
  163. package/dist/runtime/build-mode.js +116 -0
  164. package/dist/runtime/build-mode.js.map +1 -0
  165. package/dist/runtime/build-mode.test.d.ts +2 -0
  166. package/dist/runtime/build-mode.test.d.ts.map +1 -0
  167. package/dist/runtime/build-mode.test.js +121 -0
  168. package/dist/runtime/build-mode.test.js.map +1 -0
  169. package/dist/runtime/cli.js +7 -2
  170. package/dist/runtime/cli.js.map +1 -1
  171. package/dist/runtime/config.d.ts +4 -0
  172. package/dist/runtime/config.d.ts.map +1 -1
  173. package/dist/runtime/config.js +13 -2
  174. package/dist/runtime/config.js.map +1 -1
  175. package/dist/runtime/guest-server.d.ts +3 -0
  176. package/dist/runtime/guest-server.d.ts.map +1 -0
  177. package/dist/runtime/{lambda-microvm.js → guest-server.js} +49 -18
  178. package/dist/runtime/guest-server.js.map +1 -0
  179. package/dist/runtime/image-hooks.d.ts +5 -0
  180. package/dist/runtime/image-hooks.d.ts.map +1 -0
  181. package/dist/runtime/image-hooks.js +68 -0
  182. package/dist/runtime/image-hooks.js.map +1 -0
  183. package/dist/runtime/image-hooks.test.d.ts +2 -0
  184. package/dist/runtime/image-hooks.test.d.ts.map +1 -0
  185. package/dist/runtime/image-hooks.test.js +74 -0
  186. package/dist/runtime/image-hooks.test.js.map +1 -0
  187. package/dist/runtime/index.d.ts +8 -3
  188. package/dist/runtime/index.d.ts.map +1 -1
  189. package/dist/runtime/index.js +53 -35
  190. package/dist/runtime/index.js.map +1 -1
  191. package/dist/runtime/listening-ports.d.ts +13 -0
  192. package/dist/runtime/listening-ports.d.ts.map +1 -0
  193. package/dist/runtime/listening-ports.js +78 -0
  194. package/dist/runtime/listening-ports.js.map +1 -0
  195. package/dist/runtime/listening-ports.test.d.ts +2 -0
  196. package/dist/runtime/listening-ports.test.d.ts.map +1 -0
  197. package/dist/runtime/listening-ports.test.js +39 -0
  198. package/dist/runtime/listening-ports.test.js.map +1 -0
  199. package/dist/runtime/preview-proxy.d.ts +56 -0
  200. package/dist/runtime/preview-proxy.d.ts.map +1 -0
  201. package/dist/runtime/preview-proxy.js +302 -0
  202. package/dist/runtime/preview-proxy.js.map +1 -0
  203. package/dist/runtime/preview-proxy.test.d.ts +2 -0
  204. package/dist/runtime/preview-proxy.test.d.ts.map +1 -0
  205. package/dist/runtime/preview-proxy.test.js +122 -0
  206. package/dist/runtime/preview-proxy.test.js.map +1 -0
  207. package/dist/runtime/session-mode.d.ts +3 -0
  208. package/dist/runtime/session-mode.d.ts.map +1 -0
  209. package/dist/runtime/session-mode.js +60 -0
  210. package/dist/runtime/session-mode.js.map +1 -0
  211. package/dist/runtime/workload.d.ts +44 -0
  212. package/dist/runtime/workload.d.ts.map +1 -0
  213. package/dist/runtime/workload.js +222 -0
  214. package/dist/runtime/workload.js.map +1 -0
  215. package/dist/runtime/workload.test.d.ts +2 -0
  216. package/dist/runtime/workload.test.d.ts.map +1 -0
  217. package/dist/runtime/workload.test.js +235 -0
  218. package/dist/runtime/workload.test.js.map +1 -0
  219. package/dist/session/conversation.d.ts +3 -2
  220. package/dist/session/conversation.d.ts.map +1 -1
  221. package/dist/session/conversation.js +11 -7
  222. package/dist/session/conversation.js.map +1 -1
  223. package/dist/session/conversation.test.js +2 -3
  224. package/dist/session/conversation.test.js.map +1 -1
  225. package/dist/session/runtime.d.ts +16 -3
  226. package/dist/session/runtime.d.ts.map +1 -1
  227. package/dist/session/runtime.js +80 -13
  228. package/dist/session/runtime.js.map +1 -1
  229. package/dist/session/runtime.test.js +18 -7
  230. package/dist/session/runtime.test.js.map +1 -1
  231. package/dist/session/tools.d.ts.map +1 -1
  232. package/dist/session/tools.js +3 -3
  233. package/dist/session/tools.js.map +1 -1
  234. package/dist/task/loop.d.ts.map +1 -1
  235. package/dist/task/loop.js +6 -4
  236. package/dist/task/loop.js.map +1 -1
  237. package/dist/tools/exec-tools.d.ts +12 -0
  238. package/dist/tools/exec-tools.d.ts.map +1 -1
  239. package/dist/tools/exec-tools.js +46 -3
  240. package/dist/tools/exec-tools.js.map +1 -1
  241. package/dist/tools/exec-tools.test.d.ts +2 -0
  242. package/dist/tools/exec-tools.test.d.ts.map +1 -0
  243. package/dist/tools/exec-tools.test.js +48 -0
  244. package/dist/tools/exec-tools.test.js.map +1 -0
  245. package/dist/tools/fs-tools.d.ts.map +1 -1
  246. package/dist/tools/fs-tools.js +5 -5
  247. package/dist/tools/fs-tools.js.map +1 -1
  248. package/dist/transport/link.d.ts.map +1 -1
  249. package/dist/transport/link.js +16 -5
  250. package/dist/transport/link.js.map +1 -1
  251. package/dist/transport/link.test.js +24 -0
  252. package/dist/transport/link.test.js.map +1 -1
  253. package/dist/transport/protocol.d.ts +190 -3
  254. package/dist/transport/protocol.d.ts.map +1 -1
  255. package/dist/transport/protocol.js +147 -7
  256. package/dist/transport/protocol.js.map +1 -1
  257. package/dist/transport/protocol.test.js +41 -0
  258. package/dist/transport/protocol.test.js.map +1 -1
  259. package/dist/workspace-sync/eligibility.d.ts +14 -0
  260. package/dist/workspace-sync/eligibility.d.ts.map +1 -0
  261. package/dist/workspace-sync/eligibility.js +53 -0
  262. package/dist/workspace-sync/eligibility.js.map +1 -0
  263. package/dist/workspace-sync/merge.d.ts +15 -0
  264. package/dist/workspace-sync/merge.d.ts.map +1 -0
  265. package/dist/workspace-sync/merge.js +66 -0
  266. package/dist/workspace-sync/merge.js.map +1 -0
  267. package/dist/workspace-sync/merge.test.d.ts +2 -0
  268. package/dist/workspace-sync/merge.test.d.ts.map +1 -0
  269. package/dist/workspace-sync/merge.test.js +28 -0
  270. package/dist/workspace-sync/merge.test.js.map +1 -0
  271. package/dist/workspace-sync/workspace-sync.d.ts +48 -0
  272. package/dist/workspace-sync/workspace-sync.d.ts.map +1 -0
  273. package/dist/workspace-sync/workspace-sync.js +308 -0
  274. package/dist/workspace-sync/workspace-sync.js.map +1 -0
  275. package/dist/workspace-sync/workspace-sync.test.d.ts +2 -0
  276. package/dist/workspace-sync/workspace-sync.test.d.ts.map +1 -0
  277. package/dist/workspace-sync/workspace-sync.test.js +111 -0
  278. package/dist/workspace-sync/workspace-sync.test.js.map +1 -0
  279. package/dist/workspace-sync/write-drafts.d.ts +24 -0
  280. package/dist/workspace-sync/write-drafts.d.ts.map +1 -0
  281. package/dist/workspace-sync/write-drafts.js +87 -0
  282. package/dist/workspace-sync/write-drafts.js.map +1 -0
  283. package/dist/workspace-sync/write-drafts.test.d.ts +2 -0
  284. package/dist/workspace-sync/write-drafts.test.d.ts.map +1 -0
  285. package/dist/workspace-sync/write-drafts.test.js +36 -0
  286. package/dist/workspace-sync/write-drafts.test.js.map +1 -0
  287. package/package.json +12 -2
  288. package/dist/runtime/lambda-microvm.d.ts +0 -3
  289. package/dist/runtime/lambda-microvm.d.ts.map +0 -1
  290. package/dist/runtime/lambda-microvm.js.map +0 -1
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.siteContentType = siteContentType;
7
+ exports.createStaticSite = createStaticSite;
8
+ exports.isProjectFilePath = isProjectFilePath;
9
+ exports.findSiteFile = findSiteFile;
10
+ exports.serveStatic = serveStatic;
11
+ // A static service (no command for this mode, or built output in a deployment): its files served
12
+ // by the guest itself, the way Vercel serves a static output — a file when one matches (`/about`
13
+ // finds about.html with cleanUrls), else the service's own rewrites (an SPA's `/index.html`), with
14
+ // its header rules applied to the path asked. Redirects answer before this (rules.ts).
15
+ const node_fs_1 = require("node:fs");
16
+ const node_path_1 = __importDefault(require("node:path"));
17
+ const workload_1 = require("../runtime/workload");
18
+ const protocol_1 = require("../transport/protocol");
19
+ const rules_1 = require("./rules");
20
+ const CONTENT_TYPES = {
21
+ '.html': 'text/html; charset=utf-8',
22
+ '.htm': 'text/html; charset=utf-8',
23
+ '.css': 'text/css; charset=utf-8',
24
+ '.js': 'text/javascript; charset=utf-8',
25
+ '.mjs': 'text/javascript; charset=utf-8',
26
+ '.json': 'application/json; charset=utf-8',
27
+ '.map': 'application/json; charset=utf-8',
28
+ '.txt': 'text/plain; charset=utf-8',
29
+ '.md': 'text/markdown; charset=utf-8',
30
+ '.csv': 'text/csv; charset=utf-8',
31
+ '.xml': 'application/xml; charset=utf-8',
32
+ '.svg': 'image/svg+xml',
33
+ '.png': 'image/png',
34
+ '.jpg': 'image/jpeg',
35
+ '.jpeg': 'image/jpeg',
36
+ '.gif': 'image/gif',
37
+ '.webp': 'image/webp',
38
+ '.avif': 'image/avif',
39
+ '.ico': 'image/x-icon',
40
+ '.woff': 'font/woff',
41
+ '.woff2': 'font/woff2',
42
+ '.ttf': 'font/ttf',
43
+ '.otf': 'font/otf',
44
+ '.wasm': 'application/wasm',
45
+ '.pdf': 'application/pdf',
46
+ '.mp4': 'video/mp4',
47
+ '.webm': 'video/webm',
48
+ '.mp3': 'audio/mpeg',
49
+ };
50
+ /** The Content-Type a site's file is served with; undefined for one it doesn't know. */
51
+ function siteContentType(file) {
52
+ return CONTENT_TYPES[node_path_1.default.extname(file).toLowerCase()];
53
+ }
54
+ function createStaticSite(dir, rules, { hideProjectFiles = false } = {}) {
55
+ return { dir: node_path_1.default.resolve(dir), rules, hideProjectFiles };
56
+ }
57
+ const PROJECT_FILE = /^\/(?:package\.json|package-lock\.json|npm-shrinkwrap\.json|pnpm-lock\.yaml|pnpm-workspace\.yaml|yarn\.lock|bun\.lockb?|requirements\.txt|pyproject\.toml|poetry\.lock|uv\.lock|Pipfile(?:\.lock)?)$/i;
58
+ /** A project file at the top of a site (what describes and installs a service, not what it serves). */
59
+ function isProjectFilePath(pathname) {
60
+ return PROJECT_FILE.test(node_path_1.default.posix.normalize(pathname).replace(/\/+$/, ''));
61
+ }
62
+ /**
63
+ * The file `pathname` names in the site (a directory's index.html), or undefined. Never outside
64
+ * it, and never a dotfile (.env, .git, the agent's .builder) but .well-known. A site that is its
65
+ * service's own folder doesn't hand out that service's project files either.
66
+ */
67
+ async function findFile(site, pathname) {
68
+ if ((0, protocol_1.isHiddenSitePath)(pathname) || (site.hideProjectFiles && isProjectFilePath(pathname)))
69
+ return undefined;
70
+ const candidate = node_path_1.default.resolve(site.dir, `.${pathname}`);
71
+ if (!(0, workload_1.isInsideDir)(site.dir, candidate))
72
+ return undefined;
73
+ try {
74
+ // Compared as real paths: a symlink inside must not lead outside (and the site's own path may be one).
75
+ const root = await node_fs_1.promises.realpath(site.dir);
76
+ let file = await node_fs_1.promises.realpath(candidate);
77
+ if (!(0, workload_1.isInsideDir)(root, file))
78
+ return undefined;
79
+ let stat = await node_fs_1.promises.stat(file);
80
+ if (stat.isDirectory()) {
81
+ file = node_path_1.default.join(file, 'index.html');
82
+ stat = await node_fs_1.promises.stat(file);
83
+ }
84
+ return stat.isFile() ? { file, size: stat.size } : undefined;
85
+ }
86
+ catch (_a) {
87
+ return undefined;
88
+ }
89
+ }
90
+ /** A path's file as a static service finds it: the file itself, its clean URL's page, else its rewrites. */
91
+ async function findSiteFile(rules, pathname, find) {
92
+ let found = await find(pathname);
93
+ if (!found && rules.cleanUrls && pathname !== '/')
94
+ found = await find(`${pathname.replace(/\/+$/, '')}.html`);
95
+ if (!found) {
96
+ const rewritten = (0, rules_1.rewriteFor)(rules, pathname);
97
+ if (rewritten)
98
+ found = await find(rewritten);
99
+ }
100
+ return found;
101
+ }
102
+ function send(res, status, body) {
103
+ res.writeHead(status, { 'Content-Type': 'text/plain; charset=utf-8', 'Content-Length': Buffer.byteLength(body) });
104
+ res.end(body);
105
+ }
106
+ /** Answers `req` from the site; with `next`, what the site can't answer goes there instead of a 404 or 405. */
107
+ async function serveStatic(site, req, res, next) {
108
+ var _a;
109
+ if (req.method !== 'GET' && req.method !== 'HEAD') {
110
+ if (next)
111
+ return next();
112
+ res.setHeader('Allow', 'GET, HEAD');
113
+ return send(res, 405, 'Method Not Allowed');
114
+ }
115
+ let pathname;
116
+ try {
117
+ pathname = decodeURIComponent((0, protocol_1.requestUrl)(req.url).pathname);
118
+ }
119
+ catch (_b) {
120
+ return send(res, 400, 'Bad Request');
121
+ }
122
+ const found = await findSiteFile(site.rules, pathname, (candidate) => findFile(site, candidate));
123
+ if (!found)
124
+ return next ? next() : send(res, 404, 'Not Found');
125
+ // Opened before answering, and only what really is inside: a link swapped in since it was found fails here.
126
+ const opened = await (0, workload_1.openInside)(site.dir, found.file).catch(() => undefined);
127
+ if (!opened)
128
+ return next ? next() : send(res, 404, 'Not Found');
129
+ const headers = {
130
+ 'Content-Type': (_a = CONTENT_TYPES[node_path_1.default.extname(found.file).toLowerCase()]) !== null && _a !== void 0 ? _a : 'application/octet-stream',
131
+ 'Content-Length': (await opened.stat()).size,
132
+ };
133
+ for (const { key, value } of (0, rules_1.headersFor)(site.rules, pathname))
134
+ headers[key] = value;
135
+ res.writeHead(200, headers);
136
+ if (req.method === 'HEAD') {
137
+ await opened.close();
138
+ res.end();
139
+ return;
140
+ }
141
+ const stream = opened.createReadStream();
142
+ stream.on('error', () => res.destroy());
143
+ stream.pipe(res);
144
+ }
145
+ //# sourceMappingURL=static-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-server.js","sourceRoot":"","sources":["../../src/app/static-server.ts"],"names":[],"mappings":";;;;;AA2CA,0CAEC;AASD,4CAEC;AAKD,8CAEC;AA4BD,oCAQC;AAQD,kCAgCC;AA3ID,iGAAiG;AACjG,iGAAiG;AACjG,mGAAmG;AACnG,uFAAuF;AACvF,qCAAwC;AAExC,0DAA4B;AAC5B,kDAA6D;AAC7D,oDAAoE;AACpE,mCAAmE;AAEnE,MAAM,aAAa,GAA2B;IAC5C,OAAO,EAAE,0BAA0B;IACnC,MAAM,EAAE,0BAA0B;IAClC,MAAM,EAAE,yBAAyB;IACjC,KAAK,EAAE,gCAAgC;IACvC,MAAM,EAAE,gCAAgC;IACxC,OAAO,EAAE,iCAAiC;IAC1C,MAAM,EAAE,iCAAiC;IACzC,MAAM,EAAE,2BAA2B;IACnC,KAAK,EAAE,8BAA8B;IACrC,MAAM,EAAE,yBAAyB;IACjC,MAAM,EAAE,gCAAgC;IACxC,MAAM,EAAE,eAAe;IACvB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE,YAAY;IACrB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,cAAc;IACtB,OAAO,EAAE,WAAW;IACpB,QAAQ,EAAE,YAAY;IACtB,MAAM,EAAE,UAAU;IAClB,MAAM,EAAE,UAAU;IAClB,OAAO,EAAE,kBAAkB;IAC3B,MAAM,EAAE,iBAAiB;IACzB,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,YAAY;CACrB,CAAA;AAED,wFAAwF;AACxF,SAAgB,eAAe,CAAC,IAAY;IAC1C,OAAO,aAAa,CAAC,mBAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAA;AACxD,CAAC;AASD,SAAgB,gBAAgB,CAAC,GAAW,EAAE,KAAmB,EAAE,EAAE,gBAAgB,GAAG,KAAK,EAAE,GAAG,EAAE;IAClG,OAAO,EAAE,GAAG,EAAE,mBAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAA;AAC5D,CAAC;AAED,MAAM,YAAY,GAAG,uMAAuM,CAAA;AAE5N,uGAAuG;AACvG,SAAgB,iBAAiB,CAAC,QAAgB;IAChD,OAAO,YAAY,CAAC,IAAI,CAAC,mBAAI,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAA;AAC9E,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,QAAQ,CAAC,IAAgB,EAAE,QAAgB;IACxD,IAAI,IAAA,2BAAgB,EAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,IAAI,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QAAE,OAAO,SAAS,CAAA;IAC1G,MAAM,SAAS,GAAG,mBAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,QAAQ,EAAE,CAAC,CAAA;IACxD,IAAI,CAAC,IAAA,sBAAW,EAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC;QAAE,OAAO,SAAS,CAAA;IACvD,IAAI,CAAC;QACH,uGAAuG;QACvG,MAAM,IAAI,GAAG,MAAM,kBAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACxC,IAAI,IAAI,GAAG,MAAM,kBAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;QACvC,IAAI,CAAC,IAAA,sBAAW,EAAC,IAAI,EAAE,IAAI,CAAC;YAAE,OAAO,SAAS,CAAA;QAC9C,IAAI,IAAI,GAAG,MAAM,kBAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC9B,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACvB,IAAI,GAAG,mBAAI,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAA;YACpC,IAAI,GAAG,MAAM,kBAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC5B,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;IAC9D,CAAC;IAAC,WAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,4GAA4G;AACrG,KAAK,UAAU,YAAY,CAAI,KAAmB,EAAE,QAAgB,EAAE,IAAkD;IAC7H,IAAI,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAA;IAChC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,SAAS,IAAI,QAAQ,KAAK,GAAG;QAAE,KAAK,GAAG,MAAM,IAAI,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,CAAA;IAC7G,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,SAAS,GAAG,IAAA,kBAAU,EAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;QAC7C,IAAI,SAAS;YAAE,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,CAAA;IAC9C,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,SAAS,IAAI,CAAC,GAAwB,EAAE,MAAc,EAAE,IAAY;IAClE,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,2BAA2B,EAAE,gBAAgB,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACjH,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;AACf,CAAC;AAED,+GAA+G;AACxG,KAAK,UAAU,WAAW,CAAC,IAAgB,EAAE,GAAyB,EAAE,GAAwB,EAAE,IAAiB;;IACxH,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAClD,IAAI,IAAI;YAAE,OAAO,IAAI,EAAE,CAAA;QACvB,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,WAAW,CAAC,CAAA;QACnC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,oBAAoB,CAAC,CAAA;IAC7C,CAAC;IACD,IAAI,QAAgB,CAAA;IACpB,IAAI,CAAC;QACH,QAAQ,GAAG,kBAAkB,CAAC,IAAA,qBAAU,EAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAA;IAC7D,CAAC;IAAC,WAAM,CAAC;QACP,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,aAAa,CAAC,CAAA;IACtC,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAA;IAChG,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,WAAW,CAAC,CAAA;IAE9D,4GAA4G;IAC5G,MAAM,MAAM,GAAG,MAAM,IAAA,qBAAU,EAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAA;IAC5E,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,WAAW,CAAC,CAAA;IAC/D,MAAM,OAAO,GAAoC;QAC/C,cAAc,EAAE,MAAA,aAAa,CAAC,mBAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,mCAAI,0BAA0B;QACnG,gBAAgB,EAAE,CAAC,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI;KAC7C,CAAA;IACD,KAAK,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,IAAA,kBAAU,EAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC;QAAE,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;IACnF,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;IAC3B,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC1B,MAAM,MAAM,CAAC,KAAK,EAAE,CAAA;QACpB,GAAG,CAAC,GAAG,EAAE,CAAA;QACT,OAAM;IACR,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,gBAAgB,EAAE,CAAA;IACxC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAA;IACvC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAClB,CAAC"}
@@ -0,0 +1,21 @@
1
+ export interface ConversationStoreConfig {
2
+ /** The session's route in storage (SESSION_STORAGE_URL). */
3
+ url: string;
4
+ token: string;
5
+ /** Where this VM keeps it. */
6
+ file: string;
7
+ }
8
+ export declare class ConversationStore {
9
+ private readonly config;
10
+ private saved?;
11
+ constructor(config: ConversationStoreConfig);
12
+ private request;
13
+ /**
14
+ * Fetches the saved conversation. Only a 404 means there is none: an error must stop the VM
15
+ * from taking a turn with no memory of the session.
16
+ */
17
+ restore(): Promise<void>;
18
+ /** Uploads it if it changed. A failure propagates: checkpointed must mean it's durable. */
19
+ save(): Promise<void>;
20
+ }
21
+ //# sourceMappingURL=conversation-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation-store.d.ts","sourceRoot":"","sources":["../../src/persistence/conversation-store.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,uBAAuB;IACtC,4DAA4D;IAC5D,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAA;CACb;AAMD,qBAAa,iBAAiB;IAGhB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFnC,OAAO,CAAC,KAAK,CAAC,CAAQ;gBAEO,MAAM,EAAE,uBAAuB;IAE5D,OAAO,CAAC,OAAO;IASf;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAS9B,2FAA2F;IACrF,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAY5B"}
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ConversationStore = void 0;
4
+ // A session's conversation, the agent's own record of its turns. It lives in the runtime's state
5
+ // directory, which the session's commands can't read, and is saved beside the session's folder in
6
+ // storage through a route only a VM's token can use: not in the workspace, not in git, and not
7
+ // where a signed-in user could open it. It's how a replacement VM picks up where the last one stopped.
8
+ const node_crypto_1 = require("node:crypto");
9
+ const node_fs_1 = require("node:fs");
10
+ const TIMEOUT_MS = 60000;
11
+ function hashOf(content) {
12
+ return (0, node_crypto_1.createHash)('sha256').update(content).digest('hex');
13
+ }
14
+ class ConversationStore {
15
+ constructor(config) {
16
+ this.config = config;
17
+ }
18
+ request(method, body) {
19
+ return fetch(`${this.config.url}/conversation`, {
20
+ method,
21
+ headers: { Authorization: `Bearer ${this.config.token}` },
22
+ ...(body ? { body: new Uint8Array(body) } : {}),
23
+ signal: AbortSignal.timeout(TIMEOUT_MS),
24
+ });
25
+ }
26
+ /**
27
+ * Fetches the saved conversation. Only a 404 means there is none: an error must stop the VM
28
+ * from taking a turn with no memory of the session.
29
+ */
30
+ async restore() {
31
+ const response = await this.request('GET');
32
+ if (response.status === 404)
33
+ return;
34
+ if (!response.ok)
35
+ throw new Error(`Could not restore the conversation: ${response.status}`);
36
+ const content = Buffer.from(await response.arrayBuffer());
37
+ await node_fs_1.promises.writeFile(this.config.file, content, { mode: 0o600 });
38
+ this.saved = hashOf(content);
39
+ }
40
+ /** Uploads it if it changed. A failure propagates: checkpointed must mean it's durable. */
41
+ async save() {
42
+ const content = await node_fs_1.promises.readFile(this.config.file).catch((error) => {
43
+ if (error.code === 'ENOENT')
44
+ return undefined;
45
+ throw error;
46
+ });
47
+ if (!content)
48
+ return;
49
+ const hash = hashOf(content);
50
+ if (hash === this.saved)
51
+ return;
52
+ const response = await this.request('PUT', content);
53
+ if (!response.ok)
54
+ throw new Error(`Could not save the conversation: ${response.status}`);
55
+ this.saved = hash;
56
+ }
57
+ }
58
+ exports.ConversationStore = ConversationStore;
59
+ //# sourceMappingURL=conversation-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation-store.js","sourceRoot":"","sources":["../../src/persistence/conversation-store.ts"],"names":[],"mappings":";;;AAAA,iGAAiG;AACjG,kGAAkG;AAClG,+FAA+F;AAC/F,uGAAuG;AACvG,6CAAwC;AACxC,qCAAwC;AAExC,MAAM,UAAU,GAAG,KAAM,CAAA;AAUzB,SAAS,MAAM,CAAC,OAAe;IAC7B,OAAO,IAAA,wBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AAC3D,CAAC;AAED,MAAa,iBAAiB;IAG5B,YAA6B,MAA+B;QAA/B,WAAM,GAAN,MAAM,CAAyB;IAAG,CAAC;IAExD,OAAO,CAAC,MAAqB,EAAE,IAAa;QAClD,OAAO,KAAK,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,eAAe,EAAE;YAC9C,MAAM;YACN,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE;YACzD,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/C,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC;SACxC,CAAC,CAAA;IACJ,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,OAAO;QACX,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QAC1C,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;YAAE,OAAM;QACnC,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAA;QAC3F,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAA;QACzD,MAAM,kBAAE,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;QAC9D,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAA;IAC9B,CAAC;IAED,2FAA2F;IAC3F,KAAK,CAAC,IAAI;QACR,MAAM,OAAO,GAAG,MAAM,kBAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAA4B,EAAE,EAAE;YACzF,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;gBAAE,OAAO,SAAS,CAAA;YAC7C,MAAM,KAAK,CAAA;QACb,CAAC,CAAC,CAAA;QACF,IAAI,CAAC,OAAO;YAAE,OAAM;QACpB,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,CAAA;QAC5B,IAAI,IAAI,KAAK,IAAI,CAAC,KAAK;YAAE,OAAM;QAC/B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;QACnD,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAA;QACxF,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;IACnB,CAAC;CACF;AAxCD,8CAwCC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=conversation-store.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation-store.test.d.ts","sourceRoot":"","sources":["../../src/persistence/conversation-store.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const strict_1 = __importDefault(require("node:assert/strict"));
7
+ const node_fs_1 = require("node:fs");
8
+ const node_http_1 = __importDefault(require("node:http"));
9
+ const node_os_1 = __importDefault(require("node:os"));
10
+ const node_path_1 = __importDefault(require("node:path"));
11
+ const node_test_1 = require("node:test");
12
+ const conversation_store_1 = require("./conversation-store");
13
+ (0, node_test_1.describe)('a session\'s saved conversation', () => {
14
+ let root;
15
+ let server;
16
+ let stored;
17
+ let failWith;
18
+ let requests;
19
+ let store;
20
+ let file;
21
+ (0, node_test_1.beforeEach)(async () => {
22
+ root = await node_fs_1.promises.mkdtemp(node_path_1.default.join(node_os_1.default.tmpdir(), 'conversation-store-'));
23
+ file = node_path_1.default.join(root, 'conversation.json');
24
+ stored = undefined;
25
+ failWith = undefined;
26
+ requests = [];
27
+ server = node_http_1.default.createServer((req, res) => {
28
+ requests.push({ method: req.method, url: req.url, authorization: req.headers.authorization });
29
+ if (failWith)
30
+ return void res.writeHead(failWith).end();
31
+ if (req.method === 'PUT') {
32
+ const chunks = [];
33
+ req.on('data', (chunk) => chunks.push(chunk));
34
+ req.on('end', () => {
35
+ stored = Buffer.concat(chunks);
36
+ res.writeHead(204).end();
37
+ });
38
+ return;
39
+ }
40
+ if (!stored)
41
+ return void res.writeHead(404).end();
42
+ res.writeHead(200).end(stored);
43
+ });
44
+ await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
45
+ const { port } = server.address();
46
+ store = new conversation_store_1.ConversationStore({ url: `http://127.0.0.1:${port}/workspaces/a/s`, token: 'tok', file });
47
+ });
48
+ (0, node_test_1.afterEach)(async () => {
49
+ await new Promise((resolve) => server.close(resolve));
50
+ await node_fs_1.promises.rm(root, { recursive: true, force: true });
51
+ });
52
+ (0, node_test_1.it)('asks its own route, with the VM\'s token', async () => {
53
+ await store.restore();
54
+ strict_1.default.deepEqual(requests, [{ method: 'GET', url: '/workspaces/a/s/conversation', authorization: 'Bearer tok' }]);
55
+ });
56
+ (0, node_test_1.it)('has nothing to restore for a new session', async () => {
57
+ await store.restore();
58
+ await strict_1.default.rejects(node_fs_1.promises.access(file));
59
+ });
60
+ (0, node_test_1.it)('stops a VM from starting with no memory when storage fails', async () => {
61
+ for (const status of [401, 403, 500, 503]) {
62
+ failWith = status;
63
+ await strict_1.default.rejects(store.restore(), new RegExp(String(status)));
64
+ }
65
+ });
66
+ (0, node_test_1.it)('restores what was saved, readable only by the runtime', async () => {
67
+ stored = Buffer.from('{"version":1}');
68
+ await store.restore();
69
+ strict_1.default.equal(await node_fs_1.promises.readFile(file, 'utf8'), '{"version":1}');
70
+ strict_1.default.equal((await node_fs_1.promises.stat(file)).mode & 0o077, 0);
71
+ });
72
+ (0, node_test_1.it)('saves only when it changed, including right after restoring it', async () => {
73
+ stored = Buffer.from('saved');
74
+ await store.restore();
75
+ requests = [];
76
+ await store.save();
77
+ strict_1.default.deepEqual(requests, []);
78
+ await node_fs_1.promises.writeFile(file, 'changed');
79
+ await store.save();
80
+ strict_1.default.equal(stored === null || stored === void 0 ? void 0 : stored.toString(), 'changed');
81
+ strict_1.default.equal(requests.length, 1);
82
+ await store.save();
83
+ strict_1.default.equal(requests.length, 1);
84
+ });
85
+ (0, node_test_1.it)('has nothing to save before the first turn', async () => {
86
+ await store.save();
87
+ strict_1.default.deepEqual(requests, []);
88
+ });
89
+ (0, node_test_1.it)('fails a checkpoint it couldn\'t save, and tries again the next time', async () => {
90
+ await node_fs_1.promises.writeFile(file, 'turn');
91
+ failWith = 503;
92
+ await strict_1.default.rejects(store.save(), /503/);
93
+ failWith = undefined;
94
+ await store.save();
95
+ strict_1.default.equal(stored === null || stored === void 0 ? void 0 : stored.toString(), 'turn');
96
+ });
97
+ });
98
+ //# sourceMappingURL=conversation-store.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation-store.test.js","sourceRoot":"","sources":["../../src/persistence/conversation-store.test.ts"],"names":[],"mappings":";;;;;AAAA,gEAAuC;AACvC,qCAAwC;AACxC,0DAA4B;AAE5B,sDAAwB;AACxB,0DAA4B;AAC5B,yCAA+D;AAC/D,6DAAwD;AAExD,IAAA,oBAAQ,EAAC,iCAAiC,EAAE,GAAG,EAAE;IAC/C,IAAI,IAAY,CAAA;IAChB,IAAI,MAAmB,CAAA;IACvB,IAAI,MAA0B,CAAA;IAC9B,IAAI,QAA4B,CAAA;IAChC,IAAI,QAA0E,CAAA;IAC9E,IAAI,KAAwB,CAAA;IAC5B,IAAI,IAAY,CAAA;IAEhB,IAAA,sBAAU,EAAC,KAAK,IAAI,EAAE;QACpB,IAAI,GAAG,MAAM,kBAAE,CAAC,OAAO,CAAC,mBAAI,CAAC,IAAI,CAAC,iBAAE,CAAC,MAAM,EAAE,EAAE,qBAAqB,CAAC,CAAC,CAAA;QACtE,IAAI,GAAG,mBAAI,CAAC,IAAI,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAA;QAC3C,MAAM,GAAG,SAAS,CAAA;QAClB,QAAQ,GAAG,SAAS,CAAA;QACpB,QAAQ,GAAG,EAAE,CAAA;QACb,MAAM,GAAG,mBAAI,CAAC,YAAY,CAAC,CAAC,GAAyB,EAAE,GAAwB,EAAE,EAAE;YACjF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,aAAa,EAAE,GAAG,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC,CAAA;YAC7F,IAAI,QAAQ;gBAAE,OAAO,KAAK,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE,CAAA;YACvD,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;gBACzB,MAAM,MAAM,GAAa,EAAE,CAAA;gBAC3B,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;gBACrD,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;oBACjB,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;oBAC9B,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAA;gBAC1B,CAAC,CAAC,CAAA;gBACF,OAAM;YACR,CAAC;YACD,IAAI,CAAC,MAAM;gBAAE,OAAO,KAAK,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAA;YACjD,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QAChC,CAAC,CAAC,CAAA;QACF,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC,CAAA;QAC5E,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC,OAAO,EAAiB,CAAA;QAChD,KAAK,GAAG,IAAI,sCAAiB,CAAC,EAAE,GAAG,EAAE,oBAAoB,IAAI,iBAAiB,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IACvG,CAAC,CAAC,CAAA;IACF,IAAA,qBAAS,EAAC,KAAK,IAAI,EAAE;QACnB,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAA;QACrD,MAAM,kBAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IACrD,CAAC,CAAC,CAAA;IAEF,IAAA,cAAE,EAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;QACxD,MAAM,KAAK,CAAC,OAAO,EAAE,CAAA;QACrB,gBAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,8BAA8B,EAAE,aAAa,EAAE,YAAY,EAAE,CAAC,CAAC,CAAA;IACnH,CAAC,CAAC,CAAA;IAEF,IAAA,cAAE,EAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;QACxD,MAAM,KAAK,CAAC,OAAO,EAAE,CAAA;QACrB,MAAM,gBAAM,CAAC,OAAO,CAAC,kBAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;IAEF,IAAA,cAAE,EAAC,4DAA4D,EAAE,KAAK,IAAI,EAAE;QAC1E,KAAK,MAAM,MAAM,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;YAC1C,QAAQ,GAAG,MAAM,CAAA;YACjB,MAAM,gBAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;QACnE,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,IAAA,cAAE,EAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA;QACrC,MAAM,KAAK,CAAC,OAAO,EAAE,CAAA;QACrB,gBAAM,CAAC,KAAK,CAAC,MAAM,kBAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,eAAe,CAAC,CAAA;QAC9D,gBAAM,CAAC,KAAK,CAAC,CAAC,MAAM,kBAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,KAAK,EAAE,CAAC,CAAC,CAAA;IACrD,CAAC,CAAC,CAAA;IAEF,IAAA,cAAE,EAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;QAC9E,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QAC7B,MAAM,KAAK,CAAC,OAAO,EAAE,CAAA;QACrB,QAAQ,GAAG,EAAE,CAAA;QACb,MAAM,KAAK,CAAC,IAAI,EAAE,CAAA;QAClB,gBAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;QAC9B,MAAM,kBAAE,CAAC,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;QACnC,MAAM,KAAK,CAAC,IAAI,EAAE,CAAA;QAClB,gBAAM,CAAC,KAAK,CAAC,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,QAAQ,EAAE,EAAE,SAAS,CAAC,CAAA;QAC3C,gBAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;QAChC,MAAM,KAAK,CAAC,IAAI,EAAE,CAAA;QAClB,gBAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;IAClC,CAAC,CAAC,CAAA;IAEF,IAAA,cAAE,EAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,MAAM,KAAK,CAAC,IAAI,EAAE,CAAA;QAClB,gBAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;IAChC,CAAC,CAAC,CAAA;IAEF,IAAA,cAAE,EAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;QACnF,MAAM,kBAAE,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;QAChC,QAAQ,GAAG,GAAG,CAAA;QACd,MAAM,gBAAM,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,KAAK,CAAC,CAAA;QACzC,QAAQ,GAAG,SAAS,CAAA;QACpB,MAAM,KAAK,CAAC,IAAI,EAAE,CAAA;QAClB,gBAAM,CAAC,KAAK,CAAC,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,QAAQ,EAAE,EAAE,MAAM,CAAC,CAAA;IAC1C,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -1,22 +1,35 @@
1
1
  import type { GitSyncConfig } from '../runtime/config';
2
- export declare const WORKSPACE_GITIGNORE: string;
3
2
  export declare class GitSync {
4
3
  private readonly config;
5
4
  private readonly remote;
6
5
  private readonly env;
6
+ readonly gitDir: string;
7
7
  private busy;
8
8
  constructor(config: GitSyncConfig);
9
9
  get dir(): string;
10
10
  /** Bounded: an unreachable git server must delay a boot or a checkpoint, never hang it. */
11
+ private run;
11
12
  private git;
13
+ /** Starts the checkout's git data outside it: `--separate-git-dir` leaves a pointer behind, which nothing needs. */
14
+ private detachGitDir;
12
15
  /** Serializes git operations: a periodic checkpoint must never race a suspend checkpoint. */
13
16
  private serialize;
14
17
  /**
15
18
  * Clone the session branch into the workspace, or pull it when a checkout already exists.
16
19
  * A brand-new session has no branch yet: start an empty repository on it so the first
17
20
  * checkpoint can push. Returns true when previous work was restored.
21
+ *
22
+ * Only the latest commit: a VM works on the files, and a project's history can be long. The
23
+ * server keeps all of it; a push only adds to it.
18
24
  */
19
25
  restore(): Promise<boolean>;
26
+ private excludeLocally;
27
+ /**
28
+ * The platform can commit to this branch too, if this VM was paused or still starting when it did.
29
+ * Refused for that, this VM's files win (people's edits reach it through live sync) with that
30
+ * commit kept in the history: pushing must not stay refused, or no checkpoint would ever land again.
31
+ */
32
+ private push;
20
33
  /** Commit everything and push, including commits left by a previously failed push. */
21
34
  commit(message: string): Promise<string | undefined>;
22
35
  }
@@ -1 +1 @@
1
- {"version":3,"file":"git-sync.d.ts","sourceRoot":"","sources":["../../src/persistence/git-sync.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAKtD,eAAO,MAAM,mBAAmB,QAAkG,CAAA;AAWlI,qBAAa,OAAO;IAKN,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAmB;IACvC,OAAO,CAAC,IAAI,CAAsC;gBAErB,MAAM,EAAE,aAAa;IAiBlD,IAAI,GAAG,IAAI,MAAM,CAEhB;IAED,2FAA2F;IAC3F,OAAO,CAAC,GAAG;IAIX,6FAA6F;IAC7F,OAAO,CAAC,SAAS;IAMjB;;;;OAIG;IACH,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAwB3B,sFAAsF;IACtF,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;CAkBrD"}
1
+ {"version":3,"file":"git-sync.d.ts","sourceRoot":"","sources":["../../src/persistence/git-sync.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAoBtD,qBAAa,OAAO;IAMN,OAAO,CAAC,QAAQ,CAAC,MAAM;IALnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAmB;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,OAAO,CAAC,IAAI,CAAsC;gBAErB,MAAM,EAAE,aAAa;IA4BlD,IAAI,GAAG,IAAI,MAAM,CAEhB;IAED,2FAA2F;IAC3F,OAAO,CAAC,GAAG;IAIX,OAAO,CAAC,GAAG;IAIX,oHAAoH;YACtG,YAAY;IAK1B,6FAA6F;IAC7F,OAAO,CAAC,SAAS;IAMjB;;;;;;;OAOG;IACH,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;YA0Bb,cAAc;IAM5B;;;;OAIG;YACW,IAAI;IAclB,sFAAsF;IACtF,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;CAgBrD"}
@@ -3,19 +3,27 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.GitSync = exports.WORKSPACE_GITIGNORE = void 0;
6
+ exports.GitSync = void 0;
7
7
  // Durability for a session VM whose disk can vanish (Lambda terminates a long-suspended
8
8
  // MicroVM): the workspace is a checkout of branch `session/<id>` on the platform's git
9
9
  // server. restore() runs at boot, commit() at every checkpoint. Bulk downloads stay out of
10
- // git (see WORKSPACE_GITIGNORE) — the extracted text and the research outputs are what a
10
+ // git (see EXCLUDES) — the extracted text and the research outputs are what a
11
11
  // restored VM needs; attachments can be fetched again.
12
+ //
13
+ // Its git data is kept outside the workspace, in the runtime's state directory. The runtime runs git
14
+ // as root, and a workload owns the workspace: a hook or a .git/config it wrote there would run as
15
+ // root with the token, or send the token to a server of its choosing.
12
16
  const child_process_1 = require("child_process");
13
17
  const fs_1 = require("fs");
14
18
  const path_1 = __importDefault(require("path"));
15
19
  const util_1 = require("util");
16
20
  const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
17
21
  const GIT_TIMEOUT_MS = 60000;
18
- exports.WORKSPACE_GITIGNORE = ['data/attachments/', 'node_modules/', '.venv/', '*.sqlite', '*.sqlite-journal', ''].join('\n');
22
+ /**
23
+ * Never committed, whatever a repository's own .gitignore says: bulk downloads and caches, the app's
24
+ * logs (src/app/runner.ts).
25
+ */
26
+ const EXCLUDES = ['data/attachments/', 'node_modules/', '.venv/', '*.sqlite', '*.sqlite-journal', '.builder/logs/'];
19
27
  async function pathExists(target) {
20
28
  try {
21
29
  await fs_1.promises.access(target);
@@ -27,30 +35,50 @@ async function pathExists(target) {
27
35
  }
28
36
  class GitSync {
29
37
  constructor(config) {
38
+ var _a;
30
39
  this.config = config;
31
40
  this.busy = Promise.resolve();
32
41
  this.remote = `${config.serverUrl}/git/${config.repository}.git`;
42
+ this.gitDir = (_a = config.gitDir) !== null && _a !== void 0 ? _a : `${config.dir}.gitdir`;
33
43
  // The token travels as a per-process http.extraheader, never on the remote URL or in
34
44
  // .git/config, so a `git remote -v` inside the workspace cannot leak it.
35
45
  this.env = {
36
46
  ...process.env,
37
47
  GIT_TERMINAL_PROMPT: '0',
38
- GIT_CONFIG_COUNT: '3',
48
+ // Only this config counts: no user's or system's, and nothing here runs anything found in the
49
+ // workspace. A nested repository's own config can't either, since root doesn't trust its owner.
50
+ GIT_CONFIG_NOSYSTEM: '1',
51
+ GIT_CONFIG_GLOBAL: '/dev/null',
52
+ GIT_CONFIG_COUNT: '6',
39
53
  GIT_CONFIG_KEY_0: 'http.extraheader',
40
54
  GIT_CONFIG_VALUE_0: `Authorization: Bearer ${config.token}`,
41
55
  GIT_CONFIG_KEY_1: 'user.name',
42
56
  GIT_CONFIG_VALUE_1: 'session-agent',
43
57
  GIT_CONFIG_KEY_2: 'user.email',
44
58
  GIT_CONFIG_VALUE_2: 'agent@builder.local',
59
+ GIT_CONFIG_KEY_3: 'core.hooksPath',
60
+ GIT_CONFIG_VALUE_3: '/dev/null',
61
+ GIT_CONFIG_KEY_4: 'core.fsmonitor',
62
+ GIT_CONFIG_VALUE_4: 'false',
63
+ GIT_CONFIG_KEY_5: 'diff.ignoreSubmodules',
64
+ GIT_CONFIG_VALUE_5: 'all',
45
65
  };
46
66
  }
47
67
  get dir() {
48
68
  return this.config.dir;
49
69
  }
50
70
  /** Bounded: an unreachable git server must delay a boot or a checkpoint, never hang it. */
51
- git(args, cwd = this.config.dir) {
71
+ run(args, cwd) {
52
72
  return execFileAsync('git', args, { cwd, env: this.env, maxBuffer: 8 * 1024 * 1024, timeout: GIT_TIMEOUT_MS });
53
73
  }
74
+ git(args) {
75
+ return this.run(['--git-dir', this.gitDir, '--work-tree', this.config.dir, ...args], this.config.dir);
76
+ }
77
+ /** Starts the checkout's git data outside it: `--separate-git-dir` leaves a pointer behind, which nothing needs. */
78
+ async detachGitDir() {
79
+ await fs_1.promises.rm(path_1.default.join(this.config.dir, '.git'), { force: true });
80
+ await this.excludeLocally();
81
+ }
54
82
  /** Serializes git operations: a periodic checkpoint must never race a suspend checkpoint. */
55
83
  serialize(work) {
56
84
  const next = this.busy.then(work, work);
@@ -61,40 +89,69 @@ class GitSync {
61
89
  * Clone the session branch into the workspace, or pull it when a checkout already exists.
62
90
  * A brand-new session has no branch yet: start an empty repository on it so the first
63
91
  * checkpoint can push. Returns true when previous work was restored.
92
+ *
93
+ * Only the latest commit: a VM works on the files, and a project's history can be long. The
94
+ * server keeps all of it; a push only adds to it.
64
95
  */
65
96
  restore() {
66
97
  return this.serialize(async () => {
67
98
  const { dir, branch } = this.config;
68
99
  await fs_1.promises.mkdir(dir, { recursive: true });
69
- if (await pathExists(path_1.default.join(dir, '.git'))) {
100
+ if (await pathExists(path_1.default.join(this.gitDir, 'HEAD'))) {
70
101
  await this.git(['fetch', 'origin', branch]);
71
102
  // Preserve any locally committed checkpoint whose push was interrupted.
72
103
  await this.git(['merge', '--ff-only', 'FETCH_HEAD']);
73
104
  return true;
74
105
  }
106
+ await fs_1.promises.mkdir(path_1.default.dirname(this.gitDir), { recursive: true, mode: 0o700 });
75
107
  // Only a successful lookup with no branch means a new session. A network/auth error
76
108
  // must never let a replacement agent accept a turn against an empty workspace.
77
- const remoteBranches = (await this.git(['ls-remote', '--heads', this.remote, branch], process.cwd())).stdout.trim();
109
+ const remoteBranches = (await this.run(['ls-remote', '--heads', this.remote, branch], process.cwd())).stdout.trim();
78
110
  if (remoteBranches) {
79
- await this.git(['clone', '--branch', branch, '--single-branch', this.remote, dir], process.cwd());
111
+ await this.run(['clone', '--depth', '1', '--branch', branch, '--single-branch', '--separate-git-dir', this.gitDir, this.remote, dir], process.cwd());
112
+ await this.detachGitDir();
80
113
  return true;
81
114
  }
82
- await this.git(['init', '--initial-branch', branch]);
115
+ await this.run(['init', '--initial-branch', branch, '--separate-git-dir', this.gitDir, dir], process.cwd());
116
+ await this.detachGitDir();
83
117
  await this.git(['remote', 'add', 'origin', this.remote]);
84
- await fs_1.promises.writeFile(path_1.default.join(dir, '.gitignore'), exports.WORKSPACE_GITIGNORE);
85
118
  return false;
86
119
  });
87
120
  }
121
+ async excludeLocally() {
122
+ const file = path_1.default.join(this.gitDir, 'info', 'exclude');
123
+ await fs_1.promises.mkdir(path_1.default.dirname(file), { recursive: true });
124
+ await fs_1.promises.writeFile(file, `${EXCLUDES.join('\n')}\n`);
125
+ }
126
+ /**
127
+ * The platform can commit to this branch too, if this VM was paused or still starting when it did.
128
+ * Refused for that, this VM's files win (people's edits reach it through live sync) with that
129
+ * commit kept in the history: pushing must not stay refused, or no checkpoint would ever land again.
130
+ */
131
+ async push(sha) {
132
+ const push = () => this.git(['push', '-u', 'origin', `HEAD:${this.config.branch}`]);
133
+ try {
134
+ await push();
135
+ return sha;
136
+ }
137
+ catch (error) {
138
+ if (!/\[rejected\]|non-fast-forward|fetch first/.test(String(error.stderr)))
139
+ throw error;
140
+ }
141
+ await this.git(['fetch', 'origin', this.config.branch]);
142
+ await this.git(['merge', '-q', '-s', 'ours', '--allow-unrelated-histories', '-m', 'Keep this session\'s files', 'FETCH_HEAD']);
143
+ await push();
144
+ return (await this.git(['rev-parse', 'HEAD'])).stdout.trim();
145
+ }
88
146
  /** Commit everything and push, including commits left by a previously failed push. */
89
147
  commit(message) {
90
148
  return this.serialize(async () => {
91
- if (!(await pathExists(path_1.default.join(this.config.dir, '.gitignore')))) {
92
- await fs_1.promises.writeFile(path_1.default.join(this.config.dir, '.gitignore'), exports.WORKSPACE_GITIGNORE);
93
- }
94
149
  await this.git(['add', '-A']);
95
150
  const status = (await this.git(['status', '--porcelain'])).stdout.trim();
96
- if (status)
97
- await this.git(['commit', '-q', '-m', message]);
151
+ // Even with nothing in it, a new session's first checkpoint starts its branch.
152
+ const started = await this.git(['rev-parse', '--verify', '-q', 'HEAD']).then(() => true, () => false);
153
+ if (status || !started)
154
+ await this.git(['commit', '-q', '--allow-empty', '-m', message]);
98
155
  const sha = (await this.git(['rev-parse', 'HEAD'])).stdout.trim();
99
156
  // No network request for an unchanged, already-pushed workspace. A failed push leaves
100
157
  // the upstream behind HEAD, so a later periodic checkpoint still retries it.
@@ -102,8 +159,7 @@ class GitSync {
102
159
  if ((upstream === null || upstream === void 0 ? void 0 : upstream.stdout.trim()) === sha)
103
160
  return undefined;
104
161
  // Propagate failure: checkpointed must mean the commit actually reached durable storage.
105
- await this.git(['push', '-u', 'origin', `HEAD:${this.config.branch}`]);
106
- return sha;
162
+ return await this.push(sha);
107
163
  });
108
164
  }
109
165
  }
@@ -1 +1 @@
1
- {"version":3,"file":"git-sync.js","sourceRoot":"","sources":["../../src/persistence/git-sync.ts"],"names":[],"mappings":";;;;;;AAAA,wFAAwF;AACxF,uFAAuF;AACvF,2FAA2F;AAC3F,yFAAyF;AACzF,uDAAuD;AACvD,iDAAwC;AACxC,2BAAmC;AACnC,gDAAuB;AACvB,+BAAgC;AAGhC,MAAM,aAAa,GAAG,IAAA,gBAAS,EAAC,wBAAQ,CAAC,CAAA;AACzC,MAAM,cAAc,GAAG,KAAM,CAAA;AAEhB,QAAA,mBAAmB,GAAG,CAAC,mBAAmB,EAAE,eAAe,EAAE,QAAQ,EAAE,UAAU,EAAE,kBAAkB,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAElI,KAAK,UAAU,UAAU,CAAC,MAAc;IACtC,IAAI,CAAC;QACH,MAAM,aAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;QACvB,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,WAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED,MAAa,OAAO;IAKlB,YAA6B,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;QAF1C,SAAI,GAAqB,OAAO,CAAC,OAAO,EAAE,CAAA;QAGhD,IAAI,CAAC,MAAM,GAAG,GAAG,MAAM,CAAC,SAAS,QAAQ,MAAM,CAAC,UAAU,MAAM,CAAA;QAChE,qFAAqF;QACrF,yEAAyE;QACzE,IAAI,CAAC,GAAG,GAAG;YACT,GAAG,OAAO,CAAC,GAAG;YACd,mBAAmB,EAAE,GAAG;YACxB,gBAAgB,EAAE,GAAG;YACrB,gBAAgB,EAAE,kBAAkB;YACpC,kBAAkB,EAAE,yBAAyB,MAAM,CAAC,KAAK,EAAE;YAC3D,gBAAgB,EAAE,WAAW;YAC7B,kBAAkB,EAAE,eAAe;YACnC,gBAAgB,EAAE,YAAY;YAC9B,kBAAkB,EAAE,qBAAqB;SAC1C,CAAA;IACH,CAAC;IAED,IAAI,GAAG;QACL,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAA;IACxB,CAAC;IAED,2FAA2F;IACnF,GAAG,CAAC,IAAc,EAAE,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG;QAC/C,OAAO,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAA;IAChH,CAAC;IAED,6FAA6F;IACrF,SAAS,CAAI,IAAsB;QACzC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QACvC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAA;QACvC,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;;;OAIG;IACH,OAAO;QACL,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,EAAE;YAC/B,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,CAAA;YACnC,MAAM,aAAE,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;YACxC,IAAI,MAAM,UAAU,CAAC,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;gBAC7C,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAA;gBAC3C,wEAAwE;gBACxE,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,WAAW,EAAE,YAAY,CAAC,CAAC,CAAA;gBACpD,OAAO,IAAI,CAAA;YACb,CAAC;YACD,oFAAoF;YACpF,+EAA+E;YAC/E,MAAM,cAAc,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAA;YACnH,IAAI,cAAc,EAAE,CAAC;gBACnB,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,iBAAiB,EAAE,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAA;gBACjG,OAAO,IAAI,CAAA;YACb,CAAC;YACD,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,kBAAkB,EAAE,MAAM,CAAC,CAAC,CAAA;YACpD,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;YACxD,MAAM,aAAE,CAAC,SAAS,CAAC,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,EAAE,2BAAmB,CAAC,CAAA;YACrE,OAAO,KAAK,CAAA;QACd,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,sFAAsF;IACtF,MAAM,CAAC,OAAe;QACpB,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,EAAE;YAC/B,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,cAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;gBAClE,MAAM,aAAE,CAAC,SAAS,CAAC,cAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,YAAY,CAAC,EAAE,2BAAmB,CAAC,CAAA;YACnF,CAAC;YACD,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAA;YAC7B,MAAM,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAA;YACxE,IAAI,MAAM;gBAAE,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAA;YAC3D,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAA;YACjE,sFAAsF;YACtF,6EAA6E;YAC7E,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAA;YAChG,IAAI,CAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,MAAM,CAAC,IAAI,EAAE,MAAK,GAAG;gBAAE,OAAO,SAAS,CAAA;YACrD,yFAAyF;YACzF,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;YACtE,OAAO,GAAG,CAAA;QACZ,CAAC,CAAC,CAAA;IACJ,CAAC;CACF;AAtFD,0BAsFC"}
1
+ {"version":3,"file":"git-sync.js","sourceRoot":"","sources":["../../src/persistence/git-sync.ts"],"names":[],"mappings":"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"}