crewly 1.20.123 → 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 (165) hide show
  1. package/dist/backend/backend/src/constants.d.ts +118 -0
  2. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  3. package/dist/backend/backend/src/constants.js +118 -0
  4. package/dist/backend/backend/src/constants.js.map +1 -1
  5. package/dist/backend/backend/src/controllers/harness/harness.controller.d.ts +54 -0
  6. package/dist/backend/backend/src/controllers/harness/harness.controller.d.ts.map +1 -0
  7. package/dist/backend/backend/src/controllers/harness/harness.controller.js +204 -0
  8. package/dist/backend/backend/src/controllers/harness/harness.controller.js.map +1 -0
  9. package/dist/backend/backend/src/controllers/harness/harness.routes.d.ts +27 -0
  10. package/dist/backend/backend/src/controllers/harness/harness.routes.d.ts.map +1 -0
  11. package/dist/backend/backend/src/controllers/harness/harness.routes.js +43 -0
  12. package/dist/backend/backend/src/controllers/harness/harness.routes.js.map +1 -0
  13. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  14. package/dist/backend/backend/src/routes/api.routes.js +4 -0
  15. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  16. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts +5 -0
  17. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  18. package/dist/backend/backend/src/services/agent/agent-registration.service.js +7 -0
  19. package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
  20. package/dist/backend/backend/src/services/cloud/cloud-client.service.d.ts +2 -1
  21. package/dist/backend/backend/src/services/cloud/cloud-client.service.d.ts.map +1 -1
  22. package/dist/backend/backend/src/services/cloud/cloud-client.service.js +4 -3
  23. package/dist/backend/backend/src/services/cloud/cloud-client.service.js.map +1 -1
  24. package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.d.ts.map +1 -1
  25. package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.js +14 -0
  26. package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.js.map +1 -1
  27. package/dist/backend/backend/src/services/harness/claude-config.utils.d.ts +67 -0
  28. package/dist/backend/backend/src/services/harness/claude-config.utils.d.ts.map +1 -0
  29. package/dist/backend/backend/src/services/harness/claude-config.utils.js +118 -0
  30. package/dist/backend/backend/src/services/harness/claude-config.utils.js.map +1 -0
  31. package/dist/backend/backend/src/services/harness/harness-api-key.service.d.ts +99 -0
  32. package/dist/backend/backend/src/services/harness/harness-api-key.service.d.ts.map +1 -0
  33. package/dist/backend/backend/src/services/harness/harness-api-key.service.js +157 -0
  34. package/dist/backend/backend/src/services/harness/harness-api-key.service.js.map +1 -0
  35. package/dist/backend/backend/src/services/harness/harness-credentials.store.d.ts +135 -0
  36. package/dist/backend/backend/src/services/harness/harness-credentials.store.d.ts.map +1 -0
  37. package/dist/backend/backend/src/services/harness/harness-credentials.store.js +208 -0
  38. package/dist/backend/backend/src/services/harness/harness-credentials.store.js.map +1 -0
  39. package/dist/backend/backend/src/services/harness/harness-exec.utils.d.ts +85 -0
  40. package/dist/backend/backend/src/services/harness/harness-exec.utils.d.ts.map +1 -0
  41. package/dist/backend/backend/src/services/harness/harness-exec.utils.js +183 -0
  42. package/dist/backend/backend/src/services/harness/harness-exec.utils.js.map +1 -0
  43. package/dist/backend/backend/src/services/harness/harness-install.service.d.ts +106 -0
  44. package/dist/backend/backend/src/services/harness/harness-install.service.d.ts.map +1 -0
  45. package/dist/backend/backend/src/services/harness/harness-install.service.js +205 -0
  46. package/dist/backend/backend/src/services/harness/harness-install.service.js.map +1 -0
  47. package/dist/backend/backend/src/services/harness/harness-registry.d.ts +86 -0
  48. package/dist/backend/backend/src/services/harness/harness-registry.d.ts.map +1 -0
  49. package/dist/backend/backend/src/services/harness/harness-registry.js +121 -0
  50. package/dist/backend/backend/src/services/harness/harness-registry.js.map +1 -0
  51. package/dist/backend/backend/src/services/harness/harness-status.service.d.ts +173 -0
  52. package/dist/backend/backend/src/services/harness/harness-status.service.d.ts.map +1 -0
  53. package/dist/backend/backend/src/services/harness/harness-status.service.js +324 -0
  54. package/dist/backend/backend/src/services/harness/harness-status.service.js.map +1 -0
  55. package/dist/backend/backend/src/services/harness/harness.service.d.ts +146 -0
  56. package/dist/backend/backend/src/services/harness/harness.service.d.ts.map +1 -0
  57. package/dist/backend/backend/src/services/harness/harness.service.js +193 -0
  58. package/dist/backend/backend/src/services/harness/harness.service.js.map +1 -0
  59. package/dist/backend/backend/src/services/harness/harness.types.d.ts +138 -0
  60. package/dist/backend/backend/src/services/harness/harness.types.d.ts.map +1 -0
  61. package/dist/backend/backend/src/services/harness/harness.types.js +51 -0
  62. package/dist/backend/backend/src/services/harness/harness.types.js.map +1 -0
  63. package/dist/backend/backend/src/services/harness/login-broker.service.d.ts +238 -0
  64. package/dist/backend/backend/src/services/harness/login-broker.service.d.ts.map +1 -0
  65. package/dist/backend/backend/src/services/harness/login-broker.service.js +495 -0
  66. package/dist/backend/backend/src/services/harness/login-broker.service.js.map +1 -0
  67. package/dist/backend/backend/src/services/harness/login-rules.d.ts +162 -0
  68. package/dist/backend/backend/src/services/harness/login-rules.d.ts.map +1 -0
  69. package/dist/backend/backend/src/services/harness/login-rules.js +344 -0
  70. package/dist/backend/backend/src/services/harness/login-rules.js.map +1 -0
  71. package/dist/backend/backend/src/services/harness/orc-harness.store.d.ts +59 -0
  72. package/dist/backend/backend/src/services/harness/orc-harness.store.d.ts.map +1 -0
  73. package/dist/backend/backend/src/services/harness/orc-harness.store.js +108 -0
  74. package/dist/backend/backend/src/services/harness/orc-harness.store.js.map +1 -0
  75. package/dist/backend/build-info.json +2 -2
  76. package/dist/cli/backend/src/constants.d.ts +118 -0
  77. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  78. package/dist/cli/backend/src/constants.js +118 -0
  79. package/dist/cli/backend/src/constants.js.map +1 -1
  80. package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts +5 -0
  81. package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  82. package/dist/cli/backend/src/services/agent/agent-registration.service.js +7 -0
  83. package/dist/cli/backend/src/services/agent/agent-registration.service.js.map +1 -1
  84. package/dist/cli/backend/src/services/cloud/cloud-client.service.d.ts +2 -1
  85. package/dist/cli/backend/src/services/cloud/cloud-client.service.d.ts.map +1 -1
  86. package/dist/cli/backend/src/services/cloud/cloud-client.service.js +4 -3
  87. package/dist/cli/backend/src/services/cloud/cloud-client.service.js.map +1 -1
  88. package/dist/cli/backend/src/services/harness/claude-config.utils.d.ts +67 -0
  89. package/dist/cli/backend/src/services/harness/claude-config.utils.d.ts.map +1 -0
  90. package/dist/cli/backend/src/services/harness/claude-config.utils.js +118 -0
  91. package/dist/cli/backend/src/services/harness/claude-config.utils.js.map +1 -0
  92. package/dist/cli/backend/src/services/harness/harness-api-key.service.d.ts +99 -0
  93. package/dist/cli/backend/src/services/harness/harness-api-key.service.d.ts.map +1 -0
  94. package/dist/cli/backend/src/services/harness/harness-api-key.service.js +157 -0
  95. package/dist/cli/backend/src/services/harness/harness-api-key.service.js.map +1 -0
  96. package/dist/cli/backend/src/services/harness/harness-credentials.store.d.ts +135 -0
  97. package/dist/cli/backend/src/services/harness/harness-credentials.store.d.ts.map +1 -0
  98. package/dist/cli/backend/src/services/harness/harness-credentials.store.js +208 -0
  99. package/dist/cli/backend/src/services/harness/harness-credentials.store.js.map +1 -0
  100. package/dist/cli/backend/src/services/harness/harness-exec.utils.d.ts +85 -0
  101. package/dist/cli/backend/src/services/harness/harness-exec.utils.d.ts.map +1 -0
  102. package/dist/cli/backend/src/services/harness/harness-exec.utils.js +183 -0
  103. package/dist/cli/backend/src/services/harness/harness-exec.utils.js.map +1 -0
  104. package/dist/cli/backend/src/services/harness/harness-install.service.d.ts +106 -0
  105. package/dist/cli/backend/src/services/harness/harness-install.service.d.ts.map +1 -0
  106. package/dist/cli/backend/src/services/harness/harness-install.service.js +205 -0
  107. package/dist/cli/backend/src/services/harness/harness-install.service.js.map +1 -0
  108. package/dist/cli/backend/src/services/harness/harness-registry.d.ts +86 -0
  109. package/dist/cli/backend/src/services/harness/harness-registry.d.ts.map +1 -0
  110. package/dist/cli/backend/src/services/harness/harness-registry.js +121 -0
  111. package/dist/cli/backend/src/services/harness/harness-registry.js.map +1 -0
  112. package/dist/cli/backend/src/services/harness/harness-status.service.d.ts +173 -0
  113. package/dist/cli/backend/src/services/harness/harness-status.service.d.ts.map +1 -0
  114. package/dist/cli/backend/src/services/harness/harness-status.service.js +324 -0
  115. package/dist/cli/backend/src/services/harness/harness-status.service.js.map +1 -0
  116. package/dist/cli/backend/src/services/harness/harness.service.d.ts +146 -0
  117. package/dist/cli/backend/src/services/harness/harness.service.d.ts.map +1 -0
  118. package/dist/cli/backend/src/services/harness/harness.service.js +193 -0
  119. package/dist/cli/backend/src/services/harness/harness.service.js.map +1 -0
  120. package/dist/cli/backend/src/services/harness/harness.types.d.ts +138 -0
  121. package/dist/cli/backend/src/services/harness/harness.types.d.ts.map +1 -0
  122. package/dist/cli/backend/src/services/harness/harness.types.js +51 -0
  123. package/dist/cli/backend/src/services/harness/harness.types.js.map +1 -0
  124. package/dist/cli/backend/src/services/harness/login-broker.service.d.ts +238 -0
  125. package/dist/cli/backend/src/services/harness/login-broker.service.d.ts.map +1 -0
  126. package/dist/cli/backend/src/services/harness/login-broker.service.js +495 -0
  127. package/dist/cli/backend/src/services/harness/login-broker.service.js.map +1 -0
  128. package/dist/cli/backend/src/services/harness/login-rules.d.ts +162 -0
  129. package/dist/cli/backend/src/services/harness/login-rules.d.ts.map +1 -0
  130. package/dist/cli/backend/src/services/harness/login-rules.js +344 -0
  131. package/dist/cli/backend/src/services/harness/login-rules.js.map +1 -0
  132. package/dist/cli/backend/src/services/harness/orc-harness.store.d.ts +59 -0
  133. package/dist/cli/backend/src/services/harness/orc-harness.store.d.ts.map +1 -0
  134. package/dist/cli/backend/src/services/harness/orc-harness.store.js +108 -0
  135. package/dist/cli/backend/src/services/harness/orc-harness.store.js.map +1 -0
  136. package/dist/cli/cli/src/commands/harness-setup.d.ts +159 -0
  137. package/dist/cli/cli/src/commands/harness-setup.d.ts.map +1 -0
  138. package/dist/cli/cli/src/commands/harness-setup.js +377 -0
  139. package/dist/cli/cli/src/commands/harness-setup.js.map +1 -0
  140. package/dist/cli/cli/src/commands/harness.d.ts +56 -0
  141. package/dist/cli/cli/src/commands/harness.d.ts.map +1 -0
  142. package/dist/cli/cli/src/commands/harness.js +97 -0
  143. package/dist/cli/cli/src/commands/harness.js.map +1 -0
  144. package/dist/cli/cli/src/commands/onboard.d.ts +108 -50
  145. package/dist/cli/cli/src/commands/onboard.d.ts.map +1 -1
  146. package/dist/cli/cli/src/commands/onboard.js +200 -191
  147. package/dist/cli/cli/src/commands/onboard.js.map +1 -1
  148. package/dist/cli/cli/src/constants.d.ts +18 -0
  149. package/dist/cli/cli/src/constants.d.ts.map +1 -1
  150. package/dist/cli/cli/src/constants.js +18 -0
  151. package/dist/cli/cli/src/constants.js.map +1 -1
  152. package/dist/cli/cli/src/index.js +22 -3
  153. package/dist/cli/cli/src/index.js.map +1 -1
  154. package/dist/cli/cli/src/utils/harness-engine.d.ts +99 -0
  155. package/dist/cli/cli/src/utils/harness-engine.d.ts.map +1 -0
  156. package/dist/cli/cli/src/utils/harness-engine.js +143 -0
  157. package/dist/cli/cli/src/utils/harness-engine.js.map +1 -0
  158. package/dist/cli/cli/src/utils/prompt-io.d.ts +25 -0
  159. package/dist/cli/cli/src/utils/prompt-io.d.ts.map +1 -0
  160. package/dist/cli/cli/src/utils/prompt-io.js +47 -0
  161. package/dist/cli/cli/src/utils/prompt-io.js.map +1 -0
  162. package/frontend/dist/assets/{index-8327e63e.css → index-0a2f783c.css} +1 -1
  163. package/frontend/dist/assets/{index-daf43f1a.js → index-aaf65055.js} +309 -309
  164. package/frontend/dist/index.html +2 -2
  165. package/package.json +1 -1
