runwork 0.15.0 → 0.15.2

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 (403) hide show
  1. package/dist/index.js +19272 -116
  2. package/package.json +4 -4
  3. package/dist/__tests__/curl-parser.test.d.ts +0 -1
  4. package/dist/__tests__/curl-parser.test.js +0 -250
  5. package/dist/__tests__/install-scripts.test.d.ts +0 -1
  6. package/dist/__tests__/install-scripts.test.js +0 -280
  7. package/dist/__tests__/types-manager.test.d.ts +0 -1
  8. package/dist/__tests__/types-manager.test.js +0 -89
  9. package/dist/agents/__tests__/chatgpt-registry.test.d.ts +0 -1
  10. package/dist/agents/__tests__/chatgpt-registry.test.js +0 -61
  11. package/dist/agents/__tests__/claude-code-managed-block.test.d.ts +0 -1
  12. package/dist/agents/__tests__/claude-code-managed-block.test.js +0 -97
  13. package/dist/agents/__tests__/claude-code-plugin.test.d.ts +0 -1
  14. package/dist/agents/__tests__/claude-code-plugin.test.js +0 -47
  15. package/dist/agents/__tests__/claude-code-stats.test.d.ts +0 -1
  16. package/dist/agents/__tests__/claude-code-stats.test.js +0 -390
  17. package/dist/agents/__tests__/claude-desktop-memory.test.d.ts +0 -1
  18. package/dist/agents/__tests__/claude-desktop-memory.test.js +0 -154
  19. package/dist/agents/__tests__/claude-desktop-plugin-tree.test.d.ts +0 -1
  20. package/dist/agents/__tests__/claude-desktop-plugin-tree.test.js +0 -161
  21. package/dist/agents/__tests__/claude-desktop-plugin.test.d.ts +0 -1
  22. package/dist/agents/__tests__/claude-desktop-plugin.test.js +0 -117
  23. package/dist/agents/__tests__/claude-desktop-rpm.test.d.ts +0 -1
  24. package/dist/agents/__tests__/claude-desktop-rpm.test.js +0 -126
  25. package/dist/agents/__tests__/claude-desktop-stats.test.d.ts +0 -1
  26. package/dist/agents/__tests__/claude-desktop-stats.test.js +0 -280
  27. package/dist/agents/__tests__/codex-instructions.test.d.ts +0 -1
  28. package/dist/agents/__tests__/codex-instructions.test.js +0 -57
  29. package/dist/agents/__tests__/codex-minimum-permissions.test.d.ts +0 -1
  30. package/dist/agents/__tests__/codex-minimum-permissions.test.js +0 -82
  31. package/dist/agents/__tests__/codex-stats.test.d.ts +0 -1
  32. package/dist/agents/__tests__/codex-stats.test.js +0 -370
  33. package/dist/agents/__tests__/cursor-merge.test.d.ts +0 -1
  34. package/dist/agents/__tests__/cursor-merge.test.js +0 -66
  35. package/dist/agents/__tests__/cursor-stats.test.d.ts +0 -1
  36. package/dist/agents/__tests__/cursor-stats.test.js +0 -183
  37. package/dist/agents/__tests__/defaults-merge.test.d.ts +0 -1
  38. package/dist/agents/__tests__/defaults-merge.test.js +0 -268
  39. package/dist/agents/__tests__/detection.test.d.ts +0 -1
  40. package/dist/agents/__tests__/detection.test.js +0 -89
  41. package/dist/agents/__tests__/graceful-degradation.test.d.ts +0 -1
  42. package/dist/agents/__tests__/graceful-degradation.test.js +0 -129
  43. package/dist/agents/__tests__/instruction-hint.test.d.ts +0 -1
  44. package/dist/agents/__tests__/instruction-hint.test.js +0 -69
  45. package/dist/agents/__tests__/intro-skill.test.d.ts +0 -1
  46. package/dist/agents/__tests__/intro-skill.test.js +0 -193
  47. package/dist/agents/__tests__/schema-validation.test.d.ts +0 -1
  48. package/dist/agents/__tests__/schema-validation.test.js +0 -212
  49. package/dist/agents/__tests__/skill-slug.test.d.ts +0 -1
  50. package/dist/agents/__tests__/skill-slug.test.js +0 -77
  51. package/dist/agents/claude-code.d.ts +0 -53
  52. package/dist/agents/claude-code.js +0 -754
  53. package/dist/agents/claude-desktop-plugin-tree.d.ts +0 -59
  54. package/dist/agents/claude-desktop-plugin-tree.js +0 -143
  55. package/dist/agents/claude-desktop.d.ts +0 -47
  56. package/dist/agents/claude-desktop.js +0 -684
  57. package/dist/agents/cline.d.ts +0 -15
  58. package/dist/agents/cline.js +0 -130
  59. package/dist/agents/codex.d.ts +0 -44
  60. package/dist/agents/codex.js +0 -453
  61. package/dist/agents/conversation-skills.d.ts +0 -18
  62. package/dist/agents/conversation-skills.js +0 -229
  63. package/dist/agents/cursor.d.ts +0 -48
  64. package/dist/agents/cursor.js +0 -324
  65. package/dist/agents/default-config.d.ts +0 -30
  66. package/dist/agents/default-config.js +0 -67
  67. package/dist/agents/defaults-merge.d.ts +0 -72
  68. package/dist/agents/defaults-merge.js +0 -131
  69. package/dist/agents/detect.d.ts +0 -4
  70. package/dist/agents/detect.js +0 -67
  71. package/dist/agents/detection.d.ts +0 -18
  72. package/dist/agents/detection.js +0 -94
  73. package/dist/agents/gemini.d.ts +0 -15
  74. package/dist/agents/gemini.js +0 -122
  75. package/dist/agents/generic-adapter.d.ts +0 -25
  76. package/dist/agents/generic-adapter.js +0 -151
  77. package/dist/agents/intro-skill.d.ts +0 -45
  78. package/dist/agents/intro-skill.js +0 -447
  79. package/dist/agents/registry-data.d.ts +0 -192
  80. package/dist/agents/registry-data.js +0 -669
  81. package/dist/agents/registry.d.ts +0 -13
  82. package/dist/agents/registry.js +0 -36
  83. package/dist/agents/runtime-detection.d.ts +0 -82
  84. package/dist/agents/runtime-detection.js +0 -271
  85. package/dist/agents/session-start-hook.d.ts +0 -37
  86. package/dist/agents/session-start-hook.js +0 -159
  87. package/dist/agents/types.d.ts +0 -171
  88. package/dist/agents/types.js +0 -75
  89. package/dist/agents/utils/instruction-hint.d.ts +0 -21
  90. package/dist/agents/utils/instruction-hint.js +0 -108
  91. package/dist/agents/utils/json-config.d.ts +0 -19
  92. package/dist/agents/utils/json-config.js +0 -69
  93. package/dist/agents/utils/toml-config.d.ts +0 -8
  94. package/dist/agents/utils/toml-config.js +0 -27
  95. package/dist/agents/windsurf.d.ts +0 -14
  96. package/dist/agents/windsurf.js +0 -102
  97. package/dist/api/__tests__/client.test.d.ts +0 -1
  98. package/dist/api/__tests__/client.test.js +0 -272
  99. package/dist/api/client.d.ts +0 -326
  100. package/dist/api/client.js +0 -427
  101. package/dist/auth/__tests__/login-flow.test.d.ts +0 -1
  102. package/dist/auth/__tests__/login-flow.test.js +0 -101
  103. package/dist/auth/__tests__/store.test.d.ts +0 -1
  104. package/dist/auth/__tests__/store.test.js +0 -132
  105. package/dist/auth/login-flow.d.ts +0 -26
  106. package/dist/auth/login-flow.js +0 -137
  107. package/dist/auth/store.d.ts +0 -5
  108. package/dist/auth/store.js +0 -62
  109. package/dist/commands/__tests__/clone-args.test.d.ts +0 -1
  110. package/dist/commands/__tests__/clone-args.test.js +0 -51
  111. package/dist/commands/__tests__/clone-source-result.test.d.ts +0 -1
  112. package/dist/commands/__tests__/clone-source-result.test.js +0 -45
  113. package/dist/commands/__tests__/info-merge.test.d.ts +0 -1
  114. package/dist/commands/__tests__/info-merge.test.js +0 -55
  115. package/dist/commands/__tests__/mcp-entries.test.d.ts +0 -1
  116. package/dist/commands/__tests__/mcp-entries.test.js +0 -48
  117. package/dist/commands/__tests__/setup-persona.test.d.ts +0 -1
  118. package/dist/commands/__tests__/setup-persona.test.js +0 -31
  119. package/dist/commands/__tests__/setup.test.d.ts +0 -1
  120. package/dist/commands/__tests__/setup.test.js +0 -81
  121. package/dist/commands/__tests__/sync-redetect.test.d.ts +0 -1
  122. package/dist/commands/__tests__/sync-redetect.test.js +0 -96
  123. package/dist/commands/__tests__/sync-telemetry.test.d.ts +0 -1
  124. package/dist/commands/__tests__/sync-telemetry.test.js +0 -281
  125. package/dist/commands/__tests__/upgrade.test.d.ts +0 -1
  126. package/dist/commands/__tests__/upgrade.test.js +0 -157
  127. package/dist/commands/agents.d.ts +0 -2
  128. package/dist/commands/agents.js +0 -160
  129. package/dist/commands/api-keys.d.ts +0 -2
  130. package/dist/commands/api-keys.js +0 -95
  131. package/dist/commands/apps.d.ts +0 -2
  132. package/dist/commands/apps.js +0 -82
  133. package/dist/commands/build-plugin.d.ts +0 -2
  134. package/dist/commands/build-plugin.js +0 -135
  135. package/dist/commands/clone.d.ts +0 -60
  136. package/dist/commands/clone.js +0 -271
  137. package/dist/commands/components.d.ts +0 -2
  138. package/dist/commands/components.js +0 -43
  139. package/dist/commands/deploy.d.ts +0 -2
  140. package/dist/commands/deploy.js +0 -279
  141. package/dist/commands/dev.d.ts +0 -11
  142. package/dist/commands/dev.js +0 -1011
  143. package/dist/commands/doctor.d.ts +0 -2
  144. package/dist/commands/doctor.js +0 -230
  145. package/dist/commands/endpoints.d.ts +0 -2
  146. package/dist/commands/endpoints.js +0 -189
  147. package/dist/commands/entities.d.ts +0 -2
  148. package/dist/commands/entities.js +0 -198
  149. package/dist/commands/files.d.ts +0 -2
  150. package/dist/commands/files.js +0 -193
  151. package/dist/commands/inbox.d.ts +0 -11
  152. package/dist/commands/inbox.js +0 -60
  153. package/dist/commands/info.d.ts +0 -178
  154. package/dist/commands/info.js +0 -455
  155. package/dist/commands/init.d.ts +0 -21
  156. package/dist/commands/init.js +0 -185
  157. package/dist/commands/integrations.d.ts +0 -2
  158. package/dist/commands/integrations.js +0 -233
  159. package/dist/commands/login.d.ts +0 -2
  160. package/dist/commands/login.js +0 -44
  161. package/dist/commands/logout.d.ts +0 -2
  162. package/dist/commands/logout.js +0 -13
  163. package/dist/commands/logs.d.ts +0 -2
  164. package/dist/commands/logs.js +0 -232
  165. package/dist/commands/mcp-entries.d.ts +0 -13
  166. package/dist/commands/mcp-entries.js +0 -26
  167. package/dist/commands/mcp.d.ts +0 -2
  168. package/dist/commands/mcp.js +0 -245
  169. package/dist/commands/open.d.ts +0 -2
  170. package/dist/commands/open.js +0 -53
  171. package/dist/commands/resume.d.ts +0 -2
  172. package/dist/commands/resume.js +0 -289
  173. package/dist/commands/save-convo.d.ts +0 -8
  174. package/dist/commands/save-convo.js +0 -20
  175. package/dist/commands/schedules.d.ts +0 -2
  176. package/dist/commands/schedules.js +0 -221
  177. package/dist/commands/setup.d.ts +0 -27
  178. package/dist/commands/setup.js +0 -177
  179. package/dist/commands/share-convo.d.ts +0 -24
  180. package/dist/commands/share-convo.js +0 -167
  181. package/dist/commands/skills.d.ts +0 -2
  182. package/dist/commands/skills.js +0 -352
  183. package/dist/commands/sync-telemetry.d.ts +0 -33
  184. package/dist/commands/sync-telemetry.js +0 -186
  185. package/dist/commands/sync.d.ts +0 -37
  186. package/dist/commands/sync.js +0 -702
  187. package/dist/commands/uninstall.d.ts +0 -2
  188. package/dist/commands/uninstall.js +0 -145
  189. package/dist/commands/upgrade.d.ts +0 -14
  190. package/dist/commands/upgrade.js +0 -217
  191. package/dist/commands/validate.d.ts +0 -2
  192. package/dist/commands/validate.js +0 -89
  193. package/dist/commands/welcome.d.ts +0 -1
  194. package/dist/commands/welcome.js +0 -86
  195. package/dist/commands/workflows.d.ts +0 -2
  196. package/dist/commands/workflows.js +0 -187
  197. package/dist/deploy/__tests__/deploy-state.test.d.ts +0 -1
  198. package/dist/deploy/__tests__/deploy-state.test.js +0 -80
  199. package/dist/deploy/__tests__/deploy-status.test.d.ts +0 -1
  200. package/dist/deploy/__tests__/deploy-status.test.js +0 -41
  201. package/dist/deploy/__tests__/detach-args.test.d.ts +0 -1
  202. package/dist/deploy/__tests__/detach-args.test.js +0 -30
  203. package/dist/deploy/deploy-state.d.ts +0 -36
  204. package/dist/deploy/deploy-state.js +0 -63
  205. package/dist/deploy/deploy-status.d.ts +0 -21
  206. package/dist/deploy/deploy-status.js +0 -36
  207. package/dist/deploy/detach.d.ts +0 -32
  208. package/dist/deploy/detach.js +0 -71
  209. package/dist/dev/__tests__/attach.test.d.ts +0 -1
  210. package/dist/dev/__tests__/attach.test.js +0 -296
  211. package/dist/dev/__tests__/detach.test.d.ts +0 -1
  212. package/dist/dev/__tests__/detach.test.js +0 -404
  213. package/dist/dev/__tests__/preview-url-poller.test.d.ts +0 -1
  214. package/dist/dev/__tests__/preview-url-poller.test.js +0 -149
  215. package/dist/dev/__tests__/session.test.d.ts +0 -1
  216. package/dist/dev/__tests__/session.test.js +0 -446
  217. package/dist/dev/__tests__/startup-sync.test.d.ts +0 -1
  218. package/dist/dev/__tests__/startup-sync.test.js +0 -32
  219. package/dist/dev/__tests__/stop.test.d.ts +0 -1
  220. package/dist/dev/__tests__/stop.test.js +0 -172
  221. package/dist/dev/attach.d.ts +0 -120
  222. package/dist/dev/attach.js +0 -269
  223. package/dist/dev/detach.d.ts +0 -187
  224. package/dist/dev/detach.js +0 -292
  225. package/dist/dev/preview-url-poller.d.ts +0 -35
  226. package/dist/dev/preview-url-poller.js +0 -50
  227. package/dist/dev/session.d.ts +0 -175
  228. package/dist/dev/session.js +0 -258
  229. package/dist/dev/startup-sync.d.ts +0 -23
  230. package/dist/dev/startup-sync.js +0 -14
  231. package/dist/dev/stop.d.ts +0 -52
  232. package/dist/dev/stop.js +0 -101
  233. package/dist/devtools/registry-data.d.ts +0 -46
  234. package/dist/devtools/registry-data.js +0 -40
  235. package/dist/generated/bundled-types.d.ts +0 -1
  236. package/dist/generated/bundled-types.js +0 -46
  237. package/dist/generated/version.d.ts +0 -1
  238. package/dist/generated/version.js +0 -2
  239. package/dist/git/__tests__/auto-commit.test.d.ts +0 -1
  240. package/dist/git/__tests__/auto-commit.test.js +0 -431
  241. package/dist/git/__tests__/classify-sync-error.test.d.ts +0 -1
  242. package/dist/git/__tests__/classify-sync-error.test.js +0 -57
  243. package/dist/git/__tests__/credential-helper-e2e.test.d.ts +0 -21
  244. package/dist/git/__tests__/credential-helper-e2e.test.js +0 -195
  245. package/dist/git/__tests__/credentials.test.d.ts +0 -1
  246. package/dist/git/__tests__/credentials.test.js +0 -141
  247. package/dist/git/__tests__/deploy-guard.test.d.ts +0 -1
  248. package/dist/git/__tests__/deploy-guard.test.js +0 -61
  249. package/dist/git/__tests__/ensure-git-credential-helper.test.d.ts +0 -1
  250. package/dist/git/__tests__/ensure-git-credential-helper.test.js +0 -133
  251. package/dist/git/__tests__/ensure-runwork-remote.test.d.ts +0 -1
  252. package/dist/git/__tests__/ensure-runwork-remote.test.js +0 -109
  253. package/dist/git/__tests__/identity.test.d.ts +0 -1
  254. package/dist/git/__tests__/identity.test.js +0 -146
  255. package/dist/git/__tests__/manifest.test.d.ts +0 -1
  256. package/dist/git/__tests__/manifest.test.js +0 -446
  257. package/dist/git/__tests__/preflight-resolution.test.d.ts +0 -1
  258. package/dist/git/__tests__/preflight-resolution.test.js +0 -366
  259. package/dist/git/__tests__/preflight.test.d.ts +0 -1
  260. package/dist/git/__tests__/preflight.test.js +0 -36
  261. package/dist/git/__tests__/repo-config.test.d.ts +0 -1
  262. package/dist/git/__tests__/repo-config.test.js +0 -26
  263. package/dist/git/__tests__/sync.test.d.ts +0 -1
  264. package/dist/git/__tests__/sync.test.js +0 -405
  265. package/dist/git/auto-commit.d.ts +0 -35
  266. package/dist/git/auto-commit.js +0 -293
  267. package/dist/git/classify-sync-error.d.ts +0 -21
  268. package/dist/git/classify-sync-error.js +0 -111
  269. package/dist/git/credentials.d.ts +0 -75
  270. package/dist/git/credentials.js +0 -164
  271. package/dist/git/critical-files.d.ts +0 -20
  272. package/dist/git/critical-files.js +0 -68
  273. package/dist/git/deploy-guard.d.ts +0 -53
  274. package/dist/git/deploy-guard.js +0 -78
  275. package/dist/git/identity.d.ts +0 -44
  276. package/dist/git/identity.js +0 -133
  277. package/dist/git/preflight.d.ts +0 -57
  278. package/dist/git/preflight.js +0 -276
  279. package/dist/git/remote.d.ts +0 -37
  280. package/dist/git/remote.js +0 -75
  281. package/dist/git/repo-config.d.ts +0 -8
  282. package/dist/git/repo-config.js +0 -29
  283. package/dist/git/sync.d.ts +0 -15
  284. package/dist/git/sync.js +0 -159
  285. package/dist/health/__tests__/checks.test.d.ts +0 -1
  286. package/dist/health/__tests__/checks.test.js +0 -357
  287. package/dist/health/__tests__/cli-distribution-checks.test.d.ts +0 -1
  288. package/dist/health/__tests__/cli-distribution-checks.test.js +0 -196
  289. package/dist/health/__tests__/fix.test.d.ts +0 -1
  290. package/dist/health/__tests__/fix.test.js +0 -72
  291. package/dist/health/__tests__/runner-filter.test.d.ts +0 -1
  292. package/dist/health/__tests__/runner-filter.test.js +0 -61
  293. package/dist/health/checks.d.ts +0 -42
  294. package/dist/health/checks.js +0 -636
  295. package/dist/health/fix.d.ts +0 -22
  296. package/dist/health/fix.js +0 -62
  297. package/dist/health/runner.d.ts +0 -8
  298. package/dist/health/runner.js +0 -47
  299. package/dist/health/types.d.ts +0 -12
  300. package/dist/health/types.js +0 -1
  301. package/dist/index.d.ts +0 -1
  302. package/dist/logs/__tests__/tailer-format.test.d.ts +0 -1
  303. package/dist/logs/__tests__/tailer-format.test.js +0 -43
  304. package/dist/logs/tailer.d.ts +0 -17
  305. package/dist/logs/tailer.js +0 -217
  306. package/dist/sync/__tests__/change-detect.test.d.ts +0 -1
  307. package/dist/sync/__tests__/change-detect.test.js +0 -123
  308. package/dist/sync/__tests__/hash.test.d.ts +0 -1
  309. package/dist/sync/__tests__/hash.test.js +0 -18
  310. package/dist/sync/change-detect.d.ts +0 -19
  311. package/dist/sync/change-detect.js +0 -136
  312. package/dist/sync/conflict-ui.d.ts +0 -5
  313. package/dist/sync/conflict-ui.js +0 -78
  314. package/dist/sync/executor.d.ts +0 -23
  315. package/dist/sync/executor.js +0 -102
  316. package/dist/sync/hash.d.ts +0 -1
  317. package/dist/sync/hash.js +0 -4
  318. package/dist/sync/types.d.ts +0 -24
  319. package/dist/sync/types.js +0 -1
  320. package/dist/template/manifest.d.ts +0 -17
  321. package/dist/template/manifest.js +0 -145
  322. package/dist/tools/types.d.ts +0 -52
  323. package/dist/tools/types.js +0 -8
  324. package/dist/types-manager.d.ts +0 -1
  325. package/dist/types-manager.js +0 -35
  326. package/dist/types.d.ts +0 -349
  327. package/dist/types.js +0 -1
  328. package/dist/ui/__tests__/banner.test.d.ts +0 -1
  329. package/dist/ui/__tests__/banner.test.js +0 -98
  330. package/dist/ui/__tests__/colors.test.d.ts +0 -1
  331. package/dist/ui/__tests__/colors.test.js +0 -22
  332. package/dist/ui/__tests__/keyboard.test.d.ts +0 -1
  333. package/dist/ui/__tests__/keyboard.test.js +0 -34
  334. package/dist/ui/__tests__/status-line.test.d.ts +0 -1
  335. package/dist/ui/__tests__/status-line.test.js +0 -54
  336. package/dist/ui/banner.d.ts +0 -29
  337. package/dist/ui/banner.js +0 -153
  338. package/dist/ui/colors.d.ts +0 -4
  339. package/dist/ui/colors.js +0 -7
  340. package/dist/ui/keyboard.d.ts +0 -12
  341. package/dist/ui/keyboard.js +0 -61
  342. package/dist/ui/status-line.d.ts +0 -6
  343. package/dist/ui/status-line.js +0 -53
  344. package/dist/utils/__tests__/format-error.test.d.ts +0 -1
  345. package/dist/utils/__tests__/format-error.test.js +0 -43
  346. package/dist/utils/__tests__/help-json.test.d.ts +0 -1
  347. package/dist/utils/__tests__/help-json.test.js +0 -39
  348. package/dist/utils/__tests__/http.test.d.ts +0 -1
  349. package/dist/utils/__tests__/http.test.js +0 -381
  350. package/dist/utils/__tests__/ignore-matcher.test.d.ts +0 -1
  351. package/dist/utils/__tests__/ignore-matcher.test.js +0 -205
  352. package/dist/utils/__tests__/output.test.d.ts +0 -1
  353. package/dist/utils/__tests__/output.test.js +0 -38
  354. package/dist/utils/__tests__/prompt.test.d.ts +0 -1
  355. package/dist/utils/__tests__/prompt.test.js +0 -27
  356. package/dist/utils/__tests__/resolve.test.d.ts +0 -1
  357. package/dist/utils/__tests__/resolve.test.js +0 -95
  358. package/dist/utils/__tests__/sqlite.test.d.ts +0 -1
  359. package/dist/utils/__tests__/sqlite.test.js +0 -89
  360. package/dist/utils/agent-guidance.d.ts +0 -47
  361. package/dist/utils/agent-guidance.js +0 -128
  362. package/dist/utils/app-info.d.ts +0 -70
  363. package/dist/utils/app-info.js +0 -167
  364. package/dist/utils/curl-parser.d.ts +0 -12
  365. package/dist/utils/curl-parser.js +0 -162
  366. package/dist/utils/data-input.d.ts +0 -1
  367. package/dist/utils/data-input.js +0 -38
  368. package/dist/utils/format-error.d.ts +0 -10
  369. package/dist/utils/format-error.js +0 -38
  370. package/dist/utils/fs.d.ts +0 -5
  371. package/dist/utils/fs.js +0 -23
  372. package/dist/utils/help-json.d.ts +0 -70
  373. package/dist/utils/help-json.js +0 -88
  374. package/dist/utils/http.d.ts +0 -46
  375. package/dist/utils/http.js +0 -421
  376. package/dist/utils/ignore-matcher.d.ts +0 -47
  377. package/dist/utils/ignore-matcher.js +0 -132
  378. package/dist/utils/output.d.ts +0 -17
  379. package/dist/utils/output.js +0 -27
  380. package/dist/utils/prompt.d.ts +0 -5
  381. package/dist/utils/prompt.js +0 -42
  382. package/dist/utils/resolve.d.ts +0 -12
  383. package/dist/utils/resolve.js +0 -52
  384. package/dist/utils/setup-state.d.ts +0 -3
  385. package/dist/utils/setup-state.js +0 -19
  386. package/dist/utils/sqlite-adapter.d.ts +0 -48
  387. package/dist/utils/sqlite-adapter.js +0 -147
  388. package/dist/utils/sqlite.d.ts +0 -14
  389. package/dist/utils/sqlite.js +0 -14
  390. package/dist/utils/subprocess.d.ts +0 -19
  391. package/dist/utils/subprocess.js +0 -27
  392. package/dist/utils/which.d.ts +0 -14
  393. package/dist/utils/which.js +0 -47
  394. package/dist/utils/zip.d.ts +0 -7
  395. package/dist/utils/zip.js +0 -42
  396. package/dist/validate/__tests__/validate.test.d.ts +0 -1
  397. package/dist/validate/__tests__/validate.test.js +0 -42
  398. package/dist/validate/freshness.d.ts +0 -28
  399. package/dist/validate/freshness.js +0 -48
  400. package/dist/validate/preview.d.ts +0 -21
  401. package/dist/validate/preview.js +0 -39
  402. package/dist/workspace/resolve.d.ts +0 -19
  403. package/dist/workspace/resolve.js +0 -100
@@ -1,195 +0,0 @@
1
- /**
2
- * End-to-end auth test.
3
- *
4
- * Spins up a tiny HTTP server that mimics the runwork.ai git endpoint's
5
- * auth contract (HTTP Basic, any username, password = API key) and runs a
6
- * real `git ls-remote` against it through a credential-helper script. This
7
- * verifies the entire chain we depend on:
8
- *
9
- * git -> credential.<origin>.helper -> our helper script -> our helper's
10
- * protocol output -> git constructs Basic auth -> server accepts it.
11
- *
12
- * Catches the class of bugs we've burned hours on (Pass 1's PATH issues,
13
- * Pass 2's "logged in but no helper registered") *before* a user hits them.
14
- *
15
- * Note: this test exercises the contract our credential helper depends on,
16
- * not the helper function itself -- credentials.test.ts already covers
17
- * `handleGitCredentialRequest()` in isolation. Together they prove that
18
- * (a) the helper produces the right protocol output and (b) git+server
19
- * accept that output as Basic auth.
20
- */
21
- import { describe, it, expect, beforeAll, afterAll } from 'vitest';
22
- import { execFile } from 'child_process';
23
- import { promisify } from 'util';
24
- import { mkdtempSync, writeFileSync, rmSync, chmodSync, existsSync } from 'fs';
25
- import { join } from 'path';
26
- import { tmpdir } from 'os';
27
- import { createServer } from 'http';
28
- import { probeGit } from '../preflight.js';
29
- const execFileAsync = promisify(execFile);
30
- const EXPECTED_API_KEY = 'test-api-key-abcd1234';
31
- /**
32
- * Minimal HTTP server that:
33
- * - Returns 401 + WWW-Authenticate when no Basic auth is supplied
34
- * - Returns 401 when password (the API key) is wrong; username is ignored
35
- * - Returns 200 + a valid empty-refs pkt-line response when auth is correct
36
- *
37
- * The pkt-line response is the smallest valid output for `info/refs?
38
- * service=git-upload-pack` -- the service announcement plus a flush packet.
39
- * That's enough for `git ls-remote` to terminate successfully.
40
- */
41
- function createBasicAuthGitServer(attempts) {
42
- return new Promise((resolve) => {
43
- const server = createServer((req, res) => {
44
- const authHeader = req.headers['authorization'];
45
- if (!authHeader || !authHeader.startsWith('Basic ')) {
46
- attempts.push({ hasAuthHeader: false });
47
- res.writeHead(401, {
48
- 'WWW-Authenticate': 'Basic realm="Test"',
49
- 'Content-Type': 'text/plain',
50
- });
51
- res.end('Authentication required');
52
- return;
53
- }
54
- const decoded = Buffer.from(authHeader.slice(6), 'base64').toString('utf-8');
55
- const colonIdx = decoded.indexOf(':');
56
- const username = colonIdx >= 0 ? decoded.slice(0, colonIdx) : decoded;
57
- const password = colonIdx >= 0 ? decoded.slice(colonIdx + 1) : '';
58
- attempts.push({ hasAuthHeader: true, username, password });
59
- if (password !== EXPECTED_API_KEY) {
60
- res.writeHead(401, {
61
- 'WWW-Authenticate': 'Basic realm="Test"',
62
- 'Content-Type': 'text/plain',
63
- });
64
- res.end('Invalid API key');
65
- return;
66
- }
67
- // Minimal valid info/refs response for git-upload-pack with no refs.
68
- // Shape:
69
- // 001e# service=git-upload-pack\n
70
- // 0000
71
- // 0000 (no refs)
72
- const service = '# service=git-upload-pack\n';
73
- const pktServiceLength = (service.length + 4).toString(16).padStart(4, '0');
74
- const flush = '0000';
75
- const body = `${pktServiceLength}${service}${flush}${flush}`;
76
- res.writeHead(200, {
77
- 'Content-Type': 'application/x-git-upload-pack-advertisement',
78
- 'Cache-Control': 'no-cache',
79
- });
80
- res.end(body);
81
- });
82
- server.listen(0, '127.0.0.1', () => resolve(server));
83
- });
84
- }
85
- /**
86
- * Write a credential helper script into `dir` and return its path. The
87
- * script ignores stdin (test fixtures don't need to honour git's
88
- * action/host inputs) and prints the test's API key. Bash on macOS/Linux
89
- * and Git Bash on Windows both run the resulting `!"<path>"` invocation
90
- * the same way.
91
- */
92
- function writeHelperScript(dir, apiKey) {
93
- const scriptPath = join(dir, 'fake-helper.sh');
94
- const body = [
95
- '#!/usr/bin/env bash',
96
- '# Test fixture: emits the git credential helper "get" protocol output',
97
- '# with a hardcoded API key. The "get" arg is the only one git invokes',
98
- '# during a fetch; "store"/"erase" are no-ops.',
99
- 'if [ "$1" != "get" ]; then exit 0; fi',
100
- '# Drain stdin so git\'s pipe doesn\'t stall.',
101
- 'cat > /dev/null',
102
- 'echo "username=runwork"',
103
- `echo "password=${apiKey}"`,
104
- '',
105
- ].join('\n');
106
- writeFileSync(scriptPath, body, { mode: 0o755 });
107
- // chmod is no-op on Windows but won't error.
108
- chmodSync(scriptPath, 0o755);
109
- return scriptPath;
110
- }
111
- describe('git credential helper e2e (Basic auth contract)', () => {
112
- const gitProbe = probeGit();
113
- const skipReason = !gitProbe.installed ? 'git not installed' : null;
114
- let tmpDir;
115
- let homeDir;
116
- let xdgConfigHome;
117
- let scriptPath;
118
- let server;
119
- let serverUrl;
120
- let attempts = [];
121
- beforeAll(async () => {
122
- if (skipReason)
123
- return;
124
- tmpDir = mkdtempSync(join(tmpdir(), 'runwork-helper-e2e-'));
125
- homeDir = join(tmpDir, 'home');
126
- xdgConfigHome = join(homeDir, '.config');
127
- // git -c gc.auto=0 needs ~/.gitconfig to exist when GIT_CONFIG_GLOBAL is
128
- // pointed at a path that doesn't yet exist; pre-create the dir and
129
- // empty file.
130
- const gitConfigGlobal = join(homeDir, '.gitconfig');
131
- require('fs').mkdirSync(homeDir, { recursive: true });
132
- writeFileSync(gitConfigGlobal, '');
133
- scriptPath = writeHelperScript(tmpDir, EXPECTED_API_KEY);
134
- server = await createBasicAuthGitServer(attempts);
135
- const addr = server.address();
136
- serverUrl = `http://127.0.0.1:${addr.port}`;
137
- // Register the credential helper globally in the isolated git config.
138
- // We use the unscoped `credential.helper` (not `credential.<url>.helper`)
139
- // because (a) the test config is fully isolated so we don't risk
140
- // bleeding into other host auth flows and (b) git's URL matching for
141
- // scoped helpers has subtleties that aren't what we're testing here --
142
- // we're testing the helper *contract*, not git's URL matcher.
143
- const gitBin = gitProbe.path ?? 'git';
144
- await execFileAsync(gitBin, [
145
- 'config', '--file', gitConfigGlobal,
146
- 'credential.helper', `!"${scriptPath}"`,
147
- ]);
148
- });
149
- afterAll(() => {
150
- if (server)
151
- server.close();
152
- if (tmpDir && existsSync(tmpDir))
153
- rmSync(tmpDir, { recursive: true, force: true });
154
- });
155
- it.skipIf(skipReason)('git ls-remote authenticates via the credential helper end-to-end', async () => {
156
- const gitBin = gitProbe.path ?? 'git';
157
- // Use GIT_CONFIG_GLOBAL to isolate from the user's real ~/.gitconfig
158
- // (which may have an auth helper registered for some other host).
159
- const env = {
160
- ...process.env,
161
- GIT_CONFIG_GLOBAL: join(homeDir, '.gitconfig'),
162
- GIT_CONFIG_SYSTEM: '/dev/null',
163
- XDG_CONFIG_HOME: xdgConfigHome,
164
- HOME: homeDir,
165
- // Force git to never prompt -- if the helper fails, we want the
166
- // command to exit non-zero, not hang.
167
- GIT_TERMINAL_PROMPT: '0',
168
- };
169
- const path = '/test-workspace/test-app';
170
- const url = `${serverUrl}${path}`;
171
- // ls-remote against the fake server. Should exit 0 (server accepted
172
- // auth and returned a valid -- empty -- ref advertisement).
173
- const result = await execFileAsync(gitBin, ['ls-remote', url], { env });
174
- expect(result.stdout).toBe('');
175
- // No refs in the test response, so stdout is empty.
176
- // Verify the server actually saw a Basic-auth attempt with our key.
177
- const successAttempt = attempts.find((a) => a.hasAuthHeader && a.password === EXPECTED_API_KEY);
178
- expect(successAttempt).toBeDefined();
179
- expect(successAttempt.username).toBe('runwork');
180
- }, 20_000);
181
- it.skipIf(skipReason)('server rejects requests with no auth (sanity: contract is enforced)', async () => {
182
- // Direct fetch with no Authorization header should 401.
183
- const response = await fetch(`${serverUrl}/whatever`);
184
- expect(response.status).toBe(401);
185
- expect(response.headers.get('www-authenticate')).toContain('Basic');
186
- });
187
- it.skipIf(skipReason)('server rejects requests with the wrong API key (sanity: contract is enforced)', async () => {
188
- const response = await fetch(`${serverUrl}/whatever`, {
189
- headers: {
190
- authorization: `Basic ${Buffer.from('runwork:wrong-key').toString('base64')}`,
191
- },
192
- });
193
- expect(response.status).toBe(401);
194
- });
195
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,141 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- vi.mock('child_process');
3
- vi.mock('../../auth/store.js', () => ({
4
- getCredentials: vi.fn(),
5
- }));
6
- const mockExecFileSync = (await import('child_process')).execFileSync;
7
- const { getCredentials: mockGetCredentials } = await import('../../auth/store.js');
8
- const { configureGitCredentials, removeGitCredentials, handleGitCredentialRequest, buildHelperValue, } = await import('../credentials.js');
9
- describe('git/credentials', () => {
10
- beforeEach(() => {
11
- vi.clearAllMocks();
12
- });
13
- describe('buildHelperValue()', () => {
14
- it('wraps the execPath in quotes and prefixes with !', () => {
15
- expect(buildHelperValue('/usr/local/bin/runwork')).toBe('!"/usr/local/bin/runwork" git-credential-helper');
16
- });
17
- it('normalises Windows backslashes to forward slashes for .gitconfig safety', () => {
18
- expect(buildHelperValue('C:\\Users\\test\\.runwork\\bin\\runwork.exe')).toBe('!"C:/Users/test/.runwork/bin/runwork.exe" git-credential-helper');
19
- });
20
- it('survives spaces in install paths via quoting', () => {
21
- expect(buildHelperValue('C:\\Program Files\\Runwork\\runwork.exe')).toBe('!"C:/Program Files/Runwork/runwork.exe" git-credential-helper');
22
- });
23
- });
24
- describe('configureGitCredentials()', () => {
25
- it('registers the helper using process.execPath, not bare "runwork"', async () => {
26
- await configureGitCredentials('https://runwork.ai/api/git/ws/app');
27
- // Don't pin process.execPath itself (varies per machine), but
28
- // assert the value follows the absolute-path shape so PATH-relative
29
- // regressions are caught.
30
- const call = mockExecFileSync.mock.calls.find((c) => c[0] === 'git' && c[1]?.includes('--global'));
31
- expect(call).toBeDefined();
32
- const args = call[1];
33
- expect(args).toContain('config');
34
- expect(args).toContain('--global');
35
- expect(args).toContain('credential.https://runwork.ai.helper');
36
- const helperValue = args[args.length - 1];
37
- expect(helperValue).toMatch(/^!"[^"]+" git-credential-helper$/);
38
- expect(helperValue).not.toBe('!runwork git-credential-helper');
39
- // The path inside the quotes should be process.execPath, normalised.
40
- expect(helperValue).toContain(process.execPath.replace(/\\/g, '/'));
41
- });
42
- it('extracts origin from full URL', async () => {
43
- await configureGitCredentials('https://custom.runwork.dev/api/git/ws-1/app-1');
44
- const call = mockExecFileSync.mock.calls[0];
45
- const args = call[1];
46
- expect(args[2]).toBe('credential.https://custom.runwork.dev.helper');
47
- });
48
- it('handles URL with port', async () => {
49
- await configureGitCredentials('https://localhost:8787/api/git/ws/app');
50
- const call = mockExecFileSync.mock.calls[0];
51
- const args = call[1];
52
- expect(args[2]).toBe('credential.https://localhost:8787.helper');
53
- });
54
- });
55
- describe('removeGitCredentials()', () => {
56
- it('calls git config --unset', async () => {
57
- await removeGitCredentials('https://runwork.ai');
58
- expect(mockExecFileSync).toHaveBeenCalledWith('git', [
59
- 'config',
60
- '--global',
61
- '--unset',
62
- 'credential.https://runwork.ai.helper',
63
- ], { stdio: 'pipe', windowsHide: true });
64
- });
65
- it('ignores errors silently', async () => {
66
- mockExecFileSync.mockImplementation(() => {
67
- throw new Error('config key not found');
68
- });
69
- // Should not throw
70
- await expect(removeGitCredentials('https://runwork.ai')).resolves.toBeUndefined();
71
- });
72
- });
73
- describe('handleGitCredentialRequest()', () => {
74
- it('ignores non-get actions (store)', async () => {
75
- const writeSpy = vi.spyOn(process.stdout, 'write').mockImplementation(() => true);
76
- await handleGitCredentialRequest('store');
77
- expect(writeSpy).not.toHaveBeenCalled();
78
- writeSpy.mockRestore();
79
- });
80
- it('ignores non-get actions (erase)', async () => {
81
- const writeSpy = vi.spyOn(process.stdout, 'write').mockImplementation(() => true);
82
- await handleGitCredentialRequest('erase');
83
- expect(writeSpy).not.toHaveBeenCalled();
84
- writeSpy.mockRestore();
85
- });
86
- it('exits with code 1 when no credentials stored', async () => {
87
- vi.mocked(mockGetCredentials).mockReturnValue(null);
88
- // Mock stdin to provide input then end
89
- const mockStdin = {
90
- setEncoding: vi.fn(),
91
- on: vi.fn((event, cb) => {
92
- if (event === 'data')
93
- cb('protocol=https\nhost=runwork.ai\n');
94
- if (event === 'end')
95
- cb();
96
- }),
97
- readableEnded: false,
98
- };
99
- const originalStdin = process.stdin;
100
- Object.defineProperty(process, 'stdin', { value: mockStdin, writable: true });
101
- const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => {
102
- throw new Error('process.exit');
103
- }));
104
- await expect(handleGitCredentialRequest('get')).rejects.toThrow('process.exit');
105
- expect(exitSpy).toHaveBeenCalledWith(1);
106
- exitSpy.mockRestore();
107
- Object.defineProperty(process, 'stdin', { value: originalStdin, writable: true });
108
- });
109
- it('outputs correct credential format when credentials exist', async () => {
110
- vi.mocked(mockGetCredentials).mockReturnValue({
111
- apiKey: 'my-api-key',
112
- email: 'test@example.com',
113
- baseUrl: 'https://runwork.ai',
114
- });
115
- const mockStdin = {
116
- setEncoding: vi.fn(),
117
- on: vi.fn((event, cb) => {
118
- if (event === 'data')
119
- cb('protocol=https\nhost=runwork.ai\n');
120
- if (event === 'end')
121
- cb();
122
- }),
123
- readableEnded: false,
124
- };
125
- const originalStdin = process.stdin;
126
- Object.defineProperty(process, 'stdin', { value: mockStdin, writable: true });
127
- const writes = [];
128
- const writeSpy = vi.spyOn(process.stdout, 'write').mockImplementation((data) => {
129
- writes.push(data.toString());
130
- return true;
131
- });
132
- await handleGitCredentialRequest('get');
133
- expect(writes).toContain('protocol=https\n');
134
- expect(writes).toContain('host=runwork.ai\n');
135
- expect(writes).toContain('username=runwork\n');
136
- expect(writes).toContain('password=my-api-key\n');
137
- writeSpy.mockRestore();
138
- Object.defineProperty(process, 'stdin', { value: originalStdin, writable: true });
139
- });
140
- });
141
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,61 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { isDirtyOrAhead, shouldWarnBeforeDeploy, } from '../deploy-guard.js';
3
- import { SESSION_FILE_SCHEMA_VERSION, } from '../../dev/session.js';
4
- function makeSessionFile(overrides = {}) {
5
- return {
6
- version: SESSION_FILE_SCHEMA_VERSION,
7
- pid: process.pid,
8
- sessionId: 'sess_test',
9
- appId: 'test-app',
10
- previewUrl: 'https://test.preview.runwork.dev',
11
- startedAt: 1_700_000_000_000,
12
- bootTime: 1_600_000_000_000,
13
- cliVersion: '0.10.2',
14
- mode: 'foreground',
15
- ...overrides,
16
- };
17
- }
18
- const noSession = { state: 'none' };
19
- const aliveSyncing = { state: 'alive', file: makeSessionFile({ noSync: false }) };
20
- const aliveNoSync = { state: 'alive', file: makeSessionFile({ noSync: true }) };
21
- const aliveLegacy = { state: 'alive', file: makeSessionFile() }; // noSync undefined
22
- const staleSession = { state: 'stale', reason: 'pid-dead', file: makeSessionFile() };
23
- const dirty = { dirty: true, ahead: false };
24
- const ahead = { dirty: false, ahead: true };
25
- const clean = { dirty: false, ahead: false };
26
- describe('isDirtyOrAhead()', () => {
27
- it('is true when dirty', () => {
28
- expect(isDirtyOrAhead(dirty)).toBe(true);
29
- });
30
- it('is true when ahead', () => {
31
- expect(isDirtyOrAhead(ahead)).toBe(true);
32
- });
33
- it('is false when clean and not ahead', () => {
34
- expect(isDirtyOrAhead(clean)).toBe(false);
35
- });
36
- });
37
- describe('shouldWarnBeforeDeploy()', () => {
38
- it('warns: dirty tree + no session', () => {
39
- expect(shouldWarnBeforeDeploy(dirty, noSession)).toBe(true);
40
- });
41
- it('does not warn: dirty tree + active auto-syncing session', () => {
42
- expect(shouldWarnBeforeDeploy(dirty, aliveSyncing)).toBe(false);
43
- });
44
- it('does not warn: dirty tree + active legacy session (noSync undefined treated as syncing)', () => {
45
- expect(shouldWarnBeforeDeploy(dirty, aliveLegacy)).toBe(false);
46
- });
47
- it('warns: dirty tree + active no-sync session', () => {
48
- expect(shouldWarnBeforeDeploy(dirty, aliveNoSync)).toBe(true);
49
- });
50
- it('warns: ahead tree + no session', () => {
51
- expect(shouldWarnBeforeDeploy(ahead, noSession)).toBe(true);
52
- });
53
- it('warns: dirty tree + stale session (watcher not actually running)', () => {
54
- expect(shouldWarnBeforeDeploy(dirty, staleSession)).toBe(true);
55
- });
56
- it('does not warn: clean + not ahead, regardless of session', () => {
57
- expect(shouldWarnBeforeDeploy(clean, noSession)).toBe(false);
58
- expect(shouldWarnBeforeDeploy(clean, aliveSyncing)).toBe(false);
59
- expect(shouldWarnBeforeDeploy(clean, aliveNoSync)).toBe(false);
60
- });
61
- });
@@ -1,133 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- vi.mock('child_process');
3
- vi.mock('fs', () => ({
4
- existsSync: vi.fn(),
5
- }));
6
- vi.mock('../../auth/store.js', () => ({
7
- getCredentials: vi.fn(),
8
- }));
9
- const mockExecFileSync = (await import('child_process')).execFileSync;
10
- const { existsSync: mockExistsSync } = await import('fs');
11
- const { lookupCredentialHelper, helperBinaryStatus, ensureGitCredentialHelper, } = await import('../credentials.js');
12
- /** Build a `git config --get-regexp` stdout block from full config lines. */
13
- function gitConfigOutput(...lines) {
14
- return Buffer.from(lines.join('\n') + '\n');
15
- }
16
- /** True when a recorded execFileSync call wrote a credential helper config. */
17
- function isHelperWrite(call) {
18
- const args = call[1];
19
- return call[0] === 'git'
20
- && Array.isArray(args)
21
- && args.includes('--global')
22
- && args.some(a => /^credential\..*\.helper$/.test(a))
23
- && !args.includes('--get-regexp')
24
- && !args.includes('--unset');
25
- }
26
- describe('git/credentials lazy-ensure', () => {
27
- beforeEach(() => {
28
- vi.clearAllMocks();
29
- });
30
- describe('lookupCredentialHelper()', () => {
31
- it('returns "none" when git has no matching entries (get-regexp exits non-zero)', () => {
32
- mockExecFileSync.mockImplementation(() => {
33
- throw new Error('exit 1'); // git config --get-regexp: no match
34
- });
35
- expect(lookupCredentialHelper('https://runwork.ai')).toEqual({ status: 'none' });
36
- });
37
- it('returns "unscoped" when entries exist but none match the origin', () => {
38
- mockExecFileSync.mockReturnValue(gitConfigOutput('credential.https://runwork-staging.example.com.helper !runwork git-credential-helper'));
39
- expect(lookupCredentialHelper('https://runwork.ai')).toEqual({
40
- status: 'unscoped',
41
- otherCount: 1,
42
- });
43
- });
44
- it('returns "registered" with the helper value when a scoped entry exists', () => {
45
- mockExecFileSync.mockReturnValue(gitConfigOutput('credential.https://runwork.ai.helper !"/usr/local/bin/runwork" git-credential-helper'));
46
- expect(lookupCredentialHelper('https://runwork.ai')).toEqual({
47
- status: 'registered',
48
- value: '!"/usr/local/bin/runwork" git-credential-helper',
49
- });
50
- });
51
- it('matches the correct origin among multiple entries', () => {
52
- mockExecFileSync.mockReturnValue(gitConfigOutput('credential.https://runwork-staging.example.com.helper !runwork git-credential-helper', 'credential.https://runwork.ai.helper !"/usr/local/bin/runwork" git-credential-helper'));
53
- const result = lookupCredentialHelper('https://runwork.ai');
54
- expect(result.status).toBe('registered');
55
- });
56
- });
57
- describe('helperBinaryStatus()', () => {
58
- it('trusts PATH-relative helper values (no on-disk check)', () => {
59
- expect(helperBinaryStatus('!runwork git-credential-helper')).toEqual({ ok: true, path: null });
60
- expect(mockExistsSync).not.toHaveBeenCalled();
61
- });
62
- it('reports ok when an absolute-path binary exists', () => {
63
- vi.mocked(mockExistsSync).mockReturnValue(true);
64
- expect(helperBinaryStatus('!"/usr/local/bin/runwork" git-credential-helper')).toEqual({
65
- ok: true,
66
- path: '/usr/local/bin/runwork',
67
- });
68
- });
69
- it('reports not-ok with the path when an absolute-path binary is missing', () => {
70
- vi.mocked(mockExistsSync).mockReturnValue(false);
71
- expect(helperBinaryStatus('!"/old/path/runwork" git-credential-helper')).toEqual({
72
- ok: false,
73
- path: '/old/path/runwork',
74
- });
75
- });
76
- it('handles Windows absolute paths', () => {
77
- vi.mocked(mockExistsSync).mockReturnValue(true);
78
- const result = helperBinaryStatus('!"C:/Users/test/.runwork/bin/runwork.exe" git-credential-helper');
79
- expect(result.ok).toBe(true);
80
- expect(result.path).toBe('C:/Users/test/.runwork/bin/runwork.exe');
81
- });
82
- });
83
- describe('ensureGitCredentialHelper()', () => {
84
- it('is a no-op when a valid scoped helper is already registered', async () => {
85
- mockExecFileSync.mockImplementation((_file, args) => {
86
- if (args.includes('--get-regexp')) {
87
- return gitConfigOutput('credential.https://runwork.ai.helper !runwork git-credential-helper');
88
- }
89
- return Buffer.from('');
90
- });
91
- await ensureGitCredentialHelper('https://runwork.ai/api/git/ws/app');
92
- // No registration write should have happened.
93
- expect(mockExecFileSync.mock.calls.some(isHelperWrite)).toBe(false);
94
- });
95
- it('registers the helper when none is present (the get_cli_setup path)', async () => {
96
- mockExecFileSync.mockImplementation((_file, args) => {
97
- if (args.includes('--get-regexp')) {
98
- throw new Error('exit 1'); // nothing registered yet
99
- }
100
- return Buffer.from('');
101
- });
102
- await ensureGitCredentialHelper('https://runwork.ai/api/git/ws/app');
103
- const write = mockExecFileSync.mock.calls.find(isHelperWrite);
104
- expect(write).toBeDefined();
105
- expect(write[1]).toContain('credential.https://runwork.ai.helper');
106
- });
107
- it('registers when entries exist but none are scoped to this origin', async () => {
108
- mockExecFileSync.mockImplementation((_file, args) => {
109
- if (args.includes('--get-regexp')) {
110
- return gitConfigOutput('credential.https://other.example.com.helper !runwork git-credential-helper');
111
- }
112
- return Buffer.from('');
113
- });
114
- await ensureGitCredentialHelper('https://runwork.ai');
115
- expect(mockExecFileSync.mock.calls.some(isHelperWrite)).toBe(true);
116
- });
117
- it('repairs a stale helper that points at a missing binary', async () => {
118
- vi.mocked(mockExistsSync).mockReturnValue(false);
119
- mockExecFileSync.mockImplementation((_file, args) => {
120
- if (args.includes('--get-regexp')) {
121
- return gitConfigOutput('credential.https://runwork.ai.helper !"/old/path/runwork" git-credential-helper');
122
- }
123
- return Buffer.from('');
124
- });
125
- await ensureGitCredentialHelper('https://runwork.ai');
126
- expect(mockExecFileSync.mock.calls.some(isHelperWrite)).toBe(true);
127
- });
128
- it('is a no-op for an unparseable baseUrl', async () => {
129
- await ensureGitCredentialHelper('not a url');
130
- expect(mockExecFileSync).not.toHaveBeenCalled();
131
- });
132
- });
133
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,109 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- vi.mock('child_process');
3
- const mockExecFileSync = (await import('child_process')).execFileSync;
4
- const { normalizeRemoteUrl, listRemotes, ensureRunworkRemote, } = await import('../remote.js');
5
- /** Build `git remote -v` stdout from name->url pairs (fetch + push lines). */
6
- function remoteVerbose(pairs) {
7
- const lines = [];
8
- for (const [name, url] of Object.entries(pairs)) {
9
- lines.push(`${name}\t${url} (fetch)`);
10
- lines.push(`${name}\t${url} (push)`);
11
- }
12
- return Buffer.from(lines.join('\n') + '\n');
13
- }
14
- /**
15
- * Drive ensureRunworkRemote/listRemotes against a fixed `git remote -v`
16
- * result, recording any set-url/add mutations.
17
- */
18
- function withRemotes(pairs) {
19
- const setUrl = [];
20
- const add = [];
21
- mockExecFileSync.mockImplementation((_file, args) => {
22
- if (args[0] === 'remote' && args[1] === '-v') {
23
- return remoteVerbose(pairs);
24
- }
25
- if (args[0] === 'remote' && args[1] === 'set-url') {
26
- setUrl.push(args);
27
- return Buffer.from('');
28
- }
29
- if (args[0] === 'remote' && args[1] === 'add') {
30
- add.push(args);
31
- return Buffer.from('');
32
- }
33
- return Buffer.from('');
34
- });
35
- return { setUrl, add };
36
- }
37
- const CANONICAL = 'https://runwork.ai/api/git/ws/app';
38
- describe('git/remote', () => {
39
- beforeEach(() => {
40
- vi.clearAllMocks();
41
- });
42
- describe('normalizeRemoteUrl()', () => {
43
- it('strips a trailing .git', () => {
44
- expect(normalizeRemoteUrl('https://runwork.ai/api/git/ws/app.git')).toBe(CANONICAL);
45
- });
46
- it('strips trailing slashes and lower-cases the host (path preserved)', () => {
47
- expect(normalizeRemoteUrl('https://RunWork.ai/api/git/ws/app/')).toBe(CANONICAL);
48
- });
49
- it('drops userinfo so embedded creds do not break equality', () => {
50
- expect(normalizeRemoteUrl('https://x-access-token:KEY@runwork.ai/api/git/ws/app')).toBe(CANONICAL);
51
- });
52
- it('falls back to a lower-cased trim for scp-style remotes', () => {
53
- expect(normalizeRemoteUrl('git@GitHub.com:Foo/Bar.git')).toBe('git@github.com:foo/bar');
54
- });
55
- });
56
- describe('listRemotes()', () => {
57
- it('parses name -> fetch URL, ignoring push duplicates', () => {
58
- withRemotes({ origin: 'https://example.com/a', runwork: CANONICAL });
59
- expect(listRemotes('/repo')).toEqual({
60
- origin: 'https://example.com/a',
61
- runwork: CANONICAL,
62
- });
63
- });
64
- it('returns {} when git fails (not a repo)', () => {
65
- mockExecFileSync.mockImplementation(() => { throw new Error('not a git repo'); });
66
- expect(listRemotes('/repo')).toEqual({});
67
- });
68
- });
69
- describe('ensureRunworkRemote()', () => {
70
- it('is a no-op when runwork already points at the canonical URL', () => {
71
- const { setUrl, add } = withRemotes({ runwork: CANONICAL });
72
- expect(ensureRunworkRemote('/repo', CANONICAL)).toEqual({ action: 'noop' });
73
- expect(setUrl).toHaveLength(0);
74
- expect(add).toHaveLength(0);
75
- });
76
- it('treats a .git-suffixed existing runwork remote as a match (no rewrite)', () => {
77
- const { setUrl, add } = withRemotes({ runwork: `${CANONICAL}.git` });
78
- expect(ensureRunworkRemote('/repo', CANONICAL)).toEqual({ action: 'noop' });
79
- expect(setUrl).toHaveLength(0);
80
- expect(add).toHaveLength(0);
81
- });
82
- it('repoints an existing runwork remote that points elsewhere', () => {
83
- const { setUrl, add } = withRemotes({ runwork: 'https://runwork.ai/api/git/OLD/app' });
84
- expect(ensureRunworkRemote('/repo', CANONICAL)).toEqual({ action: 'updated' });
85
- expect(setUrl).toHaveLength(1);
86
- expect(setUrl[0]).toEqual(['remote', 'set-url', 'runwork', CANONICAL]);
87
- expect(add).toHaveLength(0);
88
- });
89
- it('adds the runwork remote when missing (clean repo)', () => {
90
- const { setUrl, add } = withRemotes({});
91
- expect(ensureRunworkRemote('/repo', CANONICAL)).toEqual({ action: 'added' });
92
- expect(add).toHaveLength(1);
93
- expect(add[0]).toEqual(['remote', 'add', 'runwork', CANONICAL]);
94
- expect(setUrl).toHaveLength(0);
95
- });
96
- it('recognizes a matching origin (manual git clone) via reusedFrom and still adds the runwork alias', () => {
97
- const { setUrl, add } = withRemotes({ origin: CANONICAL });
98
- expect(ensureRunworkRemote('/repo', CANONICAL)).toEqual({ action: 'added', reusedFrom: 'origin' });
99
- expect(add).toHaveLength(1);
100
- expect(add[0]).toEqual(['remote', 'add', 'runwork', CANONICAL]);
101
- expect(setUrl).toHaveLength(0);
102
- });
103
- it('does not set reusedFrom when no existing remote matches', () => {
104
- withRemotes({ origin: 'https://github.com/someone/fork' });
105
- const result = ensureRunworkRemote('/repo', CANONICAL);
106
- expect(result).toEqual({ action: 'added' });
107
- });
108
- });
109
- });
@@ -1 +0,0 @@
1
- export {};