crewly 1.5.22 → 1.6.0
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/prompt.md +182 -25
- package/config/skills/agent/core/cancel-followup/SKILL.md +38 -0
- package/config/skills/agent/core/cancel-followup/execute.sh +111 -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 +93 -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 +195 -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 +177 -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/dist/backend/backend/src/controllers/credentials/credentials.controller.d.ts +80 -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 +365 -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 +40 -0
- package/dist/backend/backend/src/controllers/credentials/credentials.routes.js.map +1 -0
- 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/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/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 +117 -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 +293 -0
- package/dist/backend/backend/src/services/credential/helpers/gemini-cli-workspace.helper.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 +69 -53
- package/dist/backend/backend/src/services/project/task.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/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/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 +117 -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 +293 -0
- package/dist/cli/backend/src/services/credential/helpers/gemini-cli-workspace.helper.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 +159 -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 +626 -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/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/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-9e6d97d1.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,298 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credential Store Service
|
|
3
|
+
*
|
|
4
|
+
* Manages the workspace-level credential registry and per-credential
|
|
5
|
+
* encrypted payload files under `~/.crewly/credentials/`.
|
|
6
|
+
*
|
|
7
|
+
* The store is split into two surfaces:
|
|
8
|
+
*
|
|
9
|
+
* - **Metadata API** (`listCredentials`, `getCredential`, `findCredentialsByProvider`):
|
|
10
|
+
* returns `CredentialRegistryEntry` objects containing only non-secret
|
|
11
|
+
* information (id, name, provider, scopes, email, timestamps). Safe to
|
|
12
|
+
* expose to agent / LLM context and over MCP.
|
|
13
|
+
*
|
|
14
|
+
* - **Payload API** (`getPayload`, `setPayload`): decrypts the per-credential
|
|
15
|
+
* `.enc` file to return the actual token value(s). **Intended only for
|
|
16
|
+
* credential helpers and the skill executor** (which injects values into
|
|
17
|
+
* skill subprocess env vars). Callers must never return payload contents
|
|
18
|
+
* to agent/LLM context.
|
|
19
|
+
*
|
|
20
|
+
* Encrypted file format and threat model: see `utils/encryption.utils.ts`.
|
|
21
|
+
*
|
|
22
|
+
* @module services/credential/credential-store.service
|
|
23
|
+
*/
|
|
24
|
+
import { promises as fs } from 'fs';
|
|
25
|
+
import path from 'path';
|
|
26
|
+
import crypto from 'crypto';
|
|
27
|
+
import { CredentialNotFoundError, } from '../../types/credential.types.js';
|
|
28
|
+
import { ensureDir, atomicWriteFile, atomicWriteJson, safeReadJson, withOperationLock, } from '../../utils/file-io.utils.js';
|
|
29
|
+
import { encrypt, decrypt, ensureMasterKey, defaultCredentialsDir, } from '../../utils/encryption.utils.js';
|
|
30
|
+
// ============================================================================
|
|
31
|
+
// Constants
|
|
32
|
+
// ============================================================================
|
|
33
|
+
const REGISTRY_FILENAME = 'registry.json';
|
|
34
|
+
const EMPTY_REGISTRY = {
|
|
35
|
+
schemaVersion: 1,
|
|
36
|
+
credentials: [],
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* File-based credential store.
|
|
40
|
+
*/
|
|
41
|
+
export class CredentialStoreService {
|
|
42
|
+
dir;
|
|
43
|
+
registryPath;
|
|
44
|
+
masterKeyPath;
|
|
45
|
+
initialized = false;
|
|
46
|
+
constructor(options) {
|
|
47
|
+
this.dir = options?.dir ?? defaultCredentialsDir();
|
|
48
|
+
this.registryPath = path.join(this.dir, REGISTRY_FILENAME);
|
|
49
|
+
this.masterKeyPath =
|
|
50
|
+
options?.masterKeyPath ?? path.join(this.dir, 'master.key');
|
|
51
|
+
}
|
|
52
|
+
// ------------------------------------------------------------------
|
|
53
|
+
// Initialization (idempotent, lazy)
|
|
54
|
+
// ------------------------------------------------------------------
|
|
55
|
+
/**
|
|
56
|
+
* Ensure the credentials directory and master.key exist. Called
|
|
57
|
+
* automatically by every public method — safe to invoke explicitly
|
|
58
|
+
* for eager initialization.
|
|
59
|
+
*/
|
|
60
|
+
async init() {
|
|
61
|
+
if (this.initialized)
|
|
62
|
+
return;
|
|
63
|
+
await ensureDir(this.dir);
|
|
64
|
+
await ensureMasterKey(this.masterKeyPath);
|
|
65
|
+
this.initialized = true;
|
|
66
|
+
}
|
|
67
|
+
// ------------------------------------------------------------------
|
|
68
|
+
// Metadata API (safe to expose to agent/LLM)
|
|
69
|
+
// ------------------------------------------------------------------
|
|
70
|
+
/**
|
|
71
|
+
* List all credentials' metadata. Does not include secret values.
|
|
72
|
+
*/
|
|
73
|
+
async listCredentials() {
|
|
74
|
+
await this.init();
|
|
75
|
+
const reg = await this.readRegistry();
|
|
76
|
+
return reg.credentials;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Get a single credential's metadata by id.
|
|
80
|
+
*
|
|
81
|
+
* @throws CredentialNotFoundError if no entry with that id exists
|
|
82
|
+
*/
|
|
83
|
+
async getCredential(id) {
|
|
84
|
+
await this.init();
|
|
85
|
+
const reg = await this.readRegistry();
|
|
86
|
+
const entry = reg.credentials.find((c) => c.id === id);
|
|
87
|
+
if (!entry)
|
|
88
|
+
throw new CredentialNotFoundError(id);
|
|
89
|
+
return entry;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Find all credentials for a given provider, optionally filtered by type.
|
|
93
|
+
*/
|
|
94
|
+
async findCredentialsByProvider(provider, type) {
|
|
95
|
+
await this.init();
|
|
96
|
+
const reg = await this.readRegistry();
|
|
97
|
+
return reg.credentials.filter((c) => c.provider === provider && (!type || c.type === type));
|
|
98
|
+
}
|
|
99
|
+
// ------------------------------------------------------------------
|
|
100
|
+
// Add
|
|
101
|
+
// ------------------------------------------------------------------
|
|
102
|
+
/**
|
|
103
|
+
* Add a new API key credential. The value is encrypted on disk and
|
|
104
|
+
* never exposed back through the metadata API.
|
|
105
|
+
*/
|
|
106
|
+
async addApiKey(input) {
|
|
107
|
+
await this.init();
|
|
108
|
+
const id = this.newId();
|
|
109
|
+
const encFile = `${id}.enc`;
|
|
110
|
+
const payload = { type: 'api-key', value: input.value };
|
|
111
|
+
const now = new Date().toISOString();
|
|
112
|
+
const entry = {
|
|
113
|
+
id,
|
|
114
|
+
name: input.name,
|
|
115
|
+
type: 'api-key',
|
|
116
|
+
provider: input.provider,
|
|
117
|
+
createdAt: now,
|
|
118
|
+
updatedAt: now,
|
|
119
|
+
status: 'active',
|
|
120
|
+
encFile,
|
|
121
|
+
};
|
|
122
|
+
await this.writePayload(encFile, payload);
|
|
123
|
+
await this.appendEntry(entry);
|
|
124
|
+
return entry;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Add a new OAuth credential. Typically called by a helper's capture
|
|
128
|
+
* flow after completing an OAuth exchange.
|
|
129
|
+
*/
|
|
130
|
+
async addOAuth(input) {
|
|
131
|
+
await this.init();
|
|
132
|
+
const id = this.newId();
|
|
133
|
+
const encFile = `${id}.enc`;
|
|
134
|
+
const now = new Date().toISOString();
|
|
135
|
+
const entry = {
|
|
136
|
+
id,
|
|
137
|
+
name: input.name,
|
|
138
|
+
type: 'google-oauth',
|
|
139
|
+
provider: input.provider,
|
|
140
|
+
helper: input.helper,
|
|
141
|
+
scopes: input.payload.scopes,
|
|
142
|
+
accountEmail: input.payload.accountEmail,
|
|
143
|
+
expiresAt: input.payload.expiresAt,
|
|
144
|
+
createdAt: now,
|
|
145
|
+
updatedAt: now,
|
|
146
|
+
status: 'active',
|
|
147
|
+
encFile,
|
|
148
|
+
};
|
|
149
|
+
await this.writePayload(encFile, input.payload);
|
|
150
|
+
await this.appendEntry(entry);
|
|
151
|
+
return entry;
|
|
152
|
+
}
|
|
153
|
+
// ------------------------------------------------------------------
|
|
154
|
+
// Update
|
|
155
|
+
// ------------------------------------------------------------------
|
|
156
|
+
/**
|
|
157
|
+
* Update a credential's metadata. Does not touch the encrypted payload.
|
|
158
|
+
* Use `setPayload` to rewrite the secret material (e.g., after refresh).
|
|
159
|
+
*
|
|
160
|
+
* @throws CredentialNotFoundError if no entry with that id exists
|
|
161
|
+
*/
|
|
162
|
+
async updateCredential(id, patch) {
|
|
163
|
+
await this.init();
|
|
164
|
+
let updated;
|
|
165
|
+
await withOperationLock(this.registryPath, async () => {
|
|
166
|
+
const reg = await this.readRegistry();
|
|
167
|
+
const idx = reg.credentials.findIndex((c) => c.id === id);
|
|
168
|
+
if (idx < 0)
|
|
169
|
+
throw new CredentialNotFoundError(id);
|
|
170
|
+
updated = {
|
|
171
|
+
...reg.credentials[idx],
|
|
172
|
+
...patch,
|
|
173
|
+
updatedAt: new Date().toISOString(),
|
|
174
|
+
};
|
|
175
|
+
reg.credentials[idx] = updated;
|
|
176
|
+
await this.writeRegistry(reg);
|
|
177
|
+
});
|
|
178
|
+
return updated;
|
|
179
|
+
}
|
|
180
|
+
// ------------------------------------------------------------------
|
|
181
|
+
// Delete
|
|
182
|
+
// ------------------------------------------------------------------
|
|
183
|
+
/**
|
|
184
|
+
* Delete a credential (removes registry entry and encrypted payload).
|
|
185
|
+
* The registry removal is authoritative — if the `.enc` file is missing
|
|
186
|
+
* for any reason, that is not an error.
|
|
187
|
+
*
|
|
188
|
+
* @throws CredentialNotFoundError if no entry with that id exists
|
|
189
|
+
*/
|
|
190
|
+
async deleteCredential(id) {
|
|
191
|
+
await this.init();
|
|
192
|
+
let encFileToDelete = null;
|
|
193
|
+
await withOperationLock(this.registryPath, async () => {
|
|
194
|
+
const reg = await this.readRegistry();
|
|
195
|
+
const idx = reg.credentials.findIndex((c) => c.id === id);
|
|
196
|
+
if (idx < 0)
|
|
197
|
+
throw new CredentialNotFoundError(id);
|
|
198
|
+
encFileToDelete = reg.credentials[idx].encFile;
|
|
199
|
+
reg.credentials.splice(idx, 1);
|
|
200
|
+
await this.writeRegistry(reg);
|
|
201
|
+
});
|
|
202
|
+
if (encFileToDelete) {
|
|
203
|
+
try {
|
|
204
|
+
await fs.unlink(this.encFilePath(encFileToDelete));
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
// registry is source of truth — ignore missing .enc file
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// ------------------------------------------------------------------
|
|
212
|
+
// Payload API (INTERNAL — helpers + executor only)
|
|
213
|
+
// ------------------------------------------------------------------
|
|
214
|
+
/**
|
|
215
|
+
* Decrypt and return the credential's payload. **Do not return the
|
|
216
|
+
* result to agent / LLM contexts** — intended only for helpers
|
|
217
|
+
* refreshing tokens and the skill executor injecting env vars.
|
|
218
|
+
*
|
|
219
|
+
* @throws CredentialNotFoundError if no entry with that id exists
|
|
220
|
+
*/
|
|
221
|
+
async getPayload(id) {
|
|
222
|
+
await this.init();
|
|
223
|
+
const entry = await this.getCredential(id);
|
|
224
|
+
const b64 = await fs.readFile(this.encFilePath(entry.encFile), 'utf8');
|
|
225
|
+
const encBuffer = Buffer.from(b64, 'base64');
|
|
226
|
+
const plaintext = await decrypt(encBuffer, this.masterKeyPath);
|
|
227
|
+
return JSON.parse(plaintext);
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Encrypt and write a new payload for an existing credential. Used by
|
|
231
|
+
* helpers after a successful token refresh.
|
|
232
|
+
*
|
|
233
|
+
* @throws CredentialNotFoundError if no entry with that id exists
|
|
234
|
+
*/
|
|
235
|
+
async setPayload(id, payload) {
|
|
236
|
+
await this.init();
|
|
237
|
+
const entry = await this.getCredential(id);
|
|
238
|
+
await this.writePayload(entry.encFile, payload);
|
|
239
|
+
}
|
|
240
|
+
// ------------------------------------------------------------------
|
|
241
|
+
// Internals
|
|
242
|
+
// ------------------------------------------------------------------
|
|
243
|
+
async readRegistry() {
|
|
244
|
+
return safeReadJson(this.registryPath, {
|
|
245
|
+
...EMPTY_REGISTRY,
|
|
246
|
+
credentials: [],
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
async writeRegistry(reg) {
|
|
250
|
+
await atomicWriteJson(this.registryPath, reg);
|
|
251
|
+
}
|
|
252
|
+
async appendEntry(entry) {
|
|
253
|
+
await withOperationLock(this.registryPath, async () => {
|
|
254
|
+
const reg = await this.readRegistry();
|
|
255
|
+
reg.credentials.push(entry);
|
|
256
|
+
await this.writeRegistry(reg);
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
encFilePath(encFile) {
|
|
260
|
+
return path.join(this.dir, encFile);
|
|
261
|
+
}
|
|
262
|
+
async writePayload(encFile, payload) {
|
|
263
|
+
const json = JSON.stringify(payload);
|
|
264
|
+
const enc = await encrypt(json, this.masterKeyPath);
|
|
265
|
+
// Encrypted bytes are stored base64-encoded so they go through
|
|
266
|
+
// atomicWriteFile's utf8 serializer safely.
|
|
267
|
+
await atomicWriteFile(this.encFilePath(encFile), enc.toString('base64'));
|
|
268
|
+
}
|
|
269
|
+
newId() {
|
|
270
|
+
return `cred-${crypto.randomUUID()}`;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
// ============================================================================
|
|
274
|
+
// Singleton
|
|
275
|
+
// ============================================================================
|
|
276
|
+
let instance = null;
|
|
277
|
+
/**
|
|
278
|
+
* Get the process-wide CredentialStoreService singleton.
|
|
279
|
+
*/
|
|
280
|
+
export function getCredentialStoreService() {
|
|
281
|
+
if (!instance)
|
|
282
|
+
instance = new CredentialStoreService();
|
|
283
|
+
return instance;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Reset the singleton — for tests only.
|
|
287
|
+
*/
|
|
288
|
+
export function resetCredentialStoreService() {
|
|
289
|
+
instance = null;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Replace the singleton with a specific instance — for tests only.
|
|
293
|
+
* Allows route/controller tests to point the store at a scratch directory.
|
|
294
|
+
*/
|
|
295
|
+
export function _setCredentialStoreForTesting(svc) {
|
|
296
|
+
instance = svc;
|
|
297
|
+
}
|
|
298
|
+
//# sourceMappingURL=credential-store.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credential-store.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/credential/credential-store.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,117 @@
|
|
|
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
|
+
/**
|
|
23
|
+
* Minimal fetch-compatible function shape (for test injection).
|
|
24
|
+
*/
|
|
25
|
+
export type FetchLike = (url: string, init?: {
|
|
26
|
+
method?: string;
|
|
27
|
+
headers?: Record<string, string>;
|
|
28
|
+
body?: string;
|
|
29
|
+
}) => Promise<{
|
|
30
|
+
ok: boolean;
|
|
31
|
+
status: number;
|
|
32
|
+
text(): Promise<string>;
|
|
33
|
+
json(): Promise<unknown>;
|
|
34
|
+
}>;
|
|
35
|
+
/**
|
|
36
|
+
* Helper configuration — all fields optional; defaults match production.
|
|
37
|
+
*/
|
|
38
|
+
export interface GeminiCliHelperConfig {
|
|
39
|
+
/** Path to the extension install directory (default: `~/.gemini/extensions/google-workspace`). */
|
|
40
|
+
extensionPath?: string;
|
|
41
|
+
/** Cloud Function base URL. */
|
|
42
|
+
cloudFunctionUrl?: string;
|
|
43
|
+
/** Path on the cloud function for refresh calls. */
|
|
44
|
+
refreshPath?: string;
|
|
45
|
+
/** Client ID to store on the credential (for later refresh identification). */
|
|
46
|
+
clientId?: string;
|
|
47
|
+
/** Refresh buffer in ms — refresh if token expires within this window. */
|
|
48
|
+
expiryBufferMs?: number;
|
|
49
|
+
/** Fetch implementation (injectable for tests). */
|
|
50
|
+
fetch?: FetchLike;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Credential helper that reads tokens from the gemini-cli-workspace extension
|
|
54
|
+
* and refreshes them via the extension's Cloud Function.
|
|
55
|
+
*/
|
|
56
|
+
export declare class GeminiCliWorkspaceHelper implements CredentialHelper {
|
|
57
|
+
readonly name: CredentialHelperName;
|
|
58
|
+
private readonly extensionPath;
|
|
59
|
+
private readonly cloudFunctionUrl;
|
|
60
|
+
private readonly refreshPath;
|
|
61
|
+
private readonly clientId;
|
|
62
|
+
private readonly expiryBufferMs;
|
|
63
|
+
private readonly fetchFn;
|
|
64
|
+
private readonly store;
|
|
65
|
+
/** Per-credential refresh in-flight promises (serializes concurrent refreshes). */
|
|
66
|
+
private readonly refreshInFlight;
|
|
67
|
+
/** Per-credential last refresh attempt timestamp (for cooldown). */
|
|
68
|
+
private readonly lastRefreshAttempt;
|
|
69
|
+
constructor(store: CredentialStoreService, config?: GeminiCliHelperConfig);
|
|
70
|
+
/**
|
|
71
|
+
* Read the extension's current token file and return its contents as a
|
|
72
|
+
* `GoogleOAuthPayload` ready to persist in Crewly's store.
|
|
73
|
+
*
|
|
74
|
+
* The user must have completed extension login with
|
|
75
|
+
* `GEMINI_CLI_WORKSPACE_FORCE_FILE_STORAGE=true` before calling this.
|
|
76
|
+
*/
|
|
77
|
+
captureFromFile(): Promise<GoogleOAuthPayload>;
|
|
78
|
+
/**
|
|
79
|
+
* Remove the extension's token file. Call after `captureFromFile()` to
|
|
80
|
+
* prepare for the next account's login (the extension otherwise returns
|
|
81
|
+
* cached credentials if scopes match, skipping the login prompt).
|
|
82
|
+
* Leaves the master.key file untouched so existing ciphertexts remain
|
|
83
|
+
* decryptable if needed.
|
|
84
|
+
*/
|
|
85
|
+
clearExtensionFile(): Promise<void>;
|
|
86
|
+
/**
|
|
87
|
+
* Return a valid `GoogleOAuthPayload`, refreshing via the extension's
|
|
88
|
+
* cloud function if the access token is within the expiry buffer.
|
|
89
|
+
*
|
|
90
|
+
* Concurrent calls for the same credential share a single refresh.
|
|
91
|
+
*
|
|
92
|
+
* @throws CredentialRevokedError if the refresh token is no longer valid
|
|
93
|
+
*/
|
|
94
|
+
getAccessToken(entry: CredentialRegistryEntry, payload: GoogleOAuthPayload): Promise<GoogleOAuthPayload>;
|
|
95
|
+
private doRefresh;
|
|
96
|
+
/**
|
|
97
|
+
* Decrypt the extension's `{iv_hex}:{authTag_hex}:{ciphertext_hex}`
|
|
98
|
+
* format (AES-256-GCM).
|
|
99
|
+
*/
|
|
100
|
+
private decryptExtensionFormat;
|
|
101
|
+
/**
|
|
102
|
+
* Fetch the user's email via Google's userinfo endpoint. Best-effort;
|
|
103
|
+
* returns undefined on failure.
|
|
104
|
+
*/
|
|
105
|
+
private fetchUserEmail;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Encrypt a plaintext string with the extension's file format. Used in
|
|
109
|
+
* tests to generate fake token files.
|
|
110
|
+
*/
|
|
111
|
+
export declare function encryptExtensionFormatForTesting(plaintext: string, key: Buffer): string;
|
|
112
|
+
/**
|
|
113
|
+
* Derive the extension's encryption key using the real scrypt + salt.
|
|
114
|
+
* Test-only export.
|
|
115
|
+
*/
|
|
116
|
+
export declare function deriveExtensionKeyForTesting(masterKey: Buffer): Buffer;
|
|
117
|
+
//# 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;AAmDxE;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,CACtB,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,KACxE,OAAO,CAAC;IACX,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IACxB,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1B,CAAC,CAAC;AAEH;;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;IAoB9B;;;OAGG;YACW,cAAc;CAe7B;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"}
|