crewly 1.5.22 → 1.6.1

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 (180) hide show
  1. package/config/roles/orchestrator/fragments/role-boundary.md +4 -1
  2. package/config/roles/orchestrator/prompt.md +219 -25
  3. package/config/roles/orchestrator/soul.md +47 -10
  4. package/config/skills/_common/lib.sh +28 -0
  5. package/config/skills/agent/core/cancel-followup/SKILL.md +38 -0
  6. package/config/skills/agent/core/cancel-followup/execute.sh +92 -0
  7. package/config/skills/agent/core/cancel-followup/execute.test.sh +42 -0
  8. package/config/skills/agent/core/list-my-followups/SKILL.md +36 -0
  9. package/config/skills/agent/core/list-my-followups/execute.sh +74 -0
  10. package/config/skills/agent/core/list-my-followups/execute.test.sh +41 -0
  11. package/config/skills/agent/core/schedule-followup/SKILL.md +53 -0
  12. package/config/skills/agent/core/schedule-followup/execute.sh +176 -0
  13. package/config/skills/agent/core/schedule-followup/execute.test.sh +48 -0
  14. package/config/skills/agent/core/watch-for-event/SKILL.md +60 -0
  15. package/config/skills/agent/core/watch-for-event/execute.sh +158 -0
  16. package/config/skills/agent/core/watch-for-event/execute.test.sh +43 -0
  17. package/config/skills/orchestrator/credential-manager/SKILL.md +218 -0
  18. package/config/skills/orchestrator/credential-manager/execute.sh +166 -0
  19. package/config/skills/orchestrator/credential-manager/execute.test.sh +88 -0
  20. package/dist/backend/backend/src/config/oauth.config.d.ts +33 -0
  21. package/dist/backend/backend/src/config/oauth.config.d.ts.map +1 -0
  22. package/dist/backend/backend/src/config/oauth.config.js +45 -0
  23. package/dist/backend/backend/src/config/oauth.config.js.map +1 -0
  24. package/dist/backend/backend/src/controllers/credentials/credentials.controller.d.ts +54 -0
  25. package/dist/backend/backend/src/controllers/credentials/credentials.controller.d.ts.map +1 -0
  26. package/dist/backend/backend/src/controllers/credentials/credentials.controller.js +228 -0
  27. package/dist/backend/backend/src/controllers/credentials/credentials.controller.js.map +1 -0
  28. package/dist/backend/backend/src/controllers/credentials/credentials.routes.d.ts +26 -0
  29. package/dist/backend/backend/src/controllers/credentials/credentials.routes.d.ts.map +1 -0
  30. package/dist/backend/backend/src/controllers/credentials/credentials.routes.js +41 -0
  31. package/dist/backend/backend/src/controllers/credentials/credentials.routes.js.map +1 -0
  32. package/dist/backend/backend/src/controllers/credentials/google-oauth.controller.d.ts +40 -0
  33. package/dist/backend/backend/src/controllers/credentials/google-oauth.controller.d.ts.map +1 -0
  34. package/dist/backend/backend/src/controllers/credentials/google-oauth.controller.js +162 -0
  35. package/dist/backend/backend/src/controllers/credentials/google-oauth.controller.js.map +1 -0
  36. package/dist/backend/backend/src/controllers/skill/skill.controller.d.ts.map +1 -1
  37. package/dist/backend/backend/src/controllers/skill/skill.controller.js +1 -0
  38. package/dist/backend/backend/src/controllers/skill/skill.controller.js.map +1 -1
  39. package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js +23 -14
  40. package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js.map +1 -1
  41. package/dist/backend/backend/src/index.d.ts.map +1 -1
  42. package/dist/backend/backend/src/index.js +23 -4
  43. package/dist/backend/backend/src/index.js.map +1 -1
  44. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  45. package/dist/backend/backend/src/routes/api.routes.js +3 -0
  46. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  47. package/dist/backend/backend/src/scripts/backfill-mission-priority.d.ts +3 -1
  48. package/dist/backend/backend/src/scripts/backfill-mission-priority.d.ts.map +1 -1
  49. package/dist/backend/backend/src/scripts/backfill-mission-priority.js +16 -4
  50. package/dist/backend/backend/src/scripts/backfill-mission-priority.js.map +1 -1
  51. package/dist/backend/backend/src/services/ai/prompt-modules/role-boundary.module.d.ts.map +1 -1
  52. package/dist/backend/backend/src/services/ai/prompt-modules/role-boundary.module.js +4 -1
  53. package/dist/backend/backend/src/services/ai/prompt-modules/role-boundary.module.js.map +1 -1
  54. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
  55. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js +17 -0
  56. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
  57. package/dist/backend/backend/src/services/browser/browser-proxy.service.js +1 -1
  58. package/dist/backend/backend/src/services/browser/browser-proxy.service.js.map +1 -1
  59. package/dist/backend/backend/src/services/credential/credential-store.service.d.ts +161 -0
  60. package/dist/backend/backend/src/services/credential/credential-store.service.d.ts.map +1 -0
  61. package/dist/backend/backend/src/services/credential/credential-store.service.js +298 -0
  62. package/dist/backend/backend/src/services/credential/credential-store.service.js.map +1 -0
  63. package/dist/backend/backend/src/services/credential/helpers/gemini-cli-workspace.helper.d.ts +105 -0
  64. package/dist/backend/backend/src/services/credential/helpers/gemini-cli-workspace.helper.d.ts.map +1 -0
  65. package/dist/backend/backend/src/services/credential/helpers/gemini-cli-workspace.helper.js +272 -0
  66. package/dist/backend/backend/src/services/credential/helpers/gemini-cli-workspace.helper.js.map +1 -0
  67. package/dist/backend/backend/src/services/mcp-server.d.ts +46 -2
  68. package/dist/backend/backend/src/services/mcp-server.d.ts.map +1 -1
  69. package/dist/backend/backend/src/services/mcp-server.js +216 -211
  70. package/dist/backend/backend/src/services/mcp-server.js.map +1 -1
  71. package/dist/backend/backend/src/services/mcp-tool-definitions.d.ts +254 -0
  72. package/dist/backend/backend/src/services/mcp-tool-definitions.d.ts.map +1 -0
  73. package/dist/backend/backend/src/services/mcp-tool-definitions.js +285 -0
  74. package/dist/backend/backend/src/services/mcp-tool-definitions.js.map +1 -0
  75. package/dist/backend/backend/src/services/project/task.service.d.ts +18 -2
  76. package/dist/backend/backend/src/services/project/task.service.d.ts.map +1 -1
  77. package/dist/backend/backend/src/services/project/task.service.js +74 -53
  78. package/dist/backend/backend/src/services/project/task.service.js.map +1 -1
  79. package/dist/backend/backend/src/services/skill/skill-executor.service.d.ts +41 -0
  80. package/dist/backend/backend/src/services/skill/skill-executor.service.d.ts.map +1 -1
  81. package/dist/backend/backend/src/services/skill/skill-executor.service.js +136 -7
  82. package/dist/backend/backend/src/services/skill/skill-executor.service.js.map +1 -1
  83. package/dist/backend/backend/src/services/skill/skill.service.d.ts.map +1 -1
  84. package/dist/backend/backend/src/services/skill/skill.service.js +1 -0
  85. package/dist/backend/backend/src/services/skill/skill.service.js.map +1 -1
  86. package/dist/backend/backend/src/services/v3/contract-matcher.d.ts +20 -0
  87. package/dist/backend/backend/src/services/v3/contract-matcher.d.ts.map +1 -0
  88. package/dist/backend/backend/src/services/v3/contract-matcher.js +33 -0
  89. package/dist/backend/backend/src/services/v3/contract-matcher.js.map +1 -0
  90. package/dist/backend/backend/src/services/v3/escalation.service.d.ts +20 -1
  91. package/dist/backend/backend/src/services/v3/escalation.service.d.ts.map +1 -1
  92. package/dist/backend/backend/src/services/v3/escalation.service.js +97 -28
  93. package/dist/backend/backend/src/services/v3/escalation.service.js.map +1 -1
  94. package/dist/backend/backend/src/services/v3/service-contract-gate.service.d.ts +6 -4
  95. package/dist/backend/backend/src/services/v3/service-contract-gate.service.d.ts.map +1 -1
  96. package/dist/backend/backend/src/services/v3/service-contract-gate.service.js +18 -28
  97. package/dist/backend/backend/src/services/v3/service-contract-gate.service.js.map +1 -1
  98. package/dist/backend/backend/src/services/v3/team-trigger-reconciler.service.d.ts.map +1 -1
  99. package/dist/backend/backend/src/services/v3/team-trigger-reconciler.service.js +14 -9
  100. package/dist/backend/backend/src/services/v3/team-trigger-reconciler.service.js.map +1 -1
  101. package/dist/backend/backend/src/services/v3/trigger-engine.service.d.ts +34 -1
  102. package/dist/backend/backend/src/services/v3/trigger-engine.service.d.ts.map +1 -1
  103. package/dist/backend/backend/src/services/v3/trigger-engine.service.js +115 -5
  104. package/dist/backend/backend/src/services/v3/trigger-engine.service.js.map +1 -1
  105. package/dist/backend/backend/src/types/credential.types.d.ts +185 -0
  106. package/dist/backend/backend/src/types/credential.types.d.ts.map +1 -0
  107. package/dist/backend/backend/src/types/credential.types.js +76 -0
  108. package/dist/backend/backend/src/types/credential.types.js.map +1 -0
  109. package/dist/backend/backend/src/types/skill.types.d.ts +9 -0
  110. package/dist/backend/backend/src/types/skill.types.d.ts.map +1 -1
  111. package/dist/backend/backend/src/types/skill.types.js.map +1 -1
  112. package/dist/backend/backend/src/utils/encryption.utils.d.ts +57 -0
  113. package/dist/backend/backend/src/utils/encryption.utils.d.ts.map +1 -0
  114. package/dist/backend/backend/src/utils/encryption.utils.js +162 -0
  115. package/dist/backend/backend/src/utils/encryption.utils.js.map +1 -0
  116. package/dist/backend/backend/src/utils/google-userinfo.utils.d.ts +41 -0
  117. package/dist/backend/backend/src/utils/google-userinfo.utils.d.ts.map +1 -0
  118. package/dist/backend/backend/src/utils/google-userinfo.utils.js +44 -0
  119. package/dist/backend/backend/src/utils/google-userinfo.utils.js.map +1 -0
  120. package/dist/cli/backend/src/config/oauth.config.d.ts +33 -0
  121. package/dist/cli/backend/src/config/oauth.config.d.ts.map +1 -0
  122. package/dist/cli/backend/src/config/oauth.config.js +45 -0
  123. package/dist/cli/backend/src/config/oauth.config.js.map +1 -0
  124. package/dist/cli/backend/src/services/credential/credential-store.service.d.ts +161 -0
  125. package/dist/cli/backend/src/services/credential/credential-store.service.d.ts.map +1 -0
  126. package/dist/cli/backend/src/services/credential/credential-store.service.js +298 -0
  127. package/dist/cli/backend/src/services/credential/credential-store.service.js.map +1 -0
  128. package/dist/cli/backend/src/services/credential/helpers/gemini-cli-workspace.helper.d.ts +105 -0
  129. package/dist/cli/backend/src/services/credential/helpers/gemini-cli-workspace.helper.d.ts.map +1 -0
  130. package/dist/cli/backend/src/services/credential/helpers/gemini-cli-workspace.helper.js +272 -0
  131. package/dist/cli/backend/src/services/credential/helpers/gemini-cli-workspace.helper.js.map +1 -0
  132. package/dist/cli/backend/src/services/mcp-server.d.ts +46 -2
  133. package/dist/cli/backend/src/services/mcp-server.d.ts.map +1 -1
  134. package/dist/cli/backend/src/services/mcp-server.js +216 -211
  135. package/dist/cli/backend/src/services/mcp-server.js.map +1 -1
  136. package/dist/cli/backend/src/services/mcp-tool-definitions.d.ts +254 -0
  137. package/dist/cli/backend/src/services/mcp-tool-definitions.d.ts.map +1 -0
  138. package/dist/cli/backend/src/services/mcp-tool-definitions.js +285 -0
  139. package/dist/cli/backend/src/services/mcp-tool-definitions.js.map +1 -0
  140. package/dist/cli/backend/src/services/settings/settings.service.d.ts +168 -0
  141. package/dist/cli/backend/src/services/settings/settings.service.d.ts.map +1 -0
  142. package/dist/cli/backend/src/services/settings/settings.service.js +312 -0
  143. package/dist/cli/backend/src/services/settings/settings.service.js.map +1 -0
  144. package/dist/cli/backend/src/services/skill/skill-executor.service.d.ts +177 -0
  145. package/dist/cli/backend/src/services/skill/skill-executor.service.d.ts.map +1 -0
  146. package/dist/cli/backend/src/services/skill/skill-executor.service.js +624 -0
  147. package/dist/cli/backend/src/services/skill/skill-executor.service.js.map +1 -0
  148. package/dist/cli/backend/src/services/skill/skill.service.d.ts +273 -0
  149. package/dist/cli/backend/src/services/skill/skill.service.d.ts.map +1 -0
  150. package/dist/cli/backend/src/services/skill/skill.service.js +655 -0
  151. package/dist/cli/backend/src/services/skill/skill.service.js.map +1 -0
  152. package/dist/cli/backend/src/types/credential.types.d.ts +185 -0
  153. package/dist/cli/backend/src/types/credential.types.d.ts.map +1 -0
  154. package/dist/cli/backend/src/types/credential.types.js +76 -0
  155. package/dist/cli/backend/src/types/credential.types.js.map +1 -0
  156. package/dist/cli/backend/src/types/skill.types.d.ts +9 -0
  157. package/dist/cli/backend/src/types/skill.types.d.ts.map +1 -1
  158. package/dist/cli/backend/src/types/skill.types.js.map +1 -1
  159. package/dist/cli/backend/src/utils/encryption.utils.d.ts +57 -0
  160. package/dist/cli/backend/src/utils/encryption.utils.d.ts.map +1 -0
  161. package/dist/cli/backend/src/utils/encryption.utils.js +162 -0
  162. package/dist/cli/backend/src/utils/encryption.utils.js.map +1 -0
  163. package/dist/cli/backend/src/utils/google-userinfo.utils.d.ts +41 -0
  164. package/dist/cli/backend/src/utils/google-userinfo.utils.d.ts.map +1 -0
  165. package/dist/cli/backend/src/utils/google-userinfo.utils.js +44 -0
  166. package/dist/cli/backend/src/utils/google-userinfo.utils.js.map +1 -0
  167. package/dist/cli/backend/src/utils/skill-md-parser.d.ts +38 -0
  168. package/dist/cli/backend/src/utils/skill-md-parser.d.ts.map +1 -0
  169. package/dist/cli/backend/src/utils/skill-md-parser.js +47 -0
  170. package/dist/cli/backend/src/utils/skill-md-parser.js.map +1 -0
  171. package/frontend/dist/assets/{index-dc92ab64.css → index-6aaa0630.css} +1 -1
  172. package/frontend/dist/assets/{index-76d76633.js → index-70356616.js} +334 -328
  173. package/frontend/dist/index.html +2 -2
  174. package/package.json +1 -1
  175. package/config/experts/empathetic-resolver/expert.json +0 -11
  176. package/config/experts/empathetic-resolver.md +0 -32
  177. package/config/experts/pragmatic-architect/expert.json +0 -11
  178. package/config/experts/pragmatic-architect.md +0 -32
  179. package/config/experts/viral-alchemist/expert.json +0 -11
  180. package/config/experts/viral-alchemist.md +0 -32
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Gemini CLI Workspace Credential Helper
3
+ *
4
+ * Piggybacks on the Google Workspace extension for Gemini CLI
5
+ * (https://github.com/gemini-cli-extensions/workspace) for Google OAuth
6
+ * credential acquisition and refresh.
7
+ *
8
+ * **Capture** reads the extension's file-storage token file (written when
9
+ * the user runs the extension with `GEMINI_CLI_WORKSPACE_FORCE_FILE_STORAGE=true`)
10
+ * and imports the tokens into Crewly's own encrypted store.
11
+ *
12
+ * **Refresh** POSTs the stored `refresh_token` to the extension's Cloud
13
+ * Function `/refreshToken` endpoint — no client_secret needed on our side.
14
+ *
15
+ * After capture, Crewly owns the tokens; the extension's own state is not
16
+ * depended on for day-to-day operation.
17
+ *
18
+ * @module services/credential/helpers/gemini-cli-workspace.helper
19
+ */
20
+ import { CredentialHelper, CredentialHelperName, CredentialRegistryEntry, GoogleOAuthPayload } from '../../../types/credential.types.js';
21
+ import { CredentialStoreService } from '../credential-store.service.js';
22
+ import { FetchLike as UserinfoFetchLike } from '../../../utils/google-userinfo.utils.js';
23
+ /**
24
+ * Minimal fetch-compatible function shape (for test injection). Re-exported
25
+ * from the google-userinfo utility so callers can import a single type.
26
+ */
27
+ export type FetchLike = UserinfoFetchLike;
28
+ /**
29
+ * Helper configuration — all fields optional; defaults match production.
30
+ */
31
+ export interface GeminiCliHelperConfig {
32
+ /** Path to the extension install directory (default: `~/.gemini/extensions/google-workspace`). */
33
+ extensionPath?: string;
34
+ /** Cloud Function base URL. */
35
+ cloudFunctionUrl?: string;
36
+ /** Path on the cloud function for refresh calls. */
37
+ refreshPath?: string;
38
+ /** Client ID to store on the credential (for later refresh identification). */
39
+ clientId?: string;
40
+ /** Refresh buffer in ms — refresh if token expires within this window. */
41
+ expiryBufferMs?: number;
42
+ /** Fetch implementation (injectable for tests). */
43
+ fetch?: FetchLike;
44
+ }
45
+ /**
46
+ * Credential helper that reads tokens from the gemini-cli-workspace extension
47
+ * and refreshes them via the extension's Cloud Function.
48
+ */
49
+ export declare class GeminiCliWorkspaceHelper implements CredentialHelper {
50
+ readonly name: CredentialHelperName;
51
+ private readonly extensionPath;
52
+ private readonly cloudFunctionUrl;
53
+ private readonly refreshPath;
54
+ private readonly clientId;
55
+ private readonly expiryBufferMs;
56
+ private readonly fetchFn;
57
+ private readonly store;
58
+ /** Per-credential refresh in-flight promises (serializes concurrent refreshes). */
59
+ private readonly refreshInFlight;
60
+ /** Per-credential last refresh attempt timestamp (for cooldown). */
61
+ private readonly lastRefreshAttempt;
62
+ constructor(store: CredentialStoreService, config?: GeminiCliHelperConfig);
63
+ /**
64
+ * Read the extension's current token file and return its contents as a
65
+ * `GoogleOAuthPayload` ready to persist in Crewly's store.
66
+ *
67
+ * The user must have completed extension login with
68
+ * `GEMINI_CLI_WORKSPACE_FORCE_FILE_STORAGE=true` before calling this.
69
+ */
70
+ captureFromFile(): Promise<GoogleOAuthPayload>;
71
+ /**
72
+ * Remove the extension's token file. Call after `captureFromFile()` to
73
+ * prepare for the next account's login (the extension otherwise returns
74
+ * cached credentials if scopes match, skipping the login prompt).
75
+ * Leaves the master.key file untouched so existing ciphertexts remain
76
+ * decryptable if needed.
77
+ */
78
+ clearExtensionFile(): Promise<void>;
79
+ /**
80
+ * Return a valid `GoogleOAuthPayload`, refreshing via the extension's
81
+ * cloud function if the access token is within the expiry buffer.
82
+ *
83
+ * Concurrent calls for the same credential share a single refresh.
84
+ *
85
+ * @throws CredentialRevokedError if the refresh token is no longer valid
86
+ */
87
+ getAccessToken(entry: CredentialRegistryEntry, payload: GoogleOAuthPayload): Promise<GoogleOAuthPayload>;
88
+ private doRefresh;
89
+ /**
90
+ * Decrypt the extension's `{iv_hex}:{authTag_hex}:{ciphertext_hex}`
91
+ * format (AES-256-GCM).
92
+ */
93
+ private decryptExtensionFormat;
94
+ }
95
+ /**
96
+ * Encrypt a plaintext string with the extension's file format. Used in
97
+ * tests to generate fake token files.
98
+ */
99
+ export declare function encryptExtensionFormatForTesting(plaintext: string, key: Buffer): string;
100
+ /**
101
+ * Derive the extension's encryption key using the real scrypt + salt.
102
+ * Test-only export.
103
+ */
104
+ export declare function deriveExtensionKeyForTesting(masterKey: Buffer): Buffer;
105
+ //# sourceMappingURL=gemini-cli-workspace.helper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini-cli-workspace.helper.d.ts","sourceRoot":"","sources":["../../../../../../../backend/src/services/credential/helpers/gemini-cli-workspace.helper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAOH,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,uBAAuB,EACvB,kBAAkB,EAEnB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAMxE,OAAO,EAEL,SAAS,IAAI,iBAAiB,EAC/B,MAAM,yCAAyC,CAAC;AA2CjD;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG,iBAAiB,CAAC;AAE1C;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,kGAAkG;IAClG,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+BAA+B;IAC/B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,oDAAoD;IACpD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mDAAmD;IACnD,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AAMD;;;GAGG;AACH,qBAAa,wBAAyB,YAAW,gBAAgB;IAC/D,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAA0B;IAE7D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAY;IACpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAyB;IAE/C,mFAAmF;IACnF,OAAO,CAAC,QAAQ,CAAC,eAAe,CAG5B;IACJ,oEAAoE;IACpE,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA6B;gBAG9D,KAAK,EAAE,sBAAsB,EAC7B,MAAM,CAAC,EAAE,qBAAqB;IAkBhC;;;;;;OAMG;IACG,eAAe,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAoEpD;;;;;;OAMG;IACG,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAczC;;;;;;;OAOG;IACG,cAAc,CAClB,KAAK,EAAE,uBAAuB,EAC9B,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,kBAAkB,CAAC;YA4BhB,SAAS;IAuEvB;;;OAGG;IACH,OAAO,CAAC,sBAAsB;CAoB/B;AAMD;;;GAGG;AACH,wBAAgB,gCAAgC,CAC9C,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,GACV,MAAM,CAOR;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAGtE"}
@@ -0,0 +1,272 @@
1
+ /**
2
+ * Gemini CLI Workspace Credential Helper
3
+ *
4
+ * Piggybacks on the Google Workspace extension for Gemini CLI
5
+ * (https://github.com/gemini-cli-extensions/workspace) for Google OAuth
6
+ * credential acquisition and refresh.
7
+ *
8
+ * **Capture** reads the extension's file-storage token file (written when
9
+ * the user runs the extension with `GEMINI_CLI_WORKSPACE_FORCE_FILE_STORAGE=true`)
10
+ * and imports the tokens into Crewly's own encrypted store.
11
+ *
12
+ * **Refresh** POSTs the stored `refresh_token` to the extension's Cloud
13
+ * Function `/refreshToken` endpoint — no client_secret needed on our side.
14
+ *
15
+ * After capture, Crewly owns the tokens; the extension's own state is not
16
+ * depended on for day-to-day operation.
17
+ *
18
+ * @module services/credential/helpers/gemini-cli-workspace.helper
19
+ */
20
+ import { promises as fs } from 'fs';
21
+ import path from 'path';
22
+ import os from 'os';
23
+ import crypto from 'crypto';
24
+ import { CredentialRevokedError, } from '../../../types/credential.types.js';
25
+ import { GEMINI_CLI_CLOUD_FUNCTION_URL, GEMINI_CLI_REFRESH_PATH, GOOGLE_OAUTH_CLIENT_ID, } from '../../../config/oauth.config.js';
26
+ import { fetchGoogleAccountEmail, } from '../../../utils/google-userinfo.utils.js';
27
+ // ============================================================================
28
+ // Constants — extension-specific file layout and refresh tuning
29
+ // (github.com/gemini-cli-extensions/workspace)
30
+ // ============================================================================
31
+ const DEFAULT_EXTENSION_PATH = path.join(os.homedir(), '.gemini', 'extensions', 'google-workspace');
32
+ const TOKEN_FILENAME = 'gemini-cli-workspace-token.json';
33
+ const MASTER_KEY_FILENAME = '.gemini-cli-workspace-master-key';
34
+ const MAIN_ACCOUNT_KEY = 'main-account';
35
+ const SALT_SUFFIX = '-gemini-cli-workspace';
36
+ /** Refresh if the current access token expires within this window. */
37
+ const DEFAULT_EXPIRY_BUFFER_MS = 60_000;
38
+ /** Minimum gap between refresh attempts for the same credential. */
39
+ const REFRESH_COOLDOWN_MS = 30_000;
40
+ // ============================================================================
41
+ // Helper
42
+ // ============================================================================
43
+ /**
44
+ * Credential helper that reads tokens from the gemini-cli-workspace extension
45
+ * and refreshes them via the extension's Cloud Function.
46
+ */
47
+ export class GeminiCliWorkspaceHelper {
48
+ name = 'gemini-cli-workspace';
49
+ extensionPath;
50
+ cloudFunctionUrl;
51
+ refreshPath;
52
+ clientId;
53
+ expiryBufferMs;
54
+ fetchFn;
55
+ store;
56
+ /** Per-credential refresh in-flight promises (serializes concurrent refreshes). */
57
+ refreshInFlight = new Map();
58
+ /** Per-credential last refresh attempt timestamp (for cooldown). */
59
+ lastRefreshAttempt = new Map();
60
+ constructor(store, config) {
61
+ this.store = store;
62
+ this.extensionPath = config?.extensionPath ?? DEFAULT_EXTENSION_PATH;
63
+ this.cloudFunctionUrl =
64
+ config?.cloudFunctionUrl ?? GEMINI_CLI_CLOUD_FUNCTION_URL;
65
+ this.refreshPath = config?.refreshPath ?? GEMINI_CLI_REFRESH_PATH;
66
+ this.clientId = config?.clientId ?? GOOGLE_OAUTH_CLIENT_ID;
67
+ this.expiryBufferMs = config?.expiryBufferMs ?? DEFAULT_EXPIRY_BUFFER_MS;
68
+ this.fetchFn =
69
+ config?.fetch ??
70
+ ((url, init) => fetch(url, init));
71
+ }
72
+ // ------------------------------------------------------------------
73
+ // Capture
74
+ // ------------------------------------------------------------------
75
+ /**
76
+ * Read the extension's current token file and return its contents as a
77
+ * `GoogleOAuthPayload` ready to persist in Crewly's store.
78
+ *
79
+ * The user must have completed extension login with
80
+ * `GEMINI_CLI_WORKSPACE_FORCE_FILE_STORAGE=true` before calling this.
81
+ */
82
+ async captureFromFile() {
83
+ const tokenPath = path.join(this.extensionPath, TOKEN_FILENAME);
84
+ const masterKeyPath = path.join(this.extensionPath, MASTER_KEY_FILENAME);
85
+ // Surface a user-friendly error if login hasn't happened yet
86
+ try {
87
+ await fs.access(tokenPath);
88
+ }
89
+ catch {
90
+ throw new Error(`Gemini CLI Workspace token file not found at ${tokenPath}. ` +
91
+ `Please run 'GEMINI_CLI_WORKSPACE_FORCE_FILE_STORAGE=true gemini' ` +
92
+ `and complete Google sign-in first, then retry.`);
93
+ }
94
+ try {
95
+ await fs.access(masterKeyPath);
96
+ }
97
+ catch {
98
+ throw new Error(`Gemini CLI Workspace master key file not found at ${masterKeyPath}. ` +
99
+ `The extension should create this on first login.`);
100
+ }
101
+ const encryptedText = await fs.readFile(tokenPath, 'utf8');
102
+ const masterKey = await fs.readFile(masterKeyPath);
103
+ // Derive the extension's encryption key (scrypt with hostname-username salt).
104
+ // Must match `file-token-storage.ts` exactly.
105
+ const salt = `${os.hostname()}-${os.userInfo().username}${SALT_SUFFIX}`;
106
+ const encryptionKey = crypto.scryptSync(masterKey, salt, 32);
107
+ const decrypted = this.decryptExtensionFormat(encryptedText, encryptionKey);
108
+ const parsed = JSON.parse(decrypted);
109
+ const entry = parsed[MAIN_ACCOUNT_KEY];
110
+ if (!entry) {
111
+ throw new Error(`Extension token file does not contain a '${MAIN_ACCOUNT_KEY}' entry. ` +
112
+ `Did login complete successfully?`);
113
+ }
114
+ const { accessToken, refreshToken, tokenType, scope, expiresAt } = entry.token;
115
+ if (!accessToken || !refreshToken) {
116
+ throw new Error(`Extension token is missing accessToken or refreshToken — login may be incomplete.`);
117
+ }
118
+ const scopes = typeof scope === 'string' ? scope.split(' ').filter(Boolean) : [];
119
+ const accountEmail = await fetchGoogleAccountEmail(accessToken, this.fetchFn);
120
+ return {
121
+ type: 'google-oauth',
122
+ accessToken,
123
+ refreshToken,
124
+ tokenType: tokenType ?? 'Bearer',
125
+ expiresAt: expiresAt ?? Date.now() + 3600_000,
126
+ scopes,
127
+ accountEmail,
128
+ clientId: this.clientId,
129
+ };
130
+ }
131
+ /**
132
+ * Remove the extension's token file. Call after `captureFromFile()` to
133
+ * prepare for the next account's login (the extension otherwise returns
134
+ * cached credentials if scopes match, skipping the login prompt).
135
+ * Leaves the master.key file untouched so existing ciphertexts remain
136
+ * decryptable if needed.
137
+ */
138
+ async clearExtensionFile() {
139
+ const tokenPath = path.join(this.extensionPath, TOKEN_FILENAME);
140
+ try {
141
+ await fs.unlink(tokenPath);
142
+ }
143
+ catch (err) {
144
+ if (err.code === 'ENOENT')
145
+ return;
146
+ throw err;
147
+ }
148
+ }
149
+ // ------------------------------------------------------------------
150
+ // Refresh / getAccessToken
151
+ // ------------------------------------------------------------------
152
+ /**
153
+ * Return a valid `GoogleOAuthPayload`, refreshing via the extension's
154
+ * cloud function if the access token is within the expiry buffer.
155
+ *
156
+ * Concurrent calls for the same credential share a single refresh.
157
+ *
158
+ * @throws CredentialRevokedError if the refresh token is no longer valid
159
+ */
160
+ async getAccessToken(entry, payload) {
161
+ // Fast path: still valid
162
+ if (payload.expiresAt - Date.now() > this.expiryBufferMs) {
163
+ return payload;
164
+ }
165
+ // Coalesce concurrent refreshes for the same credential
166
+ const existing = this.refreshInFlight.get(entry.id);
167
+ if (existing)
168
+ return existing;
169
+ // Cooldown — avoid hammering the refresh endpoint
170
+ const last = this.lastRefreshAttempt.get(entry.id) ?? 0;
171
+ if (Date.now() - last < REFRESH_COOLDOWN_MS) {
172
+ // Within cooldown — return the (possibly expired) payload; caller will
173
+ // get a fresh attempt after the cooldown window.
174
+ return payload;
175
+ }
176
+ const promise = this.doRefresh(entry, payload);
177
+ this.refreshInFlight.set(entry.id, promise);
178
+ this.lastRefreshAttempt.set(entry.id, Date.now());
179
+ try {
180
+ return await promise;
181
+ }
182
+ finally {
183
+ this.refreshInFlight.delete(entry.id);
184
+ }
185
+ }
186
+ async doRefresh(entry, payload) {
187
+ const url = this.cloudFunctionUrl.replace(/\/$/, '') + this.refreshPath;
188
+ const response = await this.fetchFn(url, {
189
+ method: 'POST',
190
+ headers: { 'Content-Type': 'application/json' },
191
+ body: JSON.stringify({ refresh_token: payload.refreshToken }),
192
+ });
193
+ if (!response.ok) {
194
+ const body = await response.text().catch(() => '');
195
+ // Google responds 400 with body containing "invalid_grant" when the
196
+ // refresh token is revoked/expired beyond recovery.
197
+ if (response.status === 400 &&
198
+ /invalid_grant/i.test(body)) {
199
+ await this.store.updateCredential(entry.id, { status: 'revoked' });
200
+ throw new CredentialRevokedError(entry.id, entry.name, `Log in to the Gemini CLI Workspace extension again and re-import this credential in Crewly.`);
201
+ }
202
+ throw new Error(`Token refresh failed (${response.status}): ${body.slice(0, 500)}`);
203
+ }
204
+ const data = (await response.json());
205
+ if (!data.access_token) {
206
+ throw new Error('Token refresh response missing access_token');
207
+ }
208
+ const expiresAt = Date.now() + (data.expires_in ?? 3600) * 1000;
209
+ const updated = {
210
+ ...payload,
211
+ accessToken: data.access_token,
212
+ expiresAt,
213
+ // Google typically does NOT issue a new refresh_token on refresh,
214
+ // but honor it if present
215
+ refreshToken: data.refresh_token ?? payload.refreshToken,
216
+ scopes: typeof data.scope === 'string'
217
+ ? data.scope.split(' ').filter(Boolean)
218
+ : payload.scopes,
219
+ };
220
+ await this.store.setPayload(entry.id, updated);
221
+ await this.store.updateCredential(entry.id, {
222
+ expiresAt,
223
+ lastUsedAt: new Date().toISOString(),
224
+ });
225
+ return updated;
226
+ }
227
+ // ------------------------------------------------------------------
228
+ // Internals
229
+ // ------------------------------------------------------------------
230
+ /**
231
+ * Decrypt the extension's `{iv_hex}:{authTag_hex}:{ciphertext_hex}`
232
+ * format (AES-256-GCM).
233
+ */
234
+ decryptExtensionFormat(encryptedText, key) {
235
+ const parts = encryptedText.split(':');
236
+ if (parts.length !== 3) {
237
+ throw new Error('Invalid extension token format (expected iv:tag:ciphertext)');
238
+ }
239
+ const iv = Buffer.from(parts[0], 'hex');
240
+ const authTag = Buffer.from(parts[1], 'hex');
241
+ const ciphertextHex = parts[2];
242
+ const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
243
+ decipher.setAuthTag(authTag);
244
+ let decrypted = decipher.update(ciphertextHex, 'hex', 'utf8');
245
+ decrypted += decipher.final('utf8');
246
+ return decrypted;
247
+ }
248
+ }
249
+ // ============================================================================
250
+ // Test helpers (not exported from public barrel — intended for tests only)
251
+ // ============================================================================
252
+ /**
253
+ * Encrypt a plaintext string with the extension's file format. Used in
254
+ * tests to generate fake token files.
255
+ */
256
+ export function encryptExtensionFormatForTesting(plaintext, key) {
257
+ const iv = crypto.randomBytes(16);
258
+ const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
259
+ let encrypted = cipher.update(plaintext, 'utf8', 'hex');
260
+ encrypted += cipher.final('hex');
261
+ const authTag = cipher.getAuthTag();
262
+ return iv.toString('hex') + ':' + authTag.toString('hex') + ':' + encrypted;
263
+ }
264
+ /**
265
+ * Derive the extension's encryption key using the real scrypt + salt.
266
+ * Test-only export.
267
+ */
268
+ export function deriveExtensionKeyForTesting(masterKey) {
269
+ const salt = `${os.hostname()}-${os.userInfo().username}${SALT_SUFFIX}`;
270
+ return crypto.scryptSync(masterKey, salt, 32);
271
+ }
272
+ //# sourceMappingURL=gemini-cli-workspace.helper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini-cli-workspace.helper.js","sourceRoot":"","sources":["../../../../../../../backend/src/services/credential/helpers/gemini-cli-workspace.helper.ts"],"names":[],"mappings":"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"}
@@ -64,10 +64,12 @@ export interface CrewlyMcpServerConfig {
64
64
  */
65
65
  export declare class CrewlyMcpServer {
66
66
  private server;
67
- private storage;
68
- private memory;
67
+ private readonly storage;
68
+ private readonly memory;
69
69
  private transport;
70
70
  private stdioTransportCtor;
71
+ private geminiCliHelper;
72
+ private getGeminiCliHelper;
71
73
  /**
72
74
  * Creates a new CrewlyMcpServer instance.
73
75
  *
@@ -78,6 +80,14 @@ export declare class CrewlyMcpServer {
78
80
  * Register MCP request handlers for tool listing and tool calling.
79
81
  */
80
82
  private registerHandlers;
83
+ /**
84
+ * Build the Server + transport + handlers from already-loaded SDK modules.
85
+ * Returns false if any expected SDK symbol is missing (so the caller can
86
+ * decide whether to throw or silently fall back). Both `ensureInitialized`
87
+ * (dynamic import) and `tryInitializeWithRequire` (CommonJS require) feed
88
+ * their loaded modules through here.
89
+ */
90
+ private installSdkModules;
81
91
  private ensureInitialized;
82
92
  private tryInitializeWithRequire;
83
93
  /**
@@ -88,6 +98,14 @@ export declare class CrewlyMcpServer {
88
98
  * @returns Tool result with content blocks
89
99
  */
90
100
  private handleToolCall;
101
+ /**
102
+ * Format a TeamMember for an MCP response. Three variants share the
103
+ * same base (id/name/role/agentStatus/workingStatus); `includeRuntime`
104
+ * adds `runtimeType` + `sessionName`, and `includeTickets` adds
105
+ * `currentTickets`. Keeping all three paths in one place so that a
106
+ * field added to the member shape only needs to be surfaced once.
107
+ */
108
+ private formatMember;
91
109
  /**
92
110
  * Handle crewly_get_teams: list all teams and their members.
93
111
  *
@@ -134,6 +152,32 @@ export declare class CrewlyMcpServer {
134
152
  * @returns Confirmation with message ID
135
153
  */
136
154
  private handleSendMessage;
155
+ /**
156
+ * Handle crewly_credential_list: return credential metadata (no values).
157
+ */
158
+ private handleCredentialList;
159
+ /**
160
+ * Handle crewly_credential_add_api_key: store an API key.
161
+ */
162
+ private handleCredentialAddApiKey;
163
+ /**
164
+ * Handle crewly_credential_oauth_import_gemini_cli: capture the current
165
+ * gemini-cli-workspace extension login into an encrypted Crewly credential.
166
+ */
167
+ private handleCredentialImportGeminiCli;
168
+ /**
169
+ * Handle crewly_credential_clear_gemini_cli_file: delete the extension's
170
+ * cached token file so the next extension login captures a fresh account.
171
+ */
172
+ private handleCredentialClearGeminiCliFile;
173
+ /**
174
+ * Handle crewly_credential_delete: remove a credential.
175
+ */
176
+ private handleCredentialDelete;
177
+ /**
178
+ * Handle crewly_execute_skill: run a skill with optional credential bindings.
179
+ */
180
+ private handleExecuteSkill;
137
181
  /**
138
182
  * Create a success result with JSON-serialized content.
139
183
  *
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../../../../../backend/src/services/mcp-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AASH;;GAEG;AACH,eAAO,MAAM,oBAAoB;IAC/B,sDAAsD;;;;;IAKtD,uCAAuC;;CAE/B,CAAC;AAIX;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA0KD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,SAAS,CAAoB;IACrC,OAAO,CAAC,kBAAkB,CAAgC;IAE1D;;;;OAIG;gBACS,MAAM,CAAC,EAAE,qBAAqB;IAM1C;;OAEG;IACH,OAAO,CAAC,gBAAgB;YAwBV,iBAAiB;IAiC/B,OAAO,CAAC,wBAAwB;IA2ChC;;;;;;OAMG;YACW,cAAc;IA6B5B;;;;;OAKG;YACW,cAAc;IAoC5B;;;;;OAKG;YACW,gBAAgB;IA0D9B;;;;;;;;;OASG;YACW,gBAAgB;IA2C9B;;;;;OAKG;YACW,eAAe;IAiE7B;;;;;OAKG;YACW,kBAAkB;IAiChC;;;;;OAKG;YACW,iBAAiB;IAwB/B;;;;;OAKG;IACH,OAAO,CAAC,aAAa;IAMrB;;;;;OAKG;IACH,OAAO,CAAC,WAAW;IASnB;;;;;OAKG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAS5B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAO3B;;;;OAIG;IACH,SAAS,IAAI,GAAG;CAGjB"}
1
+ {"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../../../../../backend/src/services/mcp-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAcH;;GAEG;AACH,eAAO,MAAM,oBAAoB;IAC/B,sDAAsD;;;;;IAKtD,uCAAuC;;CAE/B,CAAC;AAIX;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAeD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,SAAS,CAAoB;IACrC,OAAO,CAAC,kBAAkB,CAAgC;IAC1D,OAAO,CAAC,eAAe,CAAyC;IAEhE,OAAO,CAAC,kBAAkB;IAO1B;;;;OAIG;gBACS,MAAM,CAAC,EAAE,qBAAqB;IAM1C;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAwBxB;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;YA2BX,iBAAiB;IAc/B,OAAO,CAAC,wBAAwB;IAsBhC;;;;;;OAMG;YACW,cAAc;IAyC5B;;;;;;OAMG;IACH,OAAO,CAAC,YAAY;IAuBpB;;;;;OAKG;YACW,cAAc;IA4B5B;;;;;OAKG;YACW,gBAAgB;IA8D9B;;;;;;;;;OASG;YACW,gBAAgB;IA4C9B;;;;;OAKG;YACW,eAAe;IAqD7B;;;;;OAKG;YACW,kBAAkB;IAiChC;;;;;OAKG;YACW,iBAAiB;IA0B/B;;OAEG;YACW,oBAAoB;IA6BlC;;OAEG;YACW,yBAAyB;IAqBvC;;;OAGG;YACW,+BAA+B;IA8B7C;;;OAGG;YACW,kCAAkC;IAKhD;;OAEG;YACW,sBAAsB;IAapC;;OAEG;YACW,kBAAkB;IA8BhC;;;;;OAKG;IACH,OAAO,CAAC,aAAa;IAMrB;;;;;OAKG;IACH,OAAO,CAAC,WAAW;IASnB;;;;;OAKG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAS5B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAO3B;;;;OAIG;IACH,SAAS,IAAI,GAAG;CAGjB"}