teamclaude-cloud 1.5.0 → 1.5.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/package.json +1 -1
- package/src/index.js +24 -0
- package/src/tui.js +22 -3
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -309,6 +309,30 @@ async function serverCommand() {
|
|
|
309
309
|
if (disabled) set.add(uuid); else set.delete(uuid);
|
|
310
310
|
cloud.localDisabled = [...set];
|
|
311
311
|
}),
|
|
312
|
+
// `p` in the dashboard = `teamclaude cloud push`, so the admin can register the
|
|
313
|
+
// server's live account tokens to the cloud without dropping to a shell. Only
|
|
314
|
+
// wired when a cloud config exists (else the footer hides the key). Uses the
|
|
315
|
+
// running AccountManager's LIVE tokens (freshest) and re-reads the cloud session
|
|
316
|
+
// from disk so a `cloud login` done after the server started is picked up.
|
|
317
|
+
cloudPush: config.cloud ? (async () => {
|
|
318
|
+
const fresh = (await loadConfig()) || config;
|
|
319
|
+
const cloud = await ensureCloudSession(fresh);
|
|
320
|
+
if (!cloud?.session?.access_token) throw new Error('Not logged in to cloud — run `teamclaude cloud login`');
|
|
321
|
+
const accounts = (config.accounts || []).filter(a => a.type !== 'apikey').map(a => {
|
|
322
|
+
const am = (a.accountUuid && accountManager.accounts.find(x => x.accountUuid === a.accountUuid))
|
|
323
|
+
|| accountManager.accounts.find(x => x.name === a.name);
|
|
324
|
+
return am ? { ...a, accessToken: am.credential, refreshToken: am.refreshToken, expiresAt: am.expiresAt } : a;
|
|
325
|
+
});
|
|
326
|
+
if (!accounts.length) throw new Error('No OAuth accounts to push');
|
|
327
|
+
const usageByUuid = new Map();
|
|
328
|
+
const quotaCache = await readQuotaCache();
|
|
329
|
+
for (const entry of quotaCache?.accounts || []) {
|
|
330
|
+
if (!entry?.accountUuid) continue;
|
|
331
|
+
const usage = buildUsageFromQuota(entry);
|
|
332
|
+
if (usage) usageByUuid.set(entry.accountUuid, usage);
|
|
333
|
+
}
|
|
334
|
+
return await cloudPush(cloud, accounts, usageByUuid);
|
|
335
|
+
}) : undefined,
|
|
312
336
|
});
|
|
313
337
|
hooks = {
|
|
314
338
|
onRequestStart: (id, info) => tui.onRequestStart(id, info),
|
package/src/tui.js
CHANGED
|
@@ -114,7 +114,7 @@ function timestamp() {
|
|
|
114
114
|
// ── TUI class ────────────────────────────────────────────────
|
|
115
115
|
|
|
116
116
|
export class TUI {
|
|
117
|
-
constructor({ accountManager, config, saveConfig, syncAccounts, refreshQuota, onQuit, setLocalDisabled }) {
|
|
117
|
+
constructor({ accountManager, config, saveConfig, syncAccounts, refreshQuota, onQuit, setLocalDisabled, cloudPush }) {
|
|
118
118
|
this.am = accountManager;
|
|
119
119
|
this.config = config;
|
|
120
120
|
this.saveConfig = saveConfig;
|
|
@@ -122,6 +122,7 @@ export class TUI {
|
|
|
122
122
|
this.refreshQuota = refreshQuota; // optional: forced fleet quota re-measure (R)
|
|
123
123
|
this.onQuit = onQuit;
|
|
124
124
|
this.setLocalDisabled = setLocalDisabled; // optional: persist offline local-disable overlay (by uuid) to disk (fresh-read merge)
|
|
125
|
+
this.cloudPush = cloudPush; // optional: push account tokens to the cloud (`p`) — returns {pushed,updated,skipped,usage}
|
|
125
126
|
|
|
126
127
|
this.log = []; // completed activity entries
|
|
127
128
|
this.active = new Map(); // in-flight requests
|
|
@@ -263,6 +264,7 @@ export class TUI {
|
|
|
263
264
|
if (k === 'q') { this.stop(); this.onQuit?.(); return; }
|
|
264
265
|
if (k === 'a') { this.mode = 'add'; return; }
|
|
265
266
|
if (k === 'R') { this._doSync(); return; }
|
|
267
|
+
if (k === 'p') { this._doPush(); return; }
|
|
266
268
|
|
|
267
269
|
if (this.am.accounts.length === 0) return;
|
|
268
270
|
|
|
@@ -390,6 +392,20 @@ export class TUI {
|
|
|
390
392
|
}
|
|
391
393
|
}
|
|
392
394
|
|
|
395
|
+
// `p` — push this machine's account tokens (+ usage snapshot) to the cloud, the
|
|
396
|
+
// same as `teamclaude push` / `teamclaude cloud push`, without leaving the dashboard.
|
|
397
|
+
async _doPush() {
|
|
398
|
+
if (!this.cloudPush) { this._addLog('Cloud push unavailable (no cloud config)'); return; }
|
|
399
|
+
try {
|
|
400
|
+
this._addLog('Pushing account tokens to the cloud...');
|
|
401
|
+
const r = await this.cloudPush();
|
|
402
|
+
const usageNote = (r && r.usage != null) ? `, usage ${r.usage}` : '';
|
|
403
|
+
this._addLog(`Cloud push: ${r?.pushed ?? 0} new, ${r?.updated ?? 0} updated, ${r?.skipped ?? 0} skipped${usageNote}`);
|
|
404
|
+
} catch (e) {
|
|
405
|
+
this._addLog(`Cloud push failed: ${e.message}`);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
393
409
|
async _doImport() {
|
|
394
410
|
try {
|
|
395
411
|
this._addLog('Importing credentials...');
|
|
@@ -835,8 +851,11 @@ export class TUI {
|
|
|
835
851
|
|
|
836
852
|
_renderFooter() {
|
|
837
853
|
switch (this.mode) {
|
|
838
|
-
case 'normal':
|
|
839
|
-
|
|
854
|
+
case 'normal': {
|
|
855
|
+
// `p`ush is only shown when a cloud config is present (the callback is wired).
|
|
856
|
+
const push = this.cloudPush ? ` ${bold('p')}ush` : '';
|
|
857
|
+
return ` ${dim('↑↓')} select ${bold('s')}witch ${bold('e')}nable/disable ${bold('o')}rder ${bold('d')}elete ${bold('a')}dd${push} ${bold('R')}eload ${bold('q')}uit`;
|
|
858
|
+
}
|
|
840
859
|
case 'select':
|
|
841
860
|
return ` ${dim('↑↓')} select ${bold('Enter')} delete ${bold('Esc')} cancel`;
|
|
842
861
|
case 'order':
|