crewly 1.20.122 → 1.20.124

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 (225) hide show
  1. package/config/skills/agent/core/whatsapp-draft/SKILL.md +80 -0
  2. package/config/skills/agent/core/whatsapp-draft/execute.sh +84 -0
  3. package/config/skills/agent/core/whatsapp-draft/execute.test.sh +70 -0
  4. package/config/skills/agent/core/whatsapp-inbox/SKILL.md +75 -0
  5. package/config/skills/agent/core/whatsapp-inbox/execute.sh +87 -0
  6. package/config/skills/agent/core/whatsapp-inbox/execute.test.sh +68 -0
  7. package/config/skills/agent/core/whatsapp-read/SKILL.md +80 -0
  8. package/config/skills/agent/core/whatsapp-read/execute.sh +116 -0
  9. package/config/skills/agent/core/whatsapp-read/execute.test.sh +84 -0
  10. package/config/skills/agent/core/whatsapp-send/SKILL.md +70 -0
  11. package/config/skills/agent/core/whatsapp-send/execute.sh +84 -0
  12. package/config/skills/agent/core/whatsapp-send/execute.test.sh +79 -0
  13. package/dist/backend/backend/src/constants.d.ts +225 -0
  14. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  15. package/dist/backend/backend/src/constants.js +223 -0
  16. package/dist/backend/backend/src/constants.js.map +1 -1
  17. package/dist/backend/backend/src/controllers/harness/harness.controller.d.ts +54 -0
  18. package/dist/backend/backend/src/controllers/harness/harness.controller.d.ts.map +1 -0
  19. package/dist/backend/backend/src/controllers/harness/harness.controller.js +204 -0
  20. package/dist/backend/backend/src/controllers/harness/harness.controller.js.map +1 -0
  21. package/dist/backend/backend/src/controllers/harness/harness.routes.d.ts +27 -0
  22. package/dist/backend/backend/src/controllers/harness/harness.routes.d.ts.map +1 -0
  23. package/dist/backend/backend/src/controllers/harness/harness.routes.js +43 -0
  24. package/dist/backend/backend/src/controllers/harness/harness.routes.js.map +1 -0
  25. package/dist/backend/backend/src/controllers/whatsapp/whatsapp-inbox.controller.d.ts +73 -0
  26. package/dist/backend/backend/src/controllers/whatsapp/whatsapp-inbox.controller.d.ts.map +1 -0
  27. package/dist/backend/backend/src/controllers/whatsapp/whatsapp-inbox.controller.js +310 -0
  28. package/dist/backend/backend/src/controllers/whatsapp/whatsapp-inbox.controller.js.map +1 -0
  29. package/dist/backend/backend/src/controllers/whatsapp/whatsapp.controller.d.ts.map +1 -1
  30. package/dist/backend/backend/src/controllers/whatsapp/whatsapp.controller.js +53 -4
  31. package/dist/backend/backend/src/controllers/whatsapp/whatsapp.controller.js.map +1 -1
  32. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  33. package/dist/backend/backend/src/routes/api.routes.js +4 -0
  34. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  35. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts +5 -0
  36. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  37. package/dist/backend/backend/src/services/agent/agent-registration.service.js +7 -0
  38. package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
  39. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
  40. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js +5 -0
  41. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
  42. package/dist/backend/backend/src/services/cloud/cloud-client.service.d.ts +2 -1
  43. package/dist/backend/backend/src/services/cloud/cloud-client.service.d.ts.map +1 -1
  44. package/dist/backend/backend/src/services/cloud/cloud-client.service.js +4 -3
  45. package/dist/backend/backend/src/services/cloud/cloud-client.service.js.map +1 -1
  46. package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.d.ts.map +1 -1
  47. package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.js +43 -1
  48. package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.js.map +1 -1
  49. package/dist/backend/backend/src/services/harness/claude-config.utils.d.ts +67 -0
  50. package/dist/backend/backend/src/services/harness/claude-config.utils.d.ts.map +1 -0
  51. package/dist/backend/backend/src/services/harness/claude-config.utils.js +118 -0
  52. package/dist/backend/backend/src/services/harness/claude-config.utils.js.map +1 -0
  53. package/dist/backend/backend/src/services/harness/harness-api-key.service.d.ts +99 -0
  54. package/dist/backend/backend/src/services/harness/harness-api-key.service.d.ts.map +1 -0
  55. package/dist/backend/backend/src/services/harness/harness-api-key.service.js +157 -0
  56. package/dist/backend/backend/src/services/harness/harness-api-key.service.js.map +1 -0
  57. package/dist/backend/backend/src/services/harness/harness-credentials.store.d.ts +135 -0
  58. package/dist/backend/backend/src/services/harness/harness-credentials.store.d.ts.map +1 -0
  59. package/dist/backend/backend/src/services/harness/harness-credentials.store.js +208 -0
  60. package/dist/backend/backend/src/services/harness/harness-credentials.store.js.map +1 -0
  61. package/dist/backend/backend/src/services/harness/harness-exec.utils.d.ts +85 -0
  62. package/dist/backend/backend/src/services/harness/harness-exec.utils.d.ts.map +1 -0
  63. package/dist/backend/backend/src/services/harness/harness-exec.utils.js +183 -0
  64. package/dist/backend/backend/src/services/harness/harness-exec.utils.js.map +1 -0
  65. package/dist/backend/backend/src/services/harness/harness-install.service.d.ts +106 -0
  66. package/dist/backend/backend/src/services/harness/harness-install.service.d.ts.map +1 -0
  67. package/dist/backend/backend/src/services/harness/harness-install.service.js +205 -0
  68. package/dist/backend/backend/src/services/harness/harness-install.service.js.map +1 -0
  69. package/dist/backend/backend/src/services/harness/harness-registry.d.ts +86 -0
  70. package/dist/backend/backend/src/services/harness/harness-registry.d.ts.map +1 -0
  71. package/dist/backend/backend/src/services/harness/harness-registry.js +121 -0
  72. package/dist/backend/backend/src/services/harness/harness-registry.js.map +1 -0
  73. package/dist/backend/backend/src/services/harness/harness-status.service.d.ts +173 -0
  74. package/dist/backend/backend/src/services/harness/harness-status.service.d.ts.map +1 -0
  75. package/dist/backend/backend/src/services/harness/harness-status.service.js +324 -0
  76. package/dist/backend/backend/src/services/harness/harness-status.service.js.map +1 -0
  77. package/dist/backend/backend/src/services/harness/harness.service.d.ts +146 -0
  78. package/dist/backend/backend/src/services/harness/harness.service.d.ts.map +1 -0
  79. package/dist/backend/backend/src/services/harness/harness.service.js +193 -0
  80. package/dist/backend/backend/src/services/harness/harness.service.js.map +1 -0
  81. package/dist/backend/backend/src/services/harness/harness.types.d.ts +138 -0
  82. package/dist/backend/backend/src/services/harness/harness.types.d.ts.map +1 -0
  83. package/dist/backend/backend/src/services/harness/harness.types.js +51 -0
  84. package/dist/backend/backend/src/services/harness/harness.types.js.map +1 -0
  85. package/dist/backend/backend/src/services/harness/login-broker.service.d.ts +238 -0
  86. package/dist/backend/backend/src/services/harness/login-broker.service.d.ts.map +1 -0
  87. package/dist/backend/backend/src/services/harness/login-broker.service.js +495 -0
  88. package/dist/backend/backend/src/services/harness/login-broker.service.js.map +1 -0
  89. package/dist/backend/backend/src/services/harness/login-rules.d.ts +162 -0
  90. package/dist/backend/backend/src/services/harness/login-rules.d.ts.map +1 -0
  91. package/dist/backend/backend/src/services/harness/login-rules.js +344 -0
  92. package/dist/backend/backend/src/services/harness/login-rules.js.map +1 -0
  93. package/dist/backend/backend/src/services/harness/orc-harness.store.d.ts +59 -0
  94. package/dist/backend/backend/src/services/harness/orc-harness.store.d.ts.map +1 -0
  95. package/dist/backend/backend/src/services/harness/orc-harness.store.js +108 -0
  96. package/dist/backend/backend/src/services/harness/orc-harness.store.js.map +1 -0
  97. package/dist/backend/backend/src/services/whatsapp/index.d.ts +5 -1
  98. package/dist/backend/backend/src/services/whatsapp/index.d.ts.map +1 -1
  99. package/dist/backend/backend/src/services/whatsapp/index.js +5 -1
  100. package/dist/backend/backend/src/services/whatsapp/index.js.map +1 -1
  101. package/dist/backend/backend/src/services/whatsapp/whatsapp-connection-config.d.ts +59 -0
  102. package/dist/backend/backend/src/services/whatsapp/whatsapp-connection-config.d.ts.map +1 -0
  103. package/dist/backend/backend/src/services/whatsapp/whatsapp-connection-config.js +108 -0
  104. package/dist/backend/backend/src/services/whatsapp/whatsapp-connection-config.js.map +1 -0
  105. package/dist/backend/backend/src/services/whatsapp/whatsapp-draft-gate.d.ts +74 -0
  106. package/dist/backend/backend/src/services/whatsapp/whatsapp-draft-gate.d.ts.map +1 -0
  107. package/dist/backend/backend/src/services/whatsapp/whatsapp-draft-gate.js +82 -0
  108. package/dist/backend/backend/src/services/whatsapp/whatsapp-draft-gate.js.map +1 -0
  109. package/dist/backend/backend/src/services/whatsapp/whatsapp-inbox-capture.d.ts +184 -0
  110. package/dist/backend/backend/src/services/whatsapp/whatsapp-inbox-capture.d.ts.map +1 -0
  111. package/dist/backend/backend/src/services/whatsapp/whatsapp-inbox-capture.js +420 -0
  112. package/dist/backend/backend/src/services/whatsapp/whatsapp-inbox-capture.js.map +1 -0
  113. package/dist/backend/backend/src/services/whatsapp/whatsapp-inbox.store.d.ts +243 -0
  114. package/dist/backend/backend/src/services/whatsapp/whatsapp-inbox.store.d.ts.map +1 -0
  115. package/dist/backend/backend/src/services/whatsapp/whatsapp-inbox.store.js +538 -0
  116. package/dist/backend/backend/src/services/whatsapp/whatsapp-inbox.store.js.map +1 -0
  117. package/dist/backend/backend/src/services/whatsapp/whatsapp-initializer.d.ts +32 -2
  118. package/dist/backend/backend/src/services/whatsapp/whatsapp-initializer.d.ts.map +1 -1
  119. package/dist/backend/backend/src/services/whatsapp/whatsapp-initializer.js +65 -9
  120. package/dist/backend/backend/src/services/whatsapp/whatsapp-initializer.js.map +1 -1
  121. package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.d.ts.map +1 -1
  122. package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.js +11 -0
  123. package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.js.map +1 -1
  124. package/dist/backend/backend/src/services/whatsapp/whatsapp.service.d.ts +59 -1
  125. package/dist/backend/backend/src/services/whatsapp/whatsapp.service.d.ts.map +1 -1
  126. package/dist/backend/backend/src/services/whatsapp/whatsapp.service.js +159 -9
  127. package/dist/backend/backend/src/services/whatsapp/whatsapp.service.js.map +1 -1
  128. package/dist/backend/backend/src/types/whatsapp.types.d.ts +108 -0
  129. package/dist/backend/backend/src/types/whatsapp.types.d.ts.map +1 -1
  130. package/dist/backend/backend/src/types/whatsapp.types.js +9 -0
  131. package/dist/backend/backend/src/types/whatsapp.types.js.map +1 -1
  132. package/dist/backend/build-info.json +2 -2
  133. package/dist/cli/backend/src/constants.d.ts +225 -0
  134. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  135. package/dist/cli/backend/src/constants.js +223 -0
  136. package/dist/cli/backend/src/constants.js.map +1 -1
  137. package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts +5 -0
  138. package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  139. package/dist/cli/backend/src/services/agent/agent-registration.service.js +7 -0
  140. package/dist/cli/backend/src/services/agent/agent-registration.service.js.map +1 -1
  141. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
  142. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js +5 -0
  143. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
  144. package/dist/cli/backend/src/services/cloud/cloud-client.service.d.ts +2 -1
  145. package/dist/cli/backend/src/services/cloud/cloud-client.service.d.ts.map +1 -1
  146. package/dist/cli/backend/src/services/cloud/cloud-client.service.js +4 -3
  147. package/dist/cli/backend/src/services/cloud/cloud-client.service.js.map +1 -1
  148. package/dist/cli/backend/src/services/harness/claude-config.utils.d.ts +67 -0
  149. package/dist/cli/backend/src/services/harness/claude-config.utils.d.ts.map +1 -0
  150. package/dist/cli/backend/src/services/harness/claude-config.utils.js +118 -0
  151. package/dist/cli/backend/src/services/harness/claude-config.utils.js.map +1 -0
  152. package/dist/cli/backend/src/services/harness/harness-api-key.service.d.ts +99 -0
  153. package/dist/cli/backend/src/services/harness/harness-api-key.service.d.ts.map +1 -0
  154. package/dist/cli/backend/src/services/harness/harness-api-key.service.js +157 -0
  155. package/dist/cli/backend/src/services/harness/harness-api-key.service.js.map +1 -0
  156. package/dist/cli/backend/src/services/harness/harness-credentials.store.d.ts +135 -0
  157. package/dist/cli/backend/src/services/harness/harness-credentials.store.d.ts.map +1 -0
  158. package/dist/cli/backend/src/services/harness/harness-credentials.store.js +208 -0
  159. package/dist/cli/backend/src/services/harness/harness-credentials.store.js.map +1 -0
  160. package/dist/cli/backend/src/services/harness/harness-exec.utils.d.ts +85 -0
  161. package/dist/cli/backend/src/services/harness/harness-exec.utils.d.ts.map +1 -0
  162. package/dist/cli/backend/src/services/harness/harness-exec.utils.js +183 -0
  163. package/dist/cli/backend/src/services/harness/harness-exec.utils.js.map +1 -0
  164. package/dist/cli/backend/src/services/harness/harness-install.service.d.ts +106 -0
  165. package/dist/cli/backend/src/services/harness/harness-install.service.d.ts.map +1 -0
  166. package/dist/cli/backend/src/services/harness/harness-install.service.js +205 -0
  167. package/dist/cli/backend/src/services/harness/harness-install.service.js.map +1 -0
  168. package/dist/cli/backend/src/services/harness/harness-registry.d.ts +86 -0
  169. package/dist/cli/backend/src/services/harness/harness-registry.d.ts.map +1 -0
  170. package/dist/cli/backend/src/services/harness/harness-registry.js +121 -0
  171. package/dist/cli/backend/src/services/harness/harness-registry.js.map +1 -0
  172. package/dist/cli/backend/src/services/harness/harness-status.service.d.ts +173 -0
  173. package/dist/cli/backend/src/services/harness/harness-status.service.d.ts.map +1 -0
  174. package/dist/cli/backend/src/services/harness/harness-status.service.js +324 -0
  175. package/dist/cli/backend/src/services/harness/harness-status.service.js.map +1 -0
  176. package/dist/cli/backend/src/services/harness/harness.service.d.ts +146 -0
  177. package/dist/cli/backend/src/services/harness/harness.service.d.ts.map +1 -0
  178. package/dist/cli/backend/src/services/harness/harness.service.js +193 -0
  179. package/dist/cli/backend/src/services/harness/harness.service.js.map +1 -0
  180. package/dist/cli/backend/src/services/harness/harness.types.d.ts +138 -0
  181. package/dist/cli/backend/src/services/harness/harness.types.d.ts.map +1 -0
  182. package/dist/cli/backend/src/services/harness/harness.types.js +51 -0
  183. package/dist/cli/backend/src/services/harness/harness.types.js.map +1 -0
  184. package/dist/cli/backend/src/services/harness/login-broker.service.d.ts +238 -0
  185. package/dist/cli/backend/src/services/harness/login-broker.service.d.ts.map +1 -0
  186. package/dist/cli/backend/src/services/harness/login-broker.service.js +495 -0
  187. package/dist/cli/backend/src/services/harness/login-broker.service.js.map +1 -0
  188. package/dist/cli/backend/src/services/harness/login-rules.d.ts +162 -0
  189. package/dist/cli/backend/src/services/harness/login-rules.d.ts.map +1 -0
  190. package/dist/cli/backend/src/services/harness/login-rules.js +344 -0
  191. package/dist/cli/backend/src/services/harness/login-rules.js.map +1 -0
  192. package/dist/cli/backend/src/services/harness/orc-harness.store.d.ts +59 -0
  193. package/dist/cli/backend/src/services/harness/orc-harness.store.d.ts.map +1 -0
  194. package/dist/cli/backend/src/services/harness/orc-harness.store.js +108 -0
  195. package/dist/cli/backend/src/services/harness/orc-harness.store.js.map +1 -0
  196. package/dist/cli/cli/src/commands/harness-setup.d.ts +159 -0
  197. package/dist/cli/cli/src/commands/harness-setup.d.ts.map +1 -0
  198. package/dist/cli/cli/src/commands/harness-setup.js +377 -0
  199. package/dist/cli/cli/src/commands/harness-setup.js.map +1 -0
  200. package/dist/cli/cli/src/commands/harness.d.ts +56 -0
  201. package/dist/cli/cli/src/commands/harness.d.ts.map +1 -0
  202. package/dist/cli/cli/src/commands/harness.js +97 -0
  203. package/dist/cli/cli/src/commands/harness.js.map +1 -0
  204. package/dist/cli/cli/src/commands/onboard.d.ts +108 -50
  205. package/dist/cli/cli/src/commands/onboard.d.ts.map +1 -1
  206. package/dist/cli/cli/src/commands/onboard.js +200 -191
  207. package/dist/cli/cli/src/commands/onboard.js.map +1 -1
  208. package/dist/cli/cli/src/constants.d.ts +18 -0
  209. package/dist/cli/cli/src/constants.d.ts.map +1 -1
  210. package/dist/cli/cli/src/constants.js +18 -0
  211. package/dist/cli/cli/src/constants.js.map +1 -1
  212. package/dist/cli/cli/src/index.js +22 -3
  213. package/dist/cli/cli/src/index.js.map +1 -1
  214. package/dist/cli/cli/src/utils/harness-engine.d.ts +99 -0
  215. package/dist/cli/cli/src/utils/harness-engine.d.ts.map +1 -0
  216. package/dist/cli/cli/src/utils/harness-engine.js +143 -0
  217. package/dist/cli/cli/src/utils/harness-engine.js.map +1 -0
  218. package/dist/cli/cli/src/utils/prompt-io.d.ts +25 -0
  219. package/dist/cli/cli/src/utils/prompt-io.d.ts.map +1 -0
  220. package/dist/cli/cli/src/utils/prompt-io.js +47 -0
  221. package/dist/cli/cli/src/utils/prompt-io.js.map +1 -0
  222. package/frontend/dist/assets/{index-8327e63e.css → index-0a2f783c.css} +1 -1
  223. package/frontend/dist/assets/{index-07e338a9.js → index-aaf65055.js} +309 -309
  224. package/frontend/dist/index.html +2 -2
  225. package/package.json +1 -1