@@ -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":"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"}
@@ -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"}
@@ -0,0 +1,121 @@
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 { HARNESS_CONSTANTS } from '../../constants.js';
12
+ import { isHarnessId } from './harness.types.js';
13
+ /** Every harness Crewly knows, in display order (default first). */
14
+ export const HARNESS_DEFINITIONS = [
15
+ {
16
+ id: HARNESS_CONSTANTS.IDS.CLAUDE_CODE,
17
+ displayName: 'Claude Code',
18
+ command: 'claude',
19
+ npmPackage: '@anthropic-ai/claude-code',
20
+ versionArgs: ['--version'],
21
+ loginMethods: [
22
+ {
23
+ id: 'subscription',
24
+ label: 'Claude subscription (Pro / Max)',
25
+ kind: 'broker',
26
+ broker: { command: 'claude', args: ['setup-token'] },
27
+ },
28
+ { id: 'api_key', label: 'Anthropic API key', kind: 'api_key' },
29
+ ],
30
+ },
31
+ {
32
+ id: HARNESS_CONSTANTS.IDS.CODEX_CLI,
33
+ displayName: 'Codex',
34
+ command: 'codex',
35
+ npmPackage: '@openai/codex',
36
+ versionArgs: ['--version'],
37
+ loginMethods: [
38
+ {
39
+ id: 'device',
40
+ label: 'ChatGPT account (device code)',
41
+ kind: 'broker',
42
+ broker: { command: 'codex', args: ['login', '--device-auth'] },
43
+ },
44
+ { id: 'api_key', label: 'OpenAI API key', kind: 'api_key' },
45
+ ],
46
+ },
47
+ {
48
+ id: HARNESS_CONSTANTS.IDS.GEMINI_CLI,
49
+ displayName: 'Gemini CLI',
50
+ command: 'gemini',
51
+ npmPackage: '@google/gemini-cli',
52
+ versionArgs: ['--version'],
53
+ loginMethods: [],
54
+ },
55
+ ];
56
+ /**
57
+ * All harness definitions.
58
+ *
59
+ * @returns The registry, in display order
60
+ */
61
+ export function listHarnessDefinitions() {
62
+ return HARNESS_DEFINITIONS;
63
+ }
64
+ /**
65
+ * Look up a harness definition.
66
+ *
67
+ * @param id - Harness id
68
+ * @returns The definition, or undefined for an unknown id
69
+ */
70
+ export function getHarnessDefinition(id) {
71
+ return HARNESS_DEFINITIONS.find((def) => def.id === id);
72
+ }
73
+ /**
74
+ * Look up one login method of a harness.
75
+ *
76
+ * @param harnessId - Harness id
77
+ * @param methodId - Login method id
78
+ * @returns The method, or undefined when the harness does not offer it
79
+ */
80
+ export function getLoginMethod(harnessId, methodId) {
81
+ return getHarnessDefinition(harnessId)?.loginMethods.find((method) => method.id === methodId);
82
+ }
83
+ /**
84
+ * The broker login method of a harness (the first one), if any.
85
+ *
86
+ * @param harnessId - Harness id
87
+ * @returns The method, or undefined when the harness has no broker login
88
+ */
89
+ export function getBrokerLoginMethod(harnessId) {
90
+ return getHarnessDefinition(harnessId)?.loginMethods.find((method) => method.kind === 'broker');
91
+ }
92
+ /**
93
+ * Public view of a harness's login methods (no commands).
94
+ *
95
+ * @param def - Harness definition
96
+ * @returns `{ id, label, kind }` per method
97
+ */
98
+ export function toPublicLoginMethods(def) {
99
+ return def.loginMethods.map(({ id, label, kind }) => ({ id, label, kind }));
100
+ }
101
+ /**
102
+ * Resolve a harness id from a full id or a short CLI alias.
103
+ *
104
+ * @param value - `claude-code`, `claude`, `codex-cli`, `codex`, `gemini-cli` or `gemini` (case-insensitive)
105
+ * @returns The harness id, or null when unknown
106
+ *
107
+ * @example
108
+ * ```ts
109
+ * resolveHarnessAlias('codex'); // 'codex-cli'
110
+ * ```
111
+ */
112
+ export function resolveHarnessAlias(value) {
113
+ if (!value)
114
+ return null;
115
+ const key = value.trim().toLowerCase();
116
+ if (isHarnessId(key))
117
+ return key;
118
+ const aliases = HARNESS_CONSTANTS.CLI_ALIASES;
119
+ return aliases[key] ?? null;
120
+ }
121
+ //# sourceMappingURL=harness-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harness-registry.js","sourceRoot":"","sources":["../../../../../../backend/src/services/harness/harness-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AA8BjD,oEAAoE;AACpE,MAAM,CAAC,MAAM,mBAAmB,GAAiC;IAChE;QACC,EAAE,EAAE,iBAAiB,CAAC,GAAG,CAAC,WAAW;QACrC,WAAW,EAAE,aAAa;QAC1B,OAAO,EAAE,QAAQ;QACjB,UAAU,EAAE,2BAA2B;QACvC,WAAW,EAAE,CAAC,WAAW,CAAC;QAC1B,YAAY,EAAE;YACb;gBACC,EAAE,EAAE,cAAc;gBAClB,KAAK,EAAE,iCAAiC;gBACxC,IAAI,EAAE,QAAQ;gBACd,MAAM,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,aAAa,CAAC,EAAE;aACpD;YACD,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,mBAAmB,EAAE,IAAI,EAAE,SAAS,EAAE;SAC9D;KACD;IACD;QACC,EAAE,EAAE,iBAAiB,CAAC,GAAG,CAAC,SAAS;QACnC,WAAW,EAAE,OAAO;QACpB,OAAO,EAAE,OAAO;QAChB,UAAU,EAAE,eAAe;QAC3B,WAAW,EAAE,CAAC,WAAW,CAAC;QAC1B,YAAY,EAAE;YACb;gBACC,EAAE,EAAE,QAAQ;gBACZ,KAAK,EAAE,+BAA+B;gBACtC,IAAI,EAAE,QAAQ;gBACd,MAAM,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,eAAe,CAAC,EAAE;aAC9D;YACD,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,SAAS,EAAE;SAC3D;KACD;IACD;QACC,EAAE,EAAE,iBAAiB,CAAC,GAAG,CAAC,UAAU;QACpC,WAAW,EAAE,YAAY;QACzB,OAAO,EAAE,QAAQ;QACjB,UAAU,EAAE,oBAAoB;QAChC,WAAW,EAAE,CAAC,WAAW,CAAC;QAC1B,YAAY,EAAE,EAAE;KAChB;CACD,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,sBAAsB;IACrC,OAAO,mBAAmB,CAAC;AAC5B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,EAAU;IAC9C,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;AACzD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,SAAiB,EAAE,QAAgB;IACjE,OAAO,oBAAoB,CAAC,SAAS,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC;AAC/F,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,SAAiB;IACrD,OAAO,oBAAoB,CAAC,SAAS,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;AACjG,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAsB;IAC1D,OAAO,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAC7E,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAgC;IACnE,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACvC,IAAI,WAAW,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC;IACjC,MAAM,OAAO,GAA8B,iBAAiB,CAAC,WAAW,CAAC;IACzE,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;AAC7B,CAAC"}