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.
- package/config/roles/orchestrator/fragments/role-boundary.md +4 -1
- package/config/roles/orchestrator/prompt.md +219 -25
- package/config/roles/orchestrator/soul.md +47 -10
- package/config/skills/_common/lib.sh +28 -0
- package/config/skills/agent/core/cancel-followup/SKILL.md +38 -0
- package/config/skills/agent/core/cancel-followup/execute.sh +92 -0
- package/config/skills/agent/core/cancel-followup/execute.test.sh +42 -0
- package/config/skills/agent/core/list-my-followups/SKILL.md +36 -0
- package/config/skills/agent/core/list-my-followups/execute.sh +74 -0
- package/config/skills/agent/core/list-my-followups/execute.test.sh +41 -0
- package/config/skills/agent/core/schedule-followup/SKILL.md +53 -0
- package/config/skills/agent/core/schedule-followup/execute.sh +176 -0
- package/config/skills/agent/core/schedule-followup/execute.test.sh +48 -0
- package/config/skills/agent/core/watch-for-event/SKILL.md +60 -0
- package/config/skills/agent/core/watch-for-event/execute.sh +158 -0
- package/config/skills/agent/core/watch-for-event/execute.test.sh +43 -0
- package/config/skills/orchestrator/credential-manager/SKILL.md +218 -0
- package/config/skills/orchestrator/credential-manager/execute.sh +166 -0
- package/config/skills/orchestrator/credential-manager/execute.test.sh +88 -0
- package/dist/backend/backend/src/config/oauth.config.d.ts +33 -0
- package/dist/backend/backend/src/config/oauth.config.d.ts.map +1 -0
- package/dist/backend/backend/src/config/oauth.config.js +45 -0
- package/dist/backend/backend/src/config/oauth.config.js.map +1 -0
- package/dist/backend/backend/src/controllers/credentials/credentials.controller.d.ts +54 -0
- package/dist/backend/backend/src/controllers/credentials/credentials.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/credentials/credentials.controller.js +228 -0
- package/dist/backend/backend/src/controllers/credentials/credentials.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/credentials/credentials.routes.d.ts +26 -0
- package/dist/backend/backend/src/controllers/credentials/credentials.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/credentials/credentials.routes.js +41 -0
- package/dist/backend/backend/src/controllers/credentials/credentials.routes.js.map +1 -0
- package/dist/backend/backend/src/controllers/credentials/google-oauth.controller.d.ts +40 -0
- package/dist/backend/backend/src/controllers/credentials/google-oauth.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/credentials/google-oauth.controller.js +162 -0
- package/dist/backend/backend/src/controllers/credentials/google-oauth.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/skill/skill.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/skill/skill.controller.js +1 -0
- package/dist/backend/backend/src/controllers/skill/skill.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js +23 -14
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +23 -4
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.js +3 -0
- package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
- package/dist/backend/backend/src/scripts/backfill-mission-priority.d.ts +3 -1
- package/dist/backend/backend/src/scripts/backfill-mission-priority.d.ts.map +1 -1
- package/dist/backend/backend/src/scripts/backfill-mission-priority.js +16 -4
- package/dist/backend/backend/src/scripts/backfill-mission-priority.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/role-boundary.module.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/role-boundary.module.js +4 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/role-boundary.module.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js +17 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
- package/dist/backend/backend/src/services/browser/browser-proxy.service.js +1 -1
- package/dist/backend/backend/src/services/browser/browser-proxy.service.js.map +1 -1
- package/dist/backend/backend/src/services/credential/credential-store.service.d.ts +161 -0
- package/dist/backend/backend/src/services/credential/credential-store.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/credential/credential-store.service.js +298 -0
- package/dist/backend/backend/src/services/credential/credential-store.service.js.map +1 -0
- package/dist/backend/backend/src/services/credential/helpers/gemini-cli-workspace.helper.d.ts +105 -0
- package/dist/backend/backend/src/services/credential/helpers/gemini-cli-workspace.helper.d.ts.map +1 -0
- package/dist/backend/backend/src/services/credential/helpers/gemini-cli-workspace.helper.js +272 -0
- package/dist/backend/backend/src/services/credential/helpers/gemini-cli-workspace.helper.js.map +1 -0
- package/dist/backend/backend/src/services/mcp-server.d.ts +46 -2
- package/dist/backend/backend/src/services/mcp-server.d.ts.map +1 -1
- package/dist/backend/backend/src/services/mcp-server.js +216 -211
- package/dist/backend/backend/src/services/mcp-server.js.map +1 -1
- package/dist/backend/backend/src/services/mcp-tool-definitions.d.ts +254 -0
- package/dist/backend/backend/src/services/mcp-tool-definitions.d.ts.map +1 -0
- package/dist/backend/backend/src/services/mcp-tool-definitions.js +285 -0
- package/dist/backend/backend/src/services/mcp-tool-definitions.js.map +1 -0
- package/dist/backend/backend/src/services/project/task.service.d.ts +18 -2
- package/dist/backend/backend/src/services/project/task.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project/task.service.js +74 -53
- package/dist/backend/backend/src/services/project/task.service.js.map +1 -1
- package/dist/backend/backend/src/services/skill/skill-executor.service.d.ts +41 -0
- package/dist/backend/backend/src/services/skill/skill-executor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/skill/skill-executor.service.js +136 -7
- package/dist/backend/backend/src/services/skill/skill-executor.service.js.map +1 -1
- package/dist/backend/backend/src/services/skill/skill.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/skill/skill.service.js +1 -0
- package/dist/backend/backend/src/services/skill/skill.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/contract-matcher.d.ts +20 -0
- package/dist/backend/backend/src/services/v3/contract-matcher.d.ts.map +1 -0
- package/dist/backend/backend/src/services/v3/contract-matcher.js +33 -0
- package/dist/backend/backend/src/services/v3/contract-matcher.js.map +1 -0
- package/dist/backend/backend/src/services/v3/escalation.service.d.ts +20 -1
- package/dist/backend/backend/src/services/v3/escalation.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/escalation.service.js +97 -28
- package/dist/backend/backend/src/services/v3/escalation.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/service-contract-gate.service.d.ts +6 -4
- package/dist/backend/backend/src/services/v3/service-contract-gate.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/service-contract-gate.service.js +18 -28
- package/dist/backend/backend/src/services/v3/service-contract-gate.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/team-trigger-reconciler.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/team-trigger-reconciler.service.js +14 -9
- package/dist/backend/backend/src/services/v3/team-trigger-reconciler.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/trigger-engine.service.d.ts +34 -1
- package/dist/backend/backend/src/services/v3/trigger-engine.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/trigger-engine.service.js +115 -5
- package/dist/backend/backend/src/services/v3/trigger-engine.service.js.map +1 -1
- package/dist/backend/backend/src/types/credential.types.d.ts +185 -0
- package/dist/backend/backend/src/types/credential.types.d.ts.map +1 -0
- package/dist/backend/backend/src/types/credential.types.js +76 -0
- package/dist/backend/backend/src/types/credential.types.js.map +1 -0
- package/dist/backend/backend/src/types/skill.types.d.ts +9 -0
- package/dist/backend/backend/src/types/skill.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/skill.types.js.map +1 -1
- package/dist/backend/backend/src/utils/encryption.utils.d.ts +57 -0
- package/dist/backend/backend/src/utils/encryption.utils.d.ts.map +1 -0
- package/dist/backend/backend/src/utils/encryption.utils.js +162 -0
- package/dist/backend/backend/src/utils/encryption.utils.js.map +1 -0
- package/dist/backend/backend/src/utils/google-userinfo.utils.d.ts +41 -0
- package/dist/backend/backend/src/utils/google-userinfo.utils.d.ts.map +1 -0
- package/dist/backend/backend/src/utils/google-userinfo.utils.js +44 -0
- package/dist/backend/backend/src/utils/google-userinfo.utils.js.map +1 -0
- package/dist/cli/backend/src/config/oauth.config.d.ts +33 -0
- package/dist/cli/backend/src/config/oauth.config.d.ts.map +1 -0
- package/dist/cli/backend/src/config/oauth.config.js +45 -0
- package/dist/cli/backend/src/config/oauth.config.js.map +1 -0
- package/dist/cli/backend/src/services/credential/credential-store.service.d.ts +161 -0
- package/dist/cli/backend/src/services/credential/credential-store.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/credential/credential-store.service.js +298 -0
- package/dist/cli/backend/src/services/credential/credential-store.service.js.map +1 -0
- package/dist/cli/backend/src/services/credential/helpers/gemini-cli-workspace.helper.d.ts +105 -0
- package/dist/cli/backend/src/services/credential/helpers/gemini-cli-workspace.helper.d.ts.map +1 -0
- package/dist/cli/backend/src/services/credential/helpers/gemini-cli-workspace.helper.js +272 -0
- package/dist/cli/backend/src/services/credential/helpers/gemini-cli-workspace.helper.js.map +1 -0
- package/dist/cli/backend/src/services/mcp-server.d.ts +46 -2
- package/dist/cli/backend/src/services/mcp-server.d.ts.map +1 -1
- package/dist/cli/backend/src/services/mcp-server.js +216 -211
- package/dist/cli/backend/src/services/mcp-server.js.map +1 -1
- package/dist/cli/backend/src/services/mcp-tool-definitions.d.ts +254 -0
- package/dist/cli/backend/src/services/mcp-tool-definitions.d.ts.map +1 -0
- package/dist/cli/backend/src/services/mcp-tool-definitions.js +285 -0
- package/dist/cli/backend/src/services/mcp-tool-definitions.js.map +1 -0
- package/dist/cli/backend/src/services/settings/settings.service.d.ts +168 -0
- package/dist/cli/backend/src/services/settings/settings.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/settings/settings.service.js +312 -0
- package/dist/cli/backend/src/services/settings/settings.service.js.map +1 -0
- package/dist/cli/backend/src/services/skill/skill-executor.service.d.ts +177 -0
- package/dist/cli/backend/src/services/skill/skill-executor.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/skill/skill-executor.service.js +624 -0
- package/dist/cli/backend/src/services/skill/skill-executor.service.js.map +1 -0
- package/dist/cli/backend/src/services/skill/skill.service.d.ts +273 -0
- package/dist/cli/backend/src/services/skill/skill.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/skill/skill.service.js +655 -0
- package/dist/cli/backend/src/services/skill/skill.service.js.map +1 -0
- package/dist/cli/backend/src/types/credential.types.d.ts +185 -0
- package/dist/cli/backend/src/types/credential.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/credential.types.js +76 -0
- package/dist/cli/backend/src/types/credential.types.js.map +1 -0
- package/dist/cli/backend/src/types/skill.types.d.ts +9 -0
- package/dist/cli/backend/src/types/skill.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/skill.types.js.map +1 -1
- package/dist/cli/backend/src/utils/encryption.utils.d.ts +57 -0
- package/dist/cli/backend/src/utils/encryption.utils.d.ts.map +1 -0
- package/dist/cli/backend/src/utils/encryption.utils.js +162 -0
- package/dist/cli/backend/src/utils/encryption.utils.js.map +1 -0
- package/dist/cli/backend/src/utils/google-userinfo.utils.d.ts +41 -0
- package/dist/cli/backend/src/utils/google-userinfo.utils.d.ts.map +1 -0
- package/dist/cli/backend/src/utils/google-userinfo.utils.js +44 -0
- package/dist/cli/backend/src/utils/google-userinfo.utils.js.map +1 -0
- package/dist/cli/backend/src/utils/skill-md-parser.d.ts +38 -0
- package/dist/cli/backend/src/utils/skill-md-parser.d.ts.map +1 -0
- package/dist/cli/backend/src/utils/skill-md-parser.js +47 -0
- package/dist/cli/backend/src/utils/skill-md-parser.js.map +1 -0
- package/frontend/dist/assets/{index-dc92ab64.css → index-6aaa0630.css} +1 -1
- package/frontend/dist/assets/{index-76d76633.js → index-70356616.js} +334 -328
- package/frontend/dist/index.html +2 -2
- package/package.json +1 -1
- package/config/experts/empathetic-resolver/expert.json +0 -11
- package/config/experts/empathetic-resolver.md +0 -32
- package/config/experts/pragmatic-architect/expert.json +0 -11
- package/config/experts/pragmatic-architect.md +0 -32
- package/config/experts/viral-alchemist/expert.json +0 -11
- 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
|
package/dist/backend/backend/src/services/credential/helpers/gemini-cli-workspace.helper.d.ts.map
ADDED
|
@@ -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
|
package/dist/backend/backend/src/services/credential/helpers/gemini-cli-workspace.helper.js.map
ADDED
|
@@ -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;
|
|
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"}
|