shakers-cli 0.15.0 → 0.16.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/README.md +51 -1203
- package/bin/ai-usage.js +11 -56
- package/bin/login.js +10 -10
- package/bin/mcp.js +13 -9
- package/bin/mcpb.js +1 -1
- package/bin/onboarding.js +3 -2
- package/bin/register.js +17 -4
- package/bin/report-html.js +2 -2
- package/bin/shakers-cli.js +352 -0
- package/bin/shakers.js +20 -344
- package/bin/share.js +1 -1
- package/bin/superadmin.js +5 -5
- package/bin/version.js +3 -0
- package/package.json +12 -3
- package/src/agent-category.js +1 -1
- package/src/agent-evaluation.js +3 -3
- package/src/agent-org-chart.js +5 -5
- package/src/agent-synthesis.js +3 -3
- package/src/agent-usage.js +1 -1
- package/src/agents-client.js +4 -4
- package/src/ai.js +1 -1
- package/src/ansi.js +1 -1
- package/src/auth-client.js +18 -4
- package/src/auth-method-picker.js +1 -1
- package/src/auth-methods.js +1 -1
- package/src/auth-session-store.js +11 -8
- package/src/authorship-mismatch.js +1 -1
- package/src/authorship.js +2 -2
- package/src/automations-detector.js +1 -1
- package/src/backend-request.js +3 -3
- package/src/brand-ansi.js +1 -1
- package/src/browser-tools-detector.js +1 -1
- package/src/certify-disclaimer.js +1 -1
- package/src/certify-remediation-prompt.js +1 -1
- package/src/cli-args.js +2 -2
- package/src/command-audit.js +8 -5
- package/src/config-dir.js +1 -1
- package/src/config.js +112 -48
- package/src/consent-flow.js +4 -4
- package/src/consent-skip.js +1 -1
- package/src/detection-evidence.js +2 -2
- package/src/detection-noise.js +1 -1
- package/src/detectors.js +1 -1
- package/src/device-login.js +12 -1
- package/src/email-verification.js +3 -3
- package/src/env-paths.js +1 -1
- package/src/find-projects-client.js +12 -0
- package/src/find-projects-flow.js +1 -13
- package/src/git-activity.js +1 -1
- package/src/graph-certs.js +3 -3
- package/src/graph-scan.js +9 -9
- package/src/i18n.js +124 -124
- package/src/interactive-select.js +1 -1
- package/src/interview-client.js +6 -1
- package/src/interview-transcript.js +1 -1
- package/src/legal-notice.js +1 -1
- package/src/maturity.js +6 -6
- package/src/mcp-ai-usage-tool.js +1 -1
- package/src/mcp-auth-form.js +1 -1
- package/src/mcp-detector.js +3 -3
- package/src/mcp-device-login-tools.js +2 -1
- package/src/mcp-find-projects-tools.js +1 -2
- package/src/mcp-onboarding-tools.js +4 -4
- package/src/mcp-prompts.js +2 -2
- package/src/mcp-register-tools.js +1 -0
- package/src/mcp-server.js +5 -1
- package/src/mcp-signup-client.js +2 -2
- package/src/mcp-signup-tools.js +26 -2
- package/src/memory-structure-detector.js +1 -1
- package/src/model-call-record.js +2 -2
- package/src/onboarding-flow.js +16 -16
- package/src/onboarding-funnel.js +110 -17
- package/src/open-file.js +1 -1
- package/src/osc-link.js +1 -1
- package/src/portfolio-client.js +11 -1
- package/src/portfolio-git-info.js +1 -1
- package/src/profile-flow.js +1 -1
- package/src/profile-switch.js +5 -12
- package/src/render-certification.js +10 -10
- package/src/render-html.js +6 -6
- package/src/render-sheet.js +10 -10
- package/src/render-terminal.js +6 -6
- package/src/repo-scope.js +132 -0
- package/src/report-gating.js +1 -1
- package/src/report-store.js +6 -6
- package/src/roadmap-content.js +5 -5
- package/src/roadmap-personalization.js +3 -3
- package/src/roadmap-prompt.js +2 -2
- package/src/scan-exclusions.js +1 -1
- package/src/scanner.js +14 -14
- package/src/secret-prompt.js +1 -1
- package/src/session-gate.js +1 -1
- package/src/session-refresh.js +33 -3
- package/src/session-scan.js +1 -1
- package/src/shakers-wordmark.js +1 -1
- package/src/share-card.js +2 -2
- package/src/share-certification.js +4 -4
- package/src/share-consent-state.js +7 -7
- package/src/share-payload.js +7 -7
- package/src/share.js +7 -7
- package/src/signup-client.js +1 -1
- package/src/signup-copy.js +1 -1
- package/src/skills-client.js +1 -1
- package/src/start-add-agents.js +2 -2
- package/src/start-add-portfolio.js +3 -13
- package/src/start-add-skills.js +2 -2
- package/src/stdin-ask.js +3 -3
- package/src/strip-internal-comments.js +1 -1
- package/src/tech-detector.js +2 -2
- package/src/templates/report-sheet.html +11 -13
- package/src/terminal-agents.js +8 -8
- package/src/terminal-format.js +3 -3
- package/src/terminal-sections.js +11 -11
- package/src/tier-engine.js +3 -3
- package/src/tier-projection.js +2 -2
- package/src/transcript-turns.js +1 -1
- package/src/typewriter.js +1 -1
- package/src/usage-model-calls.js +6 -6
- package/src/usage-oneshot-commands.js +5 -5
- package/src/usage-repo-scope.js +11 -129
- package/src/usage-run-steps.js +32 -184
- package/src/usage-scan.js +235 -0
- package/src/work-streams.js +1 -1
package/src/auth-client.js
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
const { postJsonWithTimeout, extractSetCookie } = require('./backend-request');
|
|
4
4
|
|
|
5
|
-
// Login / token acquisition against the Hub's better-auth email engine
|
|
5
|
+
// Login / token acquisition against the Hub's better-auth email engine.
|
|
6
6
|
|
|
7
7
|
const DEFAULT_TIMEOUT_MS = 20000;
|
|
8
|
+
const SIGN_OUT_TIMEOUT_MS = 3000;
|
|
8
9
|
const SESSION_COOKIE_NAME = 'better-auth.session_token';
|
|
9
10
|
// Refresh the cookie session's own validity from the Set-Cookie Max-Age; fall
|
|
10
11
|
// back to 7 days (better-auth's default) when the attribute is absent.
|
|
@@ -88,12 +89,13 @@ function normalizeSignIn(status, raw, headers) {
|
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
// Mints a hub JWT from a better-auth session cookie: `GET {tokenEndpoint}` with the `Cookie` header.
|
|
91
|
-
async function requestAuthToken({ cookie } = {}, { endpoint, timeoutMs = DEFAULT_TIMEOUT_MS } = {}) {
|
|
92
|
+
async function requestAuthToken({ cookie, sessionToken } = {}, { endpoint, timeoutMs = DEFAULT_TIMEOUT_MS } = {}) {
|
|
92
93
|
if (!endpoint) return { ok: false, reason: 'no-endpoint' };
|
|
93
|
-
if (!cookie) return { ok: false, reason: 'no-cookie' };
|
|
94
|
+
if (!cookie && !sessionToken) return { ok: false, reason: 'no-cookie' };
|
|
95
|
+
const credential = cookie ? { Cookie: cookie } : { Authorization: `Bearer ${sessionToken}` };
|
|
94
96
|
let res;
|
|
95
97
|
try {
|
|
96
|
-
res = await postJsonWithTimeout(endpoint, null, timeoutMs, 'GET', null,
|
|
98
|
+
res = await postJsonWithTimeout(endpoint, null, timeoutMs, 'GET', null, credential);
|
|
97
99
|
} catch (e) {
|
|
98
100
|
return { ok: false, reason: (e && e.kind) || 'network-error' };
|
|
99
101
|
}
|
|
@@ -133,7 +135,19 @@ async function requestLogin(
|
|
|
133
135
|
};
|
|
134
136
|
}
|
|
135
137
|
|
|
138
|
+
async function requestSignOut({ cookie, sessionToken } = {}, { endpoint, origin = null, timeoutMs = SIGN_OUT_TIMEOUT_MS } = {}) {
|
|
139
|
+
if (!endpoint || (!cookie && !sessionToken)) return { ok: false, reason: 'no-credential' };
|
|
140
|
+
const credential = cookie ? { Cookie: cookie, ...(origin ? { Origin: origin } : {}) } : { Authorization: `Bearer ${sessionToken}` };
|
|
141
|
+
try {
|
|
142
|
+
const res = await postJsonWithTimeout(endpoint, {}, timeoutMs, 'POST', null, credential);
|
|
143
|
+
return { ok: res.status >= 200 && res.status < 300, status: res.status };
|
|
144
|
+
} catch (e) {
|
|
145
|
+
return { ok: false, reason: (e && e.kind) || 'network-error' };
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
136
149
|
module.exports = {
|
|
150
|
+
requestSignOut,
|
|
137
151
|
requestLogin,
|
|
138
152
|
requestAuthToken,
|
|
139
153
|
normalizeSignIn,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const { runInteractiveMultiSelect } = require('./interactive-select');
|
|
4
4
|
const { methodsForFlow, methodLabel } = require('./auth-methods');
|
|
5
5
|
|
|
6
|
-
// The shared interactive method picker for the CLI
|
|
6
|
+
// The shared interactive method picker for the CLI.
|
|
7
7
|
async function askNumberedChoice(ask, promptText, count) {
|
|
8
8
|
const raw = (await ask(promptText)).trim();
|
|
9
9
|
if (!raw) return null;
|
package/src/auth-methods.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
// The SINGLE source of truth for which auth methods exist and where each one is offered
|
|
3
|
+
// The SINGLE source of truth for which auth methods exist and where each one is offered.
|
|
4
4
|
const AUTH_METHODS = [
|
|
5
5
|
{ id: 'email', labelKey: 'methodEmail', availableFor: { login: true, register: true } },
|
|
6
6
|
{ id: 'google', labelKey: 'methodGoogle', availableFor: { login: true, register: true } },
|
|
@@ -5,7 +5,7 @@ const fs = require('fs');
|
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const { getConfigDir } = require('./config-dir');
|
|
7
7
|
|
|
8
|
-
// `~/.config/shakers/auth-session.json` — the logged-in Talent's session
|
|
8
|
+
// `~/.config/shakers/auth-session.json` — the logged-in Talent's session.
|
|
9
9
|
|
|
10
10
|
// Hub's `UserSubtypeEnum` (shared/domain/enum/user-subtype.enum.ts), copied VERBATIM — this repo never invents a value the wire does not send.
|
|
11
11
|
const PLATFORM_TALENT_USER_TYPES = new Set(['WORKS_TALENT', 'WORKS_PARTNER']);
|
|
@@ -89,12 +89,12 @@ function saveAuthSession(session, env = process.env, { fs: fsImpl = fs } = {}) {
|
|
|
89
89
|
const hubAccessToken = explicitHubToken || (typeof session.accessToken === 'string' && session.accessToken ? session.accessToken : null);
|
|
90
90
|
|
|
91
91
|
const cookie = typeof session.cookie === 'string' && session.cookie ? session.cookie : null;
|
|
92
|
+
const sessionToken = typeof session.sessionToken === 'string' && session.sessionToken ? session.sessionToken : null;
|
|
92
93
|
let expiresAt;
|
|
93
94
|
let accessTokenExpiresAt;
|
|
94
|
-
if (cookie) {
|
|
95
|
-
expiresAt =
|
|
96
|
-
|
|
97
|
-
: (typeof session.expiresAt === 'string' && session.expiresAt ? session.expiresAt : null);
|
|
95
|
+
if (cookie || sessionToken) {
|
|
96
|
+
expiresAt = [session.cookieExpiresAt, session.sessionExpiresAt, session.expiresAt]
|
|
97
|
+
.find((v) => typeof v === 'string' && v) || expiresAtFromToken(session.accessToken);
|
|
98
98
|
accessTokenExpiresAt = (typeof session.accessTokenExpiresAt === 'string' && session.accessTokenExpiresAt)
|
|
99
99
|
? session.accessTokenExpiresAt
|
|
100
100
|
: expiresAtFromToken(session.accessToken);
|
|
@@ -109,6 +109,7 @@ function saveAuthSession(session, env = process.env, { fs: fsImpl = fs } = {}) {
|
|
|
109
109
|
expiresAt: expiresAt ?? null,
|
|
110
110
|
accessTokenExpiresAt: accessTokenExpiresAt ?? null,
|
|
111
111
|
cookie,
|
|
112
|
+
sessionToken,
|
|
112
113
|
email: (typeof session.email === 'string' && session.email ? session.email : null)
|
|
113
114
|
|| emailFromHubToken(hubAccessToken),
|
|
114
115
|
hubAccessToken,
|
|
@@ -157,7 +158,8 @@ function loadAuthSession(env = process.env, { fs: fsImpl = fs } = {}) {
|
|
|
157
158
|
// better-auth) or a JWT (Google/legacy, or an email session whose JWT is cached).
|
|
158
159
|
const hasCookie = typeof parsed.cookie === 'string' && parsed.cookie;
|
|
159
160
|
const hasToken = typeof parsed.accessToken === 'string' && parsed.accessToken;
|
|
160
|
-
|
|
161
|
+
const sessionToken = typeof parsed.sessionToken === 'string' && parsed.sessionToken ? parsed.sessionToken : null;
|
|
162
|
+
if (!hasCookie && !hasToken && !sessionToken) return null;
|
|
161
163
|
const hubAccessToken = typeof parsed.hubAccessToken === 'string' && parsed.hubAccessToken ? parsed.hubAccessToken : null;
|
|
162
164
|
const email = (typeof parsed.email === 'string' && parsed.email ? parsed.email : null) || emailFromHubToken(hubAccessToken);
|
|
163
165
|
return {
|
|
@@ -165,6 +167,7 @@ function loadAuthSession(env = process.env, { fs: fsImpl = fs } = {}) {
|
|
|
165
167
|
expiresAt: typeof parsed.expiresAt === 'string' ? parsed.expiresAt : null,
|
|
166
168
|
accessTokenExpiresAt: typeof parsed.accessTokenExpiresAt === 'string' ? parsed.accessTokenExpiresAt : null,
|
|
167
169
|
cookie: hasCookie ? parsed.cookie : null,
|
|
170
|
+
sessionToken,
|
|
168
171
|
email,
|
|
169
172
|
hubAccessToken,
|
|
170
173
|
userType: typeof parsed.userType === 'string' && KNOWN_USER_TYPES.has(parsed.userType) ? parsed.userType : null,
|
|
@@ -184,8 +187,8 @@ function clearAuthSession(env = process.env, { fs: fsImpl = fs } = {}) {
|
|
|
184
187
|
|
|
185
188
|
// `none | active | expired`, the three states the caller needs to give the Talent a true message.
|
|
186
189
|
function sessionStatus(session, now = Date.now()) {
|
|
187
|
-
// A credential is
|
|
188
|
-
const hasCred = !!(session &&
|
|
190
|
+
// A credential is a durable cookie or session token, or a JWT (Google/legacy).
|
|
191
|
+
const hasCred = !!(session && [session.accessToken, session.cookie, session.sessionToken].some((v) => typeof v === 'string' && v));
|
|
189
192
|
if (!hasCred) return 'none';
|
|
190
193
|
const expiry = Date.parse(String(session.expiresAt || ''));
|
|
191
194
|
if (!Number.isFinite(expiry)) return 'expired';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
// Display-only authorship-transparency check
|
|
3
|
+
// Display-only authorship-transparency check.
|
|
4
4
|
//
|
|
5
5
|
// Warns the talent when their commits in the selected repos are authored under
|
|
6
6
|
// an email that is not their Shakers account email, so their own work would be
|
package/src/authorship.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const { execFileSync } = require('child_process');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
|
|
6
|
-
// Git AUTHORSHIP + provenance for the certify phase
|
|
6
|
+
// Git AUTHORSHIP + provenance for the certify phase.
|
|
7
7
|
|
|
8
8
|
const { takePrefetchedGitLog } = require('./git-log-prefetch');
|
|
9
9
|
|
|
@@ -164,7 +164,7 @@ function buildAttributionPredicate(verifiedEmail, authorizedSet) {
|
|
|
164
164
|
};
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
-
// Applies the
|
|
167
|
+
// Applies the authorship gate (widened for test identities) to ONE sampled Skill.
|
|
168
168
|
function attributeSample(sample, verifiedEmail, authorship, authorizedSet = null) {
|
|
169
169
|
const isAttributable = buildAttributionPredicate(verifiedEmail, authorizedSet);
|
|
170
170
|
const files = Array.isArray(sample.files) ? sample.files : [];
|
|
@@ -5,7 +5,7 @@ const path = require('path');
|
|
|
5
5
|
const { execFileSync } = require('child_process');
|
|
6
6
|
const { getHomeDir } = require('./env-paths');
|
|
7
7
|
|
|
8
|
-
// Deterministic (no-LLM) automations detector
|
|
8
|
+
// Deterministic (no-LLM) automations detector.
|
|
9
9
|
|
|
10
10
|
const AI_CLI_NAMES = ['claude', 'aider', 'gemini', 'codex'];
|
|
11
11
|
const AI_CLI_RE = new RegExp(`\\b(${AI_CLI_NAMES.join('|')})\\b`, 'i');
|
package/src/backend-request.js
CHANGED
|
@@ -5,7 +5,7 @@ const https = require('https');
|
|
|
5
5
|
const crypto = require('crypto');
|
|
6
6
|
const { getHubBase } = require('./config');
|
|
7
7
|
|
|
8
|
-
// ONE BACKEND: the certifications service
|
|
8
|
+
// ONE BACKEND: the certifications service.
|
|
9
9
|
|
|
10
10
|
const MAX_RESPONSE_BYTES = 8 * 1024 * 1024;
|
|
11
11
|
|
|
@@ -31,7 +31,7 @@ function profileUpdateSourceHeader(url, method) {
|
|
|
31
31
|
return { 'X-Profile-Update-Source': clientIdentity };
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
// Extra request headers, sanitized (
|
|
34
|
+
// Extra request headers, sanitized (the agent certification interview needs `Authorization: Bearer <sessionToken>`).
|
|
35
35
|
const UNSAFE_HEADER_VALUE_RE = /[\r\n\0]/;
|
|
36
36
|
|
|
37
37
|
function sanitizeExtraHeaders(extraHeaders) {
|
|
@@ -183,7 +183,7 @@ async function requestBackend({
|
|
|
183
183
|
throw Object.assign(new Error('no endpoint configured'), { kind: 'no-endpoint' });
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
-
// Optional trace
|
|
186
|
+
// Optional trace.
|
|
187
187
|
const note = (entry) => {
|
|
188
188
|
if (Array.isArray(trace)) trace.push(entry);
|
|
189
189
|
};
|
package/src/brand-ansi.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
// BRAND_ANSI — the Shakers brand palette, reincarnated as ANSI 256-colour SGR codes
|
|
3
|
+
// BRAND_ANSI — the Shakers brand palette, reincarnated as ANSI 256-colour SGR codes.
|
|
4
4
|
|
|
5
5
|
const BRAND_ANSI = {
|
|
6
6
|
primary: '\x1b[38;5;73m',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
// Deterministic (no-LLM) browser tools detector
|
|
3
|
+
// Deterministic (no-LLM) browser tools detector.
|
|
4
4
|
|
|
5
5
|
const BROWSER_DEPENDENCY_NAMES = new Set(['playwright', '@playwright/test', 'puppeteer', 'puppeteer-core']);
|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
// Legal disclaimer + EXPLICIT acceptance gate
|
|
3
|
+
// Legal disclaimer + EXPLICIT acceptance gate, shown before egress. Skill-code certify was retired (certify is now a dimension LiveKit interview); consumers today are the add-skill/add-agent/add-project consent gates.
|
|
4
4
|
|
|
5
5
|
const { renderLegalNotice } = require('./legal-notice');
|
|
6
6
|
const { styleQuestion } = require('./ansi');
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { getCatalog } = require('./i18n');
|
|
4
4
|
|
|
5
|
-
// Client-side "remediation prompt" for the certify report
|
|
5
|
+
// Client-side "remediation prompt" for the certify report.
|
|
6
6
|
function buildRemediationPrompt(item, lang) {
|
|
7
7
|
const r = getCatalog(lang).certify.report;
|
|
8
8
|
const improvements =
|
package/src/cli-args.js
CHANGED
|
@@ -39,7 +39,7 @@ function parseArgs(argv) {
|
|
|
39
39
|
repo: false,
|
|
40
40
|
scope: null,
|
|
41
41
|
noAi: false,
|
|
42
|
-
//
|
|
42
|
+
// Turns the section reveal off. Same name in both parsers, and the
|
|
43
43
|
// env var `NO_ANIMATION` does the same thing (the `NO_COLOR` pattern of 079).
|
|
44
44
|
noAnimation: false,
|
|
45
45
|
};
|
|
@@ -59,7 +59,7 @@ function parseArgs(argv) {
|
|
|
59
59
|
else if (a === '--show-endpoint') opts.showEndpoint = true;
|
|
60
60
|
else if (a === '--build-next-level') opts.buildNextLevel = true;
|
|
61
61
|
else if (a === '--force') opts.force = true;
|
|
62
|
-
//
|
|
62
|
+
// The tier roadmap / "next steps" block is removed from the
|
|
63
63
|
// default footprint output; `--roadmap` (alias `--next`) shows it again.
|
|
64
64
|
else if (a === '--roadmap' || a === '--next') opts.roadmap = true;
|
|
65
65
|
else if (a === '--lang') opts.lang = VALID_LANGS.has(argv[++i]) ? argv[i] : null;
|
package/src/command-audit.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const os = require('os');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const { scrubSecrets } = require('./agent-synthesis');
|
|
6
|
-
const { loadAuthSession } = require('./auth-session-store');
|
|
6
|
+
const { loadAuthSession, decodeJwtPayload } = require('./auth-session-store');
|
|
7
7
|
const { getCertsBase } = require('./config');
|
|
8
8
|
const { postJsonWithTimeout } = require('./backend-request');
|
|
9
9
|
|
|
@@ -46,6 +46,11 @@ function machineHint() {
|
|
|
46
46
|
return { osUser, hostname };
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
function jwtExpired(token, now) {
|
|
50
|
+
const payload = decodeJwtPayload(token);
|
|
51
|
+
return !!payload && typeof payload.exp === 'number' && payload.exp * 1000 <= now;
|
|
52
|
+
}
|
|
53
|
+
|
|
49
54
|
// Builds the record + headers; returns null when there is no endpoint to post to.
|
|
50
55
|
function buildAudit(command, argv, env) {
|
|
51
56
|
let base;
|
|
@@ -57,10 +62,8 @@ function buildAudit(command, argv, env) {
|
|
|
57
62
|
if (!base) return null;
|
|
58
63
|
|
|
59
64
|
const session = loadAuthSession(env);
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
? session.accessToken || session.hubAccessToken
|
|
63
|
-
: null;
|
|
65
|
+
const stored = (session && (session.accessToken || session.hubAccessToken)) || null;
|
|
66
|
+
const token = stored && !jwtExpired(stored, Date.now()) ? stored : null;
|
|
64
67
|
|
|
65
68
|
const body = {
|
|
66
69
|
command: String(command || 'unknown').slice(0, 100),
|
package/src/config-dir.js
CHANGED
|
@@ -4,7 +4,7 @@ const path = require('path');
|
|
|
4
4
|
const fs = require('fs');
|
|
5
5
|
const { getHomeDir, readEnv } = require('./env-paths');
|
|
6
6
|
|
|
7
|
-
// Single source of truth for the CLI's config directory
|
|
7
|
+
// Single source of truth for the CLI's config directory.
|
|
8
8
|
|
|
9
9
|
const DIR_NAME = 'shakers';
|
|
10
10
|
const LEGACY_DIR_NAME = 'ai-footprint';
|