sra-skills 0.14.0 → 0.14.2
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/index.mjs +7 -0
- package/lib.mjs +88 -0
- package/manage.mjs +4 -0
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
getVersion, parseSkillFrontmatter, DEFAULT_CRED_PATH,
|
|
8
8
|
loadCredentials, getCredValue, repoNameFromUrl, mergeCredentials,
|
|
9
9
|
runToolSetup, runPostInstall, promptSkillDeps, findSkillsWithDeps,
|
|
10
|
+
ensureIdentity,
|
|
10
11
|
} from './lib.mjs';
|
|
11
12
|
import { existsSync, mkdirSync, lstatSync, unlinkSync } from 'fs';
|
|
12
13
|
import { join, basename, resolve } from 'path';
|
|
@@ -80,6 +81,8 @@ const cmdArgs = rawArgs.slice(1);
|
|
|
80
81
|
if (cmd === 'add') {
|
|
81
82
|
const isLocal = cmdArgs.includes('--local');
|
|
82
83
|
const skipPrompt = cmdArgs.includes('-y') || cmdArgs.includes('--yes');
|
|
84
|
+
const identityIdx = cmdArgs.indexOf('--default-identity');
|
|
85
|
+
const defaultIdentity = identityIdx >= 0 ? cmdArgs[identityIdx + 1] : null;
|
|
83
86
|
const tools = parseToolFlag(cmdArgs) || detectTools();
|
|
84
87
|
const nameIdx = cmdArgs.indexOf('--name');
|
|
85
88
|
let url, name, repoPath;
|
|
@@ -140,6 +143,7 @@ if (cmd === 'add') {
|
|
|
140
143
|
console.log(`Installing ${skills.length} skills, tools: [${tools.join(', ')}]`);
|
|
141
144
|
linkSkills(skills, tools);
|
|
142
145
|
const credPath = mergeCredentials(repoPath);
|
|
146
|
+
await ensureIdentity(skipPrompt, defaultIdentity);
|
|
143
147
|
runToolSetup(repoPath, tools);
|
|
144
148
|
runPostInstall(repoPath);
|
|
145
149
|
|
|
@@ -189,6 +193,8 @@ if (cmd === 'add') {
|
|
|
189
193
|
const m = readManifest();
|
|
190
194
|
const tools = parseToolFlag(cmdArgs) || m.tools || detectTools();
|
|
191
195
|
const skipPrompt = cmdArgs.includes('-y') || cmdArgs.includes('--yes');
|
|
196
|
+
const identityIdx = cmdArgs.indexOf('--default-identity');
|
|
197
|
+
const defaultIdentity = identityIdx >= 0 ? cmdArgs[identityIdx + 1] : null;
|
|
192
198
|
const target = cmdArgs.find(a => !a.startsWith('-'));
|
|
193
199
|
const targets = target ? [target] : Object.keys(m.repos);
|
|
194
200
|
const depsEntries = [];
|
|
@@ -264,6 +270,7 @@ if (cmd === 'add') {
|
|
|
264
270
|
const skills = allSkills.filter(s => !disabled.has(s.name));
|
|
265
271
|
linkSkills(skills, tools);
|
|
266
272
|
mergeCredentials(repo.path);
|
|
273
|
+
await ensureIdentity(skipPrompt, defaultIdentity);
|
|
267
274
|
runToolSetup(repo.path, tools);
|
|
268
275
|
runPostInstall(repo.path);
|
|
269
276
|
depsEntries.push({ repoPath: repo.path, skills });
|
package/lib.mjs
CHANGED
|
@@ -317,6 +317,94 @@ export function parseSkillFrontmatter(skillPath) {
|
|
|
317
317
|
|
|
318
318
|
export const DEFAULT_CRED_PATH = join(HOME, '.config', 'sra', 'credentials.json');
|
|
319
319
|
|
|
320
|
+
export const COMPANY_EMAIL_DOMAINS = new Set(['shopee.com', 'garena.com', 'seagroup.com', 'sea.com']);
|
|
321
|
+
const PLACEHOLDER_LOCAL_PARTS = new Set([
|
|
322
|
+
'your.name', 'yourname', 'your_name', 'your-name',
|
|
323
|
+
'your.email', 'youremail', 'your_email',
|
|
324
|
+
'test', 'example', 'placeholder', 'changeme',
|
|
325
|
+
]);
|
|
326
|
+
|
|
327
|
+
export function isCompanyEmail(email) {
|
|
328
|
+
if (!email || !email.includes('@')) return false;
|
|
329
|
+
const [local, domain] = [email.substring(0, email.lastIndexOf('@')), email.substring(email.lastIndexOf('@') + 1)];
|
|
330
|
+
if (PLACEHOLDER_LOCAL_PARTS.has(local.toLowerCase())) return false;
|
|
331
|
+
return COMPANY_EMAIL_DOMAINS.has(domain.toLowerCase());
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
export async function ensureIdentity(skipPrompt, defaultIdentityArg) {
|
|
335
|
+
const credPath = DEFAULT_CRED_PATH;
|
|
336
|
+
let existing = {};
|
|
337
|
+
if (existsSync(credPath)) {
|
|
338
|
+
try {
|
|
339
|
+
existing = JSON.parse(readFileSync(credPath, 'utf8'));
|
|
340
|
+
} catch {
|
|
341
|
+
console.error(`Warning: ${credPath} contains invalid JSON, credentials will be reset`);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
const current = existing?.default?.identity || '';
|
|
346
|
+
if (isCompanyEmail(current)) return current;
|
|
347
|
+
|
|
348
|
+
// --default-identity provided
|
|
349
|
+
if (defaultIdentityArg) {
|
|
350
|
+
if (!isCompanyEmail(defaultIdentityArg)) {
|
|
351
|
+
const domains = [...COMPANY_EMAIL_DOMAINS].sort().join(', ');
|
|
352
|
+
console.error(`Error: --default-identity "${defaultIdentityArg}" is not a company email (allowed domains: ${domains})`);
|
|
353
|
+
process.exit(1);
|
|
354
|
+
}
|
|
355
|
+
existing = existing || {};
|
|
356
|
+
(existing.default = existing.default || {}).identity = defaultIdentityArg;
|
|
357
|
+
mkdirSync(join(HOME, '.config', 'sra'), { recursive: true });
|
|
358
|
+
writeFileSync(credPath, JSON.stringify(existing, null, 2) + '\n');
|
|
359
|
+
console.log(` Company email set: ${defaultIdentityArg}`);
|
|
360
|
+
return defaultIdentityArg;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// --yes mode without --default-identity
|
|
364
|
+
if (skipPrompt) {
|
|
365
|
+
const domains = [...COMPANY_EMAIL_DOMAINS].sort().join(', ');
|
|
366
|
+
console.error(`Error: --yes requires --default-identity <email@company.com> when no valid identity is set.`);
|
|
367
|
+
process.exit(1);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Non-TTY
|
|
371
|
+
if (!process.stdin.isTTY) {
|
|
372
|
+
const domains = [...COMPANY_EMAIL_DOMAINS].sort().join(', ');
|
|
373
|
+
console.error(`Error: default.identity not configured and stdin is not a terminal.`);
|
|
374
|
+
console.error(`Use --default-identity=you@company.com (${domains})`);
|
|
375
|
+
process.exit(1);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Interactive prompt
|
|
379
|
+
let gitEmail = '';
|
|
380
|
+
try {
|
|
381
|
+
gitEmail = execSync('git config --global user.email', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
|
|
382
|
+
} catch {}
|
|
383
|
+
const prefill = isCompanyEmail(gitEmail) ? gitEmail : '';
|
|
384
|
+
const domains = [...COMPANY_EMAIL_DOMAINS].sort().join(', ');
|
|
385
|
+
|
|
386
|
+
// Need to import input from @inquirer/prompts
|
|
387
|
+
const { input } = await import('@inquirer/prompts');
|
|
388
|
+
console.log(`Company email required for telemetry (accepted domains: ${domains})`);
|
|
389
|
+
|
|
390
|
+
while (true) {
|
|
391
|
+
const raw = await input({
|
|
392
|
+
message: 'Company email',
|
|
393
|
+
default: prefill || undefined,
|
|
394
|
+
});
|
|
395
|
+
const email = raw.trim();
|
|
396
|
+
if (isCompanyEmail(email)) {
|
|
397
|
+
existing = existing || {};
|
|
398
|
+
(existing.default = existing.default || {}).identity = email;
|
|
399
|
+
mkdirSync(join(HOME, '.config', 'sra'), { recursive: true });
|
|
400
|
+
writeFileSync(credPath, JSON.stringify(existing, null, 2) + '\n');
|
|
401
|
+
console.log(` Company email set: ${email}`);
|
|
402
|
+
return email;
|
|
403
|
+
}
|
|
404
|
+
console.log(` Invalid: "${email}" — must end with one of: ${domains}`);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
320
408
|
export function loadCredentials(credPath) {
|
|
321
409
|
const p = credPath || DEFAULT_CRED_PATH;
|
|
322
410
|
if (!existsSync(p)) return {};
|
package/manage.mjs
CHANGED
|
@@ -152,7 +152,11 @@ export async function main() {
|
|
|
152
152
|
const enabled = (repo.skills || []).length;
|
|
153
153
|
return `${name} (${enabled}/${all.length})`;
|
|
154
154
|
});
|
|
155
|
+
// Preserve current repo selection — setItems resets to 0 and fires
|
|
156
|
+
// 'select item', which would switch currentRepoName to the first repo.
|
|
157
|
+
const prevIdx = currentRepoName ? names.indexOf(currentRepoName) : 0;
|
|
155
158
|
reposPanel.setItems(items);
|
|
159
|
+
if (prevIdx >= 0) reposPanel.select(prevIdx);
|
|
156
160
|
}
|
|
157
161
|
|
|
158
162
|
function renderSkills() {
|