codeply-cli 0.5.2 → 0.5.3
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/lib/cloud.mjs +64 -0
- package/package.json +1 -1
package/lib/cloud.mjs
CHANGED
|
@@ -487,6 +487,67 @@ export async function ensureTrackKey({ api, repo, cwd, home = defaultHome(), fet
|
|
|
487
487
|
} catch { return false; }
|
|
488
488
|
}
|
|
489
489
|
|
|
490
|
+
/**
|
|
491
|
+
* Connected apps (Gmail, Slack, Vercel, Supabase, GitHub) for cloud runs. A run
|
|
492
|
+
* happens on GitHub's servers, which don't have the sign-ins saved on this PC,
|
|
493
|
+
* so Craft keeps an encrypted copy on Codeply's server for the signed-in user
|
|
494
|
+
* (the connections function) and the runner loads it at start with the usage
|
|
495
|
+
* key. Sent only when something changed. Off with "cloudConnections": false in
|
|
496
|
+
* ~/.codeply/config.json. Never fails a setup or a run.
|
|
497
|
+
*/
|
|
498
|
+
export const CONNECTION_APPS = ['gmail', 'slack', 'vercel', 'supabase', 'github'];
|
|
499
|
+
export async function syncCloudConnections({ home = defaultHome(), fetchImpl = fetch } = {}) {
|
|
500
|
+
try {
|
|
501
|
+
const config = require('./config.js');
|
|
502
|
+
if (config.getConfig().cloudConnections === false) return false;
|
|
503
|
+
const connections = {};
|
|
504
|
+
for (const name of CONNECTION_APPS) {
|
|
505
|
+
const c = config.getIntegration(name); // includes the app's OAuth client, which token refresh needs
|
|
506
|
+
if (c.accessToken) connections[name] = c;
|
|
507
|
+
}
|
|
508
|
+
const sig = crypto.createHash('sha256').update(JSON.stringify(connections)).digest('hex');
|
|
509
|
+
const state = readState(home);
|
|
510
|
+
if (state.connectionsSig === sig) return false;
|
|
511
|
+
const auth = require('./auth.js');
|
|
512
|
+
const token = await auth.getAccessToken().catch(() => null);
|
|
513
|
+
if (!token) return false;
|
|
514
|
+
const r = await fetchImpl(auth.SUPABASE_URL + '/functions/v1/connections', {
|
|
515
|
+
method: 'POST',
|
|
516
|
+
headers: { Authorization: 'Bearer ' + token, apikey: auth.SUPABASE_ANON_KEY, 'Content-Type': 'application/json' },
|
|
517
|
+
body: JSON.stringify({ action: 'save', connections }),
|
|
518
|
+
signal: AbortSignal.timeout(15_000),
|
|
519
|
+
});
|
|
520
|
+
if (!r.ok) return false;
|
|
521
|
+
writeState(home, { ...readState(home), connectionsSig: sig });
|
|
522
|
+
return true;
|
|
523
|
+
} catch { return false; }
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/** In the runner: put the user's connected apps into this machine's config, so the agent's tools can use them. */
|
|
527
|
+
export async function loadCloudConnections({ env = process.env, fetchImpl = fetch, log = () => {} } = {}) {
|
|
528
|
+
const key = String(env.CODEPLY_TRACK_KEY || '').trim();
|
|
529
|
+
if (!key) return [];
|
|
530
|
+
try {
|
|
531
|
+
const auth = require('./auth.js');
|
|
532
|
+
const r = await fetchImpl(auth.SUPABASE_URL + '/functions/v1/connections', {
|
|
533
|
+
method: 'POST',
|
|
534
|
+
headers: { 'x-codeply-track-key': key, apikey: auth.SUPABASE_ANON_KEY, 'Content-Type': 'application/json' },
|
|
535
|
+
body: JSON.stringify({ action: 'get' }),
|
|
536
|
+
signal: AbortSignal.timeout(15_000),
|
|
537
|
+
});
|
|
538
|
+
const j = await r.json().catch(() => ({}));
|
|
539
|
+
if (!r.ok || !j.connections) return [];
|
|
540
|
+
const config = require('./config.js');
|
|
541
|
+
const loaded = [];
|
|
542
|
+
for (const name of CONNECTION_APPS) {
|
|
543
|
+
const c = j.connections[name];
|
|
544
|
+
if (c && c.accessToken) { config.saveIntegration(name, c); loaded.push(name); }
|
|
545
|
+
}
|
|
546
|
+
if (loaded.length) log('Connected apps: ' + loaded.join(', '));
|
|
547
|
+
return loaded;
|
|
548
|
+
} catch (e) { log('Could not load connected apps: ' + e.message); return []; }
|
|
549
|
+
}
|
|
550
|
+
|
|
490
551
|
// Bumped when CLOUD_WORKFLOW changes, so repos set up earlier get the new file once.
|
|
491
552
|
export const WORKFLOW_REV = 2;
|
|
492
553
|
|
|
@@ -519,6 +580,7 @@ export async function setupCloud({ cwd, token, model, target, envText, home = de
|
|
|
519
580
|
if (envText != null) await setProjectEnv({ api, repo, envText });
|
|
520
581
|
updateProject(cwd, home, (p) => ({ ...p, modelSig: cfg.sig, modelName: model.name || model.model, enabled: true, workflowRev: WORKFLOW_REV }));
|
|
521
582
|
await ensureTrackKey({ api, repo, cwd, home, fetchImpl });
|
|
583
|
+
await syncCloudConnections({ home, fetchImpl });
|
|
522
584
|
return { repo, created, kind, base, url: `${(serverUrl || 'https://github.com').replace(/\/$/, '')}/${repo}`, skipped };
|
|
523
585
|
}
|
|
524
586
|
|
|
@@ -582,6 +644,7 @@ export async function startCloudRun({ cwd, token, prompt, mode = 'Build', sessio
|
|
|
582
644
|
updateProject(cwd, home, (q) => ({ ...q, workflowRev: WORKFLOW_REV }));
|
|
583
645
|
}
|
|
584
646
|
await ensureTrackKey({ api, repo: p.repo, cwd, home, fetchImpl });
|
|
647
|
+
await syncCloudConnections({ home, fetchImpl });
|
|
585
648
|
let baseSha;
|
|
586
649
|
if (p.kind === 'repo') {
|
|
587
650
|
const ref = await api('GET', `/repos/${p.repo}/git/ref/heads/${encodeURIComponent(base)}`, null, { allow: [404] });
|
|
@@ -986,6 +1049,7 @@ export async function runCloudRunner({ env = process.env, cwd = process.cwd(), t
|
|
|
986
1049
|
const base = env.CRAFT_BASE || env.GITHUB_REF_NAME || 'main';
|
|
987
1050
|
const merge = String(env.CRAFT_MERGE || 'true') !== 'false';
|
|
988
1051
|
await files.ensure(headSha).catch((e) => log(`Could not create ${SESSIONS_BRANCH}: ${e.message}`));
|
|
1052
|
+
await loadCloudConnections({ env, log });
|
|
989
1053
|
|
|
990
1054
|
// The project's environment for running and testing: never committed.
|
|
991
1055
|
const envFile = path.join(cwd, '.env');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeply-cli",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
4
4
|
"description": "Codeply from the terminal: an interactive AI coding agent, a local server (codeply serve), and a GitHub agent that runs in your own Actions runner.",
|
|
5
5
|
"main": "bin/codeply.js",
|
|
6
6
|
"bin": {
|