@@ -0,0 +1,183 @@
1
+ /**
2
+ * Process helpers for harness onboarding: the PATH every harness process gets
3
+ * and a shell-free command runner.
4
+ *
5
+ * PATH: when `npm install -g` hits EACCES, Crewly installs the harness under a
6
+ * user-owned prefix (`<crewlyHome>/npm-global`). Its `bin` dir is prepended to
7
+ * PATH for everything Crewly spawns — status probes, the login broker and agent
8
+ * sessions — so a harness installed there is found without touching the
9
+ * user's shell profile. Claude Code's native installer dir (`~/.local/bin`) is
10
+ * appended when missing, because a backend started by launchd/systemd often
11
+ * lacks it.
12
+ *
13
+ * @module services/harness/harness-exec.utils
14
+ */
15
+ import { spawn } from 'child_process';
16
+ import * as fs from 'fs';
17
+ import * as os from 'os';
18
+ import * as path from 'path';
19
+ import { HARNESS_CONSTANTS } from '../../constants.js';
20
+ import { getCrewlyHomePath } from '../core/crewly-home.utils.js';
21
+ /**
22
+ * The user-owned npm prefix used when a global install is not permitted.
23
+ *
24
+ * @returns Absolute path, e.g. `~/.crewly/npm-global`
25
+ */
26
+ export function getUserNpmPrefix() {
27
+ return path.join(getCrewlyHomePath(), HARNESS_CONSTANTS.USER_NPM_PREFIX_DIR);
28
+ }
29
+ /**
30
+ * The bin directory of the user-owned npm prefix.
31
+ *
32
+ * @returns Absolute path, e.g. `~/.crewly/npm-global/bin`
33
+ */
34
+ export function getUserNpmBinDir() {
35
+ return path.join(getUserNpmPrefix(), 'bin');
36
+ }
37
+ /**
38
+ * Build the PATH value harness processes run with.
39
+ *
40
+ * Prepends the user npm prefix bin dir and appends `~/.local/bin`, each only
41
+ * when not already present. Order of the existing entries is preserved.
42
+ *
43
+ * @param currentPath - Existing PATH (may be undefined)
44
+ * @param homeDir - Home directory (injectable for tests)
45
+ * @returns The PATH string
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * buildHarnessPath('/usr/bin', '/home/me');
50
+ * // '/home/me/.crewly/npm-global/bin:/usr/bin:/home/me/.local/bin'
51
+ * ```
52
+ */
53
+ export function buildHarnessPath(currentPath, homeDir = os.homedir()) {
54
+ const entries = (currentPath ?? '').split(path.delimiter).filter((entry) => entry.length > 0);
55
+ const npmBin = getUserNpmBinDir();
56
+ const nativeBin = path.join(homeDir, HARNESS_CONSTANTS.NATIVE_INSTALLER_BIN_DIR);
57
+ const result = entries.includes(npmBin) ? [...entries] : [npmBin, ...entries];
58
+ if (!result.includes(nativeBin))
59
+ result.push(nativeBin);
60
+ return result.join(path.delimiter);
61
+ }
62
+ /**
63
+ * PATH for running `npm`: the harness PATH plus the directory of the running
64
+ * Node binary, where npm lives in nvm / installer layouts. A backend started
65
+ * by launchd or systemd often has neither on its PATH.
66
+ *
67
+ * @param currentPath - Existing PATH
68
+ * @param homeDir - Home directory (injectable for tests)
69
+ * @param nodeBinDir - Directory of the Node binary (injectable for tests)
70
+ * @returns The PATH string
71
+ */
72
+ export function buildNpmPath(currentPath, homeDir = os.homedir(), nodeBinDir = path.dirname(process.execPath)) {
73
+ const harnessPath = buildHarnessPath(currentPath, homeDir);
74
+ return harnessPath.split(path.delimiter).includes(nodeBinDir) ? harnessPath : `${harnessPath}${path.delimiter}${nodeBinDir}`;
75
+ }
76
+ /**
77
+ * Copy an environment with PATH set to {@link buildHarnessPath}.
78
+ *
79
+ * @param env - Source environment (defaults to process.env)
80
+ * @returns A new environment object
81
+ */
82
+ export function withHarnessPath(env = process.env) {
83
+ return { ...env, PATH: buildHarnessPath(env.PATH) };
84
+ }
85
+ /**
86
+ * Find an executable on a PATH, like `which`.
87
+ *
88
+ * @param command - Bare command name (or an absolute path, returned when executable)
89
+ * @param envPath - PATH to search
90
+ * @param isExecutable - Executable check (injectable for tests)
91
+ * @returns Absolute path, or null when not found
92
+ */
93
+ export function resolveExecutable(command, envPath, isExecutable = defaultIsExecutable) {
94
+ if (command.includes(path.sep)) {
95
+ return isExecutable(command) ? command : null;
96
+ }
97
+ for (const dir of (envPath ?? '').split(path.delimiter)) {
98
+ if (!dir)
99
+ continue;
100
+ const candidate = path.join(dir, command);
101
+ if (isExecutable(candidate))
102
+ return candidate;
103
+ }
104
+ return null;
105
+ }
106
+ /**
107
+ * Whether a file exists and is executable by this user.
108
+ *
109
+ * @param file - Absolute path
110
+ * @returns True when executable
111
+ */
112
+ function defaultIsExecutable(file) {
113
+ try {
114
+ fs.accessSync(file, fs.constants.X_OK);
115
+ return fs.statSync(file).isFile();
116
+ }
117
+ catch {
118
+ return false;
119
+ }
120
+ }
121
+ /**
122
+ * Run a command without a shell and collect its output.
123
+ *
124
+ * Never rejects: a spawn failure (ENOENT) or timeout comes back as
125
+ * `{ code: null, error }`. Secrets must go through `options.stdin`, never
126
+ * through `args`, so they cannot appear in `ps` output.
127
+ *
128
+ * @param command - Executable
129
+ * @param args - Arguments
130
+ * @param options - env, timeout, stdin, streaming output callback
131
+ * @returns Exit code and output
132
+ */
133
+ export const runCommand = (command, args, options = {}) => new Promise((resolve) => {
134
+ let stdout = '';
135
+ let stderr = '';
136
+ let settled = false;
137
+ let timer = null;
138
+ const finish = (result) => {
139
+ if (settled)
140
+ return;
141
+ settled = true;
142
+ if (timer)
143
+ clearTimeout(timer);
144
+ resolve(result);
145
+ };
146
+ let child;
147
+ try {
148
+ child = spawn(command, [...args], {
149
+ env: options.env ?? process.env,
150
+ stdio: ['pipe', 'pipe', 'pipe'],
151
+ });
152
+ }
153
+ catch (error) {
154
+ resolve({ code: null, stdout: '', stderr: '', error: error instanceof Error ? error.message : String(error) });
155
+ return;
156
+ }
157
+ if (options.timeoutMs) {
158
+ timer = setTimeout(() => {
159
+ child.kill('SIGKILL');
160
+ finish({ code: null, stdout, stderr, error: `timed out after ${options.timeoutMs} ms` });
161
+ }, options.timeoutMs);
162
+ }
163
+ child.stdout?.on('data', (chunk) => {
164
+ const text = chunk.toString();
165
+ stdout += text;
166
+ options.onOutput?.(text);
167
+ });
168
+ child.stderr?.on('data', (chunk) => {
169
+ const text = chunk.toString();
170
+ stderr += text;
171
+ options.onOutput?.(text);
172
+ });
173
+ child.on('error', (error) => finish({ code: null, stdout, stderr, error: error.message }));
174
+ child.on('close', (code) => finish({ code, stdout, stderr }));
175
+ child.stdin?.on('error', () => undefined);
176
+ if (options.stdin !== undefined) {
177
+ child.stdin?.end(options.stdin);
178
+ }
179
+ else {
180
+ child.stdin?.end();
181
+ }
182
+ });
183
+ //# sourceMappingURL=harness-exec.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harness-exec.utils.js","sourceRoot":"","sources":["../../../../../../backend/src/services/harness/harness-exec.utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Harness install — `npm install -g <pkg>@latest` as an async job.
3
+ *
4
+ * When the global prefix is not writable (EACCES / EPERM), the install is
5
+ * retried once under the user-owned prefix `<crewlyHome>/npm-global`
6
+ * (`npm install -g --prefix …`); its `bin` dir is on the PATH of everything
7
+ * Crewly spawns (harness-exec.utils). No sudo, no shell profile edits.
8
+ *
9
+ * One install runs per harness at a time: starting a second one while the
10
+ * first is running returns the running job.
11
+ *
12
+ * @module services/harness/harness-install.service
13
+ */
14
+ import { type HarnessId, type HarnessLogger, type InstallJob, type RunCommand } from './harness.types.js';
15
+ /** Injectable dependencies. */
16
+ export interface HarnessInstallDeps {
17
+ run?: RunCommand;
18
+ env?: NodeJS.ProcessEnv;
19
+ /** Creates the user prefix dir */
20
+ mkdirp?: (dir: string) => void;
21
+ now?: () => number;
22
+ idFactory?: () => string;
23
+ logger?: HarnessLogger;
24
+ /** Called after a successful install (e.g. to refresh status caches) */
25
+ onInstalled?: (harnessId: HarnessId) => void;
26
+ }
27
+ /** Error with a machine-readable code, for the REST layer. */
28
+ export declare class HarnessInstallError extends Error {
29
+ readonly code: 'unknown_harness' | 'job_not_found';
30
+ /**
31
+ * @param code - `unknown_harness` or `job_not_found`
32
+ * @param message - Human-readable message
33
+ */
34
+ constructor(code: 'unknown_harness' | 'job_not_found', message: string);
35
+ }
36
+ /**
37
+ * Whether npm output says the global prefix is not writable.
38
+ *
39
+ * @param output - npm stdout + stderr
40
+ * @returns True for EACCES / EPERM / permission denied
41
+ */
42
+ export declare function isPermissionError(output: string): boolean;
43
+ /** Runs and tracks harness install jobs. */
44
+ export declare class HarnessInstallService {
45
+ private readonly run;
46
+ private readonly env;
47
+ private readonly mkdirp;
48
+ private readonly now;
49
+ private readonly idFactory;
50
+ private readonly logger;
51
+ private readonly onInstalled?;
52
+ private readonly jobs;
53
+ /**
54
+ * @param deps - Injectable dependencies (all optional)
55
+ */
56
+ constructor(deps?: HarnessInstallDeps);
57
+ /**
58
+ * Start installing (or updating) a harness.
59
+ *
60
+ * @param harnessId - Harness id
61
+ * @returns The new job, or the job already running for this harness
62
+ * @throws HarnessInstallError `unknown_harness`
63
+ */
64
+ startInstall(harnessId: string): InstallJob;
65
+ /**
66
+ * Look up a job.
67
+ *
68
+ * @param jobId - Job id
69
+ * @returns The job
70
+ * @throws HarnessInstallError `job_not_found`
71
+ */
72
+ getJob(jobId: string): InstallJob;
73
+ /**
74
+ * Wait for a job to finish (CLI).
75
+ *
76
+ * @param jobId - Job id
77
+ * @returns The finished job
78
+ * @throws HarnessInstallError `job_not_found`
79
+ */
80
+ waitForJob(jobId: string): Promise<InstallJob>;
81
+ /**
82
+ * Run npm, falling back to the user prefix on a permission error.
83
+ *
84
+ * @param record - Job record (mutated)
85
+ * @param npmPackage - Package to install
86
+ * @returns The finished job
87
+ */
88
+ private execute;
89
+ /**
90
+ * Append to a job log, keeping only the tail.
91
+ *
92
+ * @param record - Job record
93
+ * @param text - Text to append
94
+ */
95
+ private append;
96
+ /** Forget finished jobs older than the retention window. */
97
+ private pruneFinished;
98
+ /**
99
+ * Public view of a job.
100
+ *
101
+ * @param record - Job record
102
+ * @returns Contract shape
103
+ */
104
+ private toPublic;
105
+ }
106
+ //# sourceMappingURL=harness-install.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harness-install.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/harness/harness-install.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAOH,OAAO,EAAyB,KAAK,SAAS,EAAE,KAAK,aAAa,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEjI,+BAA+B;AAC/B,MAAM,WAAW,kBAAkB;IAClC,GAAG,CAAC,EAAE,UAAU,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,kCAAkC;IAClC,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,wEAAwE;IACxE,WAAW,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,IAAI,CAAC;CAC7C;AAED,8DAA8D;AAC9D,qBAAa,mBAAoB,SAAQ,KAAK;aAM5B,IAAI,EAAE,iBAAiB,GAAG,eAAe;IAL1D;;;OAGG;gBAEc,IAAI,EAAE,iBAAiB,GAAG,eAAe,EACzD,OAAO,EAAE,MAAM;CAKhB;AASD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAGzD;AAED,4CAA4C;AAC5C,qBAAa,qBAAqB;IACjC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAa;IACjC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAoB;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwB;IAC/C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAiC;IAC9D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgC;IAErD;;OAEG;gBACS,IAAI,GAAE,kBAAuB;IAUzC;;;;;;OAMG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU;IAqB3C;;;;;;OAMG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU;IAMjC;;;;;;OAMG;IACG,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAOpD;;;;;;OAMG;YACW,OAAO;IAuCrB;;;;;OAKG;IACH,OAAO,CAAC,MAAM;IAMd,4DAA4D;IAC5D,OAAO,CAAC,aAAa;IAOrB;;;;;OAKG;IACH,OAAO,CAAC,QAAQ;CAShB"}
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Harness install — `npm install -g <pkg>@latest` as an async job.
3
+ *
4
+ * When the global prefix is not writable (EACCES / EPERM), the install is
5
+ * retried once under the user-owned prefix `<crewlyHome>/npm-global`
6
+ * (`npm install -g --prefix …`); its `bin` dir is on the PATH of everything
7
+ * Crewly spawns (harness-exec.utils). No sudo, no shell profile edits.
8
+ *
9
+ * One install runs per harness at a time: starting a second one while the
10
+ * first is running returns the running job.
11
+ *
12
+ * @module services/harness/harness-install.service
13
+ */
14
+ import { randomUUID } from 'crypto';
15
+ import * as fs from 'fs';
16
+ import { HARNESS_CONSTANTS } from '../../constants.js';
17
+ import { buildNpmPath, getUserNpmPrefix, runCommand } from './harness-exec.utils.js';
18
+ import { getHarnessDefinition } from './harness-registry.js';
19
+ import { SILENT_HARNESS_LOGGER } from './harness.types.js';
20
+ /** Error with a machine-readable code, for the REST layer. */
21
+ export class HarnessInstallError extends Error {
22
+ code;
23
+ /**
24
+ * @param code - `unknown_harness` or `job_not_found`
25
+ * @param message - Human-readable message
26
+ */
27
+ constructor(code, message) {
28
+ super(message);
29
+ this.code = code;
30
+ this.name = 'HarnessInstallError';
31
+ }
32
+ }
33
+ /**
34
+ * Whether npm output says the global prefix is not writable.
35
+ *
36
+ * @param output - npm stdout + stderr
37
+ * @returns True for EACCES / EPERM / permission denied
38
+ */
39
+ export function isPermissionError(output) {
40
+ const lower = output.toLowerCase();
41
+ return HARNESS_CONSTANTS.PERMISSION_ERROR_PATTERNS.some((pattern) => lower.includes(pattern.toLowerCase()));
42
+ }
43
+ /** Runs and tracks harness install jobs. */
44
+ export class HarnessInstallService {
45
+ run;
46
+ env;
47
+ mkdirp;
48
+ now;
49
+ idFactory;
50
+ logger;
51
+ onInstalled;
52
+ jobs = new Map();
53
+ /**
54
+ * @param deps - Injectable dependencies (all optional)
55
+ */
56
+ constructor(deps = {}) {
57
+ this.run = deps.run ?? runCommand;
58
+ this.env = deps.env ?? process.env;
59
+ this.mkdirp = deps.mkdirp ?? ((dir) => fs.mkdirSync(dir, { recursive: true }));
60
+ this.now = deps.now ?? Date.now;
61
+ this.idFactory = deps.idFactory ?? randomUUID;
62
+ this.logger = deps.logger ?? SILENT_HARNESS_LOGGER;
63
+ this.onInstalled = deps.onInstalled;
64
+ }
65
+ /**
66
+ * Start installing (or updating) a harness.
67
+ *
68
+ * @param harnessId - Harness id
69
+ * @returns The new job, or the job already running for this harness
70
+ * @throws HarnessInstallError `unknown_harness`
71
+ */
72
+ startInstall(harnessId) {
73
+ const def = getHarnessDefinition(harnessId);
74
+ if (!def)
75
+ throw new HarnessInstallError('unknown_harness', `Unknown harness: ${harnessId}`);
76
+ this.pruneFinished();
77
+ const running = [...this.jobs.values()].find((job) => job.harnessId === def.id && job.state === 'running');
78
+ if (running)
79
+ return this.toPublic(running);
80
+ const record = {
81
+ jobId: this.idFactory(),
82
+ harnessId: def.id,
83
+ state: 'running',
84
+ log: '',
85
+ usedUserPrefix: false,
86
+ finishedAt: null,
87
+ done: null,
88
+ };
89
+ this.jobs.set(record.jobId, record);
90
+ record.done = this.execute(record, def.npmPackage);
91
+ return this.toPublic(record);
92
+ }
93
+ /**
94
+ * Look up a job.
95
+ *
96
+ * @param jobId - Job id
97
+ * @returns The job
98
+ * @throws HarnessInstallError `job_not_found`
99
+ */
100
+ getJob(jobId) {
101
+ const record = this.jobs.get(jobId);
102
+ if (!record)
103
+ throw new HarnessInstallError('job_not_found', `Install job not found: ${jobId}`);
104
+ return this.toPublic(record);
105
+ }
106
+ /**
107
+ * Wait for a job to finish (CLI).
108
+ *
109
+ * @param jobId - Job id
110
+ * @returns The finished job
111
+ * @throws HarnessInstallError `job_not_found`
112
+ */
113
+ async waitForJob(jobId) {
114
+ const record = this.jobs.get(jobId);
115
+ if (!record)
116
+ throw new HarnessInstallError('job_not_found', `Install job not found: ${jobId}`);
117
+ if (record.done)
118
+ await record.done;
119
+ return this.toPublic(record);
120
+ }
121
+ /**
122
+ * Run npm, falling back to the user prefix on a permission error.
123
+ *
124
+ * @param record - Job record (mutated)
125
+ * @param npmPackage - Package to install
126
+ * @returns The finished job
127
+ */
128
+ async execute(record, npmPackage) {
129
+ const spec = `${npmPackage}@latest`;
130
+ const env = { ...this.env, PATH: buildNpmPath(this.env.PATH) };
131
+ try {
132
+ this.append(record, `$ npm install -g ${spec}\n`);
133
+ const first = await this.run('npm', ['install', '-g', spec], {
134
+ env,
135
+ timeoutMs: HARNESS_CONSTANTS.INSTALL_TIMEOUT_MS,
136
+ onOutput: (chunk) => this.append(record, chunk),
137
+ });
138
+ let ok = first.code === 0;
139
+ if (!ok && isPermissionError(`${first.stdout}\n${first.stderr}\n${first.error ?? ''}`)) {
140
+ const prefix = getUserNpmPrefix();
141
+ this.mkdirp(prefix);
142
+ record.usedUserPrefix = true;
143
+ this.append(record, `\nNo permission to write the global npm prefix; installing under ${prefix} instead.\n`);
144
+ this.append(record, `$ npm install -g --prefix ${prefix} ${spec}\n`);
145
+ const second = await this.run('npm', ['install', '-g', '--prefix', prefix, spec], {
146
+ env,
147
+ timeoutMs: HARNESS_CONSTANTS.INSTALL_TIMEOUT_MS,
148
+ onOutput: (chunk) => this.append(record, chunk),
149
+ });
150
+ ok = second.code === 0;
151
+ if (!ok && second.error)
152
+ this.append(record, `\n${second.error}\n`);
153
+ }
154
+ else if (!ok && first.error) {
155
+ this.append(record, `\n${first.error}\n`);
156
+ }
157
+ record.state = ok ? 'succeeded' : 'failed';
158
+ this.append(record, ok ? '\nInstalled.\n' : '\nInstall failed.\n');
159
+ if (ok)
160
+ this.onInstalled?.(record.harnessId);
161
+ }
162
+ catch (error) {
163
+ record.state = 'failed';
164
+ this.append(record, `\n${error instanceof Error ? error.message : String(error)}\n`);
165
+ }
166
+ record.finishedAt = this.now();
167
+ this.logger.info('Harness install finished', { harnessId: record.harnessId, state: record.state, usedUserPrefix: record.usedUserPrefix });
168
+ return this.toPublic(record);
169
+ }
170
+ /**
171
+ * Append to a job log, keeping only the tail.
172
+ *
173
+ * @param record - Job record
174
+ * @param text - Text to append
175
+ */
176
+ append(record, text) {
177
+ const next = record.log + text;
178
+ const max = HARNESS_CONSTANTS.INSTALL_LOG_MAX_CHARS;
179
+ record.log = next.length > max ? next.slice(next.length - max) : next;
180
+ }
181
+ /** Forget finished jobs older than the retention window. */
182
+ pruneFinished() {
183
+ const cutoff = this.now() - HARNESS_CONSTANTS.INSTALL_JOB_RETENTION_MS;
184
+ for (const [id, job] of this.jobs) {
185
+ if (job.finishedAt !== null && job.finishedAt < cutoff)
186
+ this.jobs.delete(id);
187
+ }
188
+ }
189
+ /**
190
+ * Public view of a job.
191
+ *
192
+ * @param record - Job record
193
+ * @returns Contract shape
194
+ */
195
+ toPublic(record) {
196
+ return {
197
+ jobId: record.jobId,
198
+ harnessId: record.harnessId,
199
+ state: record.state,
200
+ log: record.log,
201
+ usedUserPrefix: record.usedUserPrefix,
202
+ };
203
+ }
204
+ }
205
+ //# sourceMappingURL=harness-install.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harness-install.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/harness/harness-install.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrF,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAwE,MAAM,oBAAoB,CAAC;AAejI,8DAA8D;AAC9D,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAM5B;IALjB;;;OAGG;IACH,YACiB,IAAyC,EACzD,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QAHC,SAAI,GAAJ,IAAI,CAAqC;QAIzD,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACnC,CAAC;CACD;AASD;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC/C,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IACnC,OAAO,iBAAiB,CAAC,yBAAyB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;AAC7G,CAAC;AAED,4CAA4C;AAC5C,MAAM,OAAO,qBAAqB;IAChB,GAAG,CAAa;IAChB,GAAG,CAAoB;IACvB,MAAM,CAAwB;IAC9B,GAAG,CAAe;IAClB,SAAS,CAAe;IACxB,MAAM,CAAgB;IACtB,WAAW,CAAkC;IAC7C,IAAI,GAAG,IAAI,GAAG,EAAqB,CAAC;IAErD;;OAEG;IACH,YAAY,OAA2B,EAAE;QACxC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,UAAU,CAAC;QAClC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;QACnC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC/E,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;QAChC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,UAAU,CAAC;QAC9C,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,qBAAqB,CAAC;QACnD,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IACrC,CAAC;IAED;;;;;;OAMG;IACH,YAAY,CAAC,SAAiB;QAC7B,MAAM,GAAG,GAAG,oBAAoB,CAAC,SAAS,CAAC,CAAC;QAC5C,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,mBAAmB,CAAC,iBAAiB,EAAE,oBAAoB,SAAS,EAAE,CAAC,CAAC;QAC5F,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,KAAK,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC;QAC3G,IAAI,OAAO;YAAE,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAE3C,MAAM,MAAM,GAAc;YACzB,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE;YACvB,SAAS,EAAE,GAAG,CAAC,EAAE;YACjB,KAAK,EAAE,SAAS;YAChB,GAAG,EAAE,EAAE;YACP,cAAc,EAAE,KAAK;YACrB,UAAU,EAAE,IAAI;YAChB,IAAI,EAAE,IAAI;SACV,CAAC;QACF,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACpC,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;QACnD,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,KAAa;QACnB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,mBAAmB,CAAC,eAAe,EAAE,0BAA0B,KAAK,EAAE,CAAC,CAAC;QAC/F,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,UAAU,CAAC,KAAa;QAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,mBAAmB,CAAC,eAAe,EAAE,0BAA0B,KAAK,EAAE,CAAC,CAAC;QAC/F,IAAI,MAAM,CAAC,IAAI;YAAE,MAAM,MAAM,CAAC,IAAI,CAAC;QACnC,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IAED;;;;;;OAMG;IACK,KAAK,CAAC,OAAO,CAAC,MAAiB,EAAE,UAAkB;QAC1D,MAAM,IAAI,GAAG,GAAG,UAAU,SAAS,CAAC;QACpC,MAAM,GAAG,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/D,IAAI,CAAC;YACJ,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,oBAAoB,IAAI,IAAI,CAAC,CAAC;YAClD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE;gBAC5D,GAAG;gBACH,SAAS,EAAE,iBAAiB,CAAC,kBAAkB;gBAC/C,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC;aAC/C,CAAC,CAAC;YACH,IAAI,EAAE,GAAG,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC;YAC1B,IAAI,CAAC,EAAE,IAAI,iBAAiB,CAAC,GAAG,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC;gBACxF,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;gBAClC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBACpB,MAAM,CAAC,cAAc,GAAG,IAAI,CAAC;gBAC7B,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,oEAAoE,MAAM,aAAa,CAAC,CAAC;gBAC7G,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,6BAA6B,MAAM,IAAI,IAAI,IAAI,CAAC,CAAC;gBACrE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;oBACjF,GAAG;oBACH,SAAS,EAAE,iBAAiB,CAAC,kBAAkB;oBAC/C,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC;iBAC/C,CAAC,CAAC;gBACH,EAAE,GAAG,MAAM,CAAC,IAAI,KAAK,CAAC,CAAC;gBACvB,IAAI,CAAC,EAAE,IAAI,MAAM,CAAC,KAAK;oBAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC;YACrE,CAAC;iBAAM,IAAI,CAAC,EAAE,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;gBAC/B,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC;YAC3C,CAAC;YACD,MAAM,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC;YAC3C,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC;YACnE,IAAI,EAAE;gBAAE,IAAI,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC9C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,CAAC,KAAK,GAAG,QAAQ,CAAC;YACxB,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACtF,CAAC;QACD,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC/B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,0BAA0B,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,cAAc,EAAE,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC;QAC1I,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IAED;;;;;OAKG;IACK,MAAM,CAAC,MAAiB,EAAE,IAAY;QAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC;QAC/B,MAAM,GAAG,GAAG,iBAAiB,CAAC,qBAAqB,CAAC;QACpD,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACvE,CAAC;IAED,4DAA4D;IACpD,aAAa;QACpB,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,iBAAiB,CAAC,wBAAwB,CAAC;QACvE,KAAK,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACnC,IAAI,GAAG,CAAC,UAAU,KAAK,IAAI,IAAI,GAAG,CAAC,UAAU,GAAG,MAAM;gBAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC9E,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACK,QAAQ,CAAC,MAAiB;QACjC,OAAO;YACN,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,GAAG,EAAE,MAAM,CAAC,GAAG;YACf,cAAc,EAAE,MAAM,CAAC,cAAc;SACrC,CAAC;IACH,CAAC;CACD"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Harness registry — static definitions of the agent CLIs Crewly can set up.
3
+ *
4
+ * One entry per harness: display name, binary, npm package, how to print the
5
+ * version, and the login methods Crewly offers. A `broker` method names the
6
+ * harness's own login command, which the login broker runs in a PTY; an
7
+ * `api_key` method is a pasted key. Gemini CLI is detect-only (no methods).
8
+ *
9
+ * @module services/harness/harness-registry
10
+ */
11
+ import type { HarnessId, HarnessLoginMethod, LoginMethodId, LoginMethodKind } from './harness.types.js';
12
+ /** The command a broker login method runs. */
13
+ export interface BrokerCommand {
14
+ /** Binary (resolved on the harness PATH) */
15
+ command: string;
16
+ args: readonly string[];
17
+ }
18
+ /** A login method definition (internal: includes the broker command). */
19
+ export interface LoginMethodDefinition {
20
+ id: LoginMethodId;
21
+ label: string;
22
+ kind: LoginMethodKind;
23
+ /** Command run by the login broker (kind `broker` only) */
24
+ broker?: BrokerCommand;
25
+ }
26
+ /** Static facts about one harness. */
27
+ export interface HarnessDefinition {
28
+ id: HarnessId;
29
+ displayName: string;
30
+ /** Binary name on PATH */
31
+ command: string;
32
+ npmPackage: string;
33
+ /** Arguments that print the version */
34
+ versionArgs: readonly string[];
35
+ loginMethods: readonly LoginMethodDefinition[];
36
+ }
37
+ /** Every harness Crewly knows, in display order (default first). */
38
+ export declare const HARNESS_DEFINITIONS: readonly HarnessDefinition[];
39
+ /**
40
+ * All harness definitions.
41
+ *
42
+ * @returns The registry, in display order
43
+ */
44
+ export declare function listHarnessDefinitions(): readonly HarnessDefinition[];
45
+ /**
46
+ * Look up a harness definition.
47
+ *
48
+ * @param id - Harness id
49
+ * @returns The definition, or undefined for an unknown id
50
+ */
51
+ export declare function getHarnessDefinition(id: string): HarnessDefinition | undefined;
52
+ /**
53
+ * Look up one login method of a harness.
54
+ *
55
+ * @param harnessId - Harness id
56
+ * @param methodId - Login method id
57
+ * @returns The method, or undefined when the harness does not offer it
58
+ */
59
+ export declare function getLoginMethod(harnessId: string, methodId: string): LoginMethodDefinition | undefined;
60
+ /**
61
+ * The broker login method of a harness (the first one), if any.
62
+ *
63
+ * @param harnessId - Harness id
64
+ * @returns The method, or undefined when the harness has no broker login
65
+ */
66
+ export declare function getBrokerLoginMethod(harnessId: string): LoginMethodDefinition | undefined;
67
+ /**
68
+ * Public view of a harness's login methods (no commands).
69
+ *
70
+ * @param def - Harness definition
71
+ * @returns `{ id, label, kind }` per method
72
+ */
73
+ export declare function toPublicLoginMethods(def: HarnessDefinition): HarnessLoginMethod[];
74
+ /**
75
+ * Resolve a harness id from a full id or a short CLI alias.
76
+ *
77
+ * @param value - `claude-code`, `claude`, `codex-cli`, `codex`, `gemini-cli` or `gemini` (case-insensitive)
78
+ * @returns The harness id, or null when unknown
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * resolveHarnessAlias('codex'); // 'codex-cli'
83
+ * ```
84
+ */
85
+ export declare function resolveHarnessAlias(value: string | undefined | null): HarnessId | null;
86
+ //# sourceMappingURL=harness-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harness-registry.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/harness/harness-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAGxG,8CAA8C;AAC9C,MAAM,WAAW,aAAa;IAC7B,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;CACxB;AAED,yEAAyE;AACzE,MAAM,WAAW,qBAAqB;IACrC,EAAE,EAAE,aAAa,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,eAAe,CAAC;IACtB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,aAAa,CAAC;CACvB;AAED,sCAAsC;AACtC,MAAM,WAAW,iBAAiB;IACjC,EAAE,EAAE,SAAS,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,YAAY,EAAE,SAAS,qBAAqB,EAAE,CAAC;CAC/C;AAED,oEAAoE;AACpE,eAAO,MAAM,mBAAmB,EAAE,SAAS,iBAAiB,EAyC3D,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,SAAS,iBAAiB,EAAE,CAErE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAE9E;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS,CAErG;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS,CAEzF;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,iBAAiB,GAAG,kBAAkB,EAAE,CAEjF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,CAMtF"}