@skillsmith/cli 0.6.5 → 0.7.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/CHANGELOG.md +8 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/src/commands/index.d.ts +1 -0
- package/dist/src/commands/index.d.ts.map +1 -1
- package/dist/src/commands/index.js +2 -0
- package/dist/src/commands/index.js.map +1 -1
- package/dist/src/commands/inventory.action.d.ts +55 -0
- package/dist/src/commands/inventory.action.d.ts.map +1 -0
- package/dist/src/commands/inventory.action.js +179 -0
- package/dist/src/commands/inventory.action.js.map +1 -0
- package/dist/src/commands/inventory.action.test.d.ts +19 -0
- package/dist/src/commands/inventory.action.test.d.ts.map +1 -0
- package/dist/src/commands/inventory.action.test.js +371 -0
- package/dist/src/commands/inventory.action.test.js.map +1 -0
- package/dist/src/commands/inventory.d.ts +21 -0
- package/dist/src/commands/inventory.d.ts.map +1 -0
- package/dist/src/commands/inventory.js +42 -0
- package/dist/src/commands/inventory.js.map +1 -0
- package/dist/src/commands/login.d.ts.map +1 -1
- package/dist/src/commands/login.js +8 -40
- package/dist/src/commands/login.js.map +1 -1
- package/dist/src/commands/login.test.js +12 -32
- package/dist/src/commands/login.test.js.map +1 -1
- package/dist/src/index.js +9 -5
- package/dist/src/index.js.map +1 -1
- package/dist/src/utils/skills-directory.d.ts +42 -0
- package/dist/src/utils/skills-directory.d.ts.map +1 -1
- package/dist/src/utils/skills-directory.js +76 -0
- package/dist/src/utils/skills-directory.js.map +1 -1
- package/dist/src/utils/startup-header-gate.d.ts +29 -0
- package/dist/src/utils/startup-header-gate.d.ts.map +1 -0
- package/dist/src/utils/startup-header-gate.js +44 -0
- package/dist/src/utils/startup-header-gate.js.map +1 -0
- package/dist/src/utils/startup-header-gate.test.d.ts +2 -0
- package/dist/src/utils/startup-header-gate.test.d.ts.map +1 -0
- package/dist/src/utils/startup-header-gate.test.js +46 -0
- package/dist/src/utils/startup-header-gate.test.js.map +1 -0
- package/dist/tests/skills-directory-per-harness.test.d.ts +2 -0
- package/dist/tests/skills-directory-per-harness.test.d.ts.map +1 -0
- package/dist/tests/skills-directory-per-harness.test.js +116 -0
- package/dist/tests/skills-directory-per-harness.test.js.map +1 -0
- package/package.json +3 -3
- package/dist/src/commands/login.post-login-sync.test.d.ts +0 -2
- package/dist/src/commands/login.post-login-sync.test.d.ts.map +0 -1
- package/dist/src/commands/login.post-login-sync.test.js +0 -120
- package/dist/src/commands/login.post-login-sync.test.js.map +0 -1
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-5390: Tests for `getInstalledSkillsPerHarness` — the cross-harness
|
|
3
|
+
* inventory scanner that returns one entry per (harness × skill) with
|
|
4
|
+
* realpath-only deduplication.
|
|
5
|
+
*
|
|
6
|
+
* Harness pattern follows the existing `skills-directory.test.ts` (SMI-4578):
|
|
7
|
+
* temp `$HOME` + `process.cwd()` spy so we never touch the real `~/.claude`
|
|
8
|
+
* directories. Modules are reset per test so CLIENT_NATIVE_PATHS recomputes
|
|
9
|
+
* against the fake home.
|
|
10
|
+
*/
|
|
11
|
+
import { createHash } from 'node:crypto';
|
|
12
|
+
import { mkdir, mkdtemp, rm, symlink, writeFile } from 'node:fs/promises';
|
|
13
|
+
import { tmpdir } from 'node:os';
|
|
14
|
+
import * as path from 'node:path';
|
|
15
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
16
|
+
const ORIGINAL_HOME = process.env['HOME'];
|
|
17
|
+
const ORIGINAL_USERPROFILE = process.env['USERPROFILE'];
|
|
18
|
+
let homeDir;
|
|
19
|
+
let cwdDir;
|
|
20
|
+
beforeEach(async () => {
|
|
21
|
+
homeDir = await mkdtemp(path.join(tmpdir(), 'smi5390-perharness-'));
|
|
22
|
+
cwdDir = await mkdtemp(path.join(tmpdir(), 'smi5390-cwd-'));
|
|
23
|
+
process.env['HOME'] = homeDir;
|
|
24
|
+
process.env['USERPROFILE'] = homeDir;
|
|
25
|
+
vi.spyOn(process, 'cwd').mockReturnValue(cwdDir);
|
|
26
|
+
vi.resetModules();
|
|
27
|
+
});
|
|
28
|
+
afterEach(async () => {
|
|
29
|
+
vi.restoreAllMocks();
|
|
30
|
+
if (ORIGINAL_HOME === undefined)
|
|
31
|
+
delete process.env['HOME'];
|
|
32
|
+
else
|
|
33
|
+
process.env['HOME'] = ORIGINAL_HOME;
|
|
34
|
+
if (ORIGINAL_USERPROFILE === undefined)
|
|
35
|
+
delete process.env['USERPROFILE'];
|
|
36
|
+
else
|
|
37
|
+
process.env['USERPROFILE'] = ORIGINAL_USERPROFILE;
|
|
38
|
+
await Promise.all([
|
|
39
|
+
rm(homeDir, { recursive: true, force: true }),
|
|
40
|
+
rm(cwdDir, { recursive: true, force: true }),
|
|
41
|
+
]);
|
|
42
|
+
});
|
|
43
|
+
/**
|
|
44
|
+
* Write a minimal SKILL.md under `<skillsRoot>/<id>/SKILL.md` and return
|
|
45
|
+
* the full SKILL.md content so callers can compute the expected hash.
|
|
46
|
+
*/
|
|
47
|
+
async function plantSkill(skillsRoot, id, body = '# test\n') {
|
|
48
|
+
const dir = path.join(skillsRoot, id);
|
|
49
|
+
await mkdir(dir, { recursive: true });
|
|
50
|
+
const content = `---\nname: ${id}\nversion: 1.0.0\n---\n${body}`;
|
|
51
|
+
await writeFile(path.join(dir, 'SKILL.md'), content, 'utf-8');
|
|
52
|
+
return { dir, content };
|
|
53
|
+
}
|
|
54
|
+
describe('getInstalledSkillsPerHarness (SMI-5390)', () => {
|
|
55
|
+
it('returns empty when no client directories exist', async () => {
|
|
56
|
+
const { getInstalledSkillsPerHarness } = await import('../src/utils/skills-directory.js');
|
|
57
|
+
const skills = await getInstalledSkillsPerHarness();
|
|
58
|
+
expect(skills).toEqual([]);
|
|
59
|
+
});
|
|
60
|
+
it('same-named skill under two distinct harness directories yields two entries', async () => {
|
|
61
|
+
await plantSkill(path.join(homeDir, '.claude', 'skills'), 'docker', '# claude docker\n');
|
|
62
|
+
await plantSkill(path.join(homeDir, '.cursor', 'skills'), 'docker', '# cursor docker\n');
|
|
63
|
+
const { getInstalledSkillsPerHarness } = await import('../src/utils/skills-directory.js');
|
|
64
|
+
const skills = await getInstalledSkillsPerHarness();
|
|
65
|
+
const dockerEntries = skills.filter((s) => s.skillId === 'docker');
|
|
66
|
+
expect(dockerEntries).toHaveLength(2);
|
|
67
|
+
const harnesses = dockerEntries.map((s) => s.harness);
|
|
68
|
+
expect(harnesses).toContain('claude-code');
|
|
69
|
+
expect(harnesses).toContain('cursor');
|
|
70
|
+
});
|
|
71
|
+
it('symlinked alias (same realpath) yields one entry', async () => {
|
|
72
|
+
// Plant the skill under claude-code, then point ~/.agents/skills at the
|
|
73
|
+
// same directory via a symlink — same inode, different harness path.
|
|
74
|
+
const claudeSkillsDir = path.join(homeDir, '.claude', 'skills');
|
|
75
|
+
await plantSkill(claudeSkillsDir, 'shared', '# shared\n');
|
|
76
|
+
const agentsParent = path.join(homeDir, '.agents');
|
|
77
|
+
await mkdir(agentsParent, { recursive: true });
|
|
78
|
+
// Symlink the entire skills directory, not just the skill subdirectory,
|
|
79
|
+
// matching the real-world scenario where a harness shares another's root.
|
|
80
|
+
await symlink(claudeSkillsDir, path.join(agentsParent, 'skills'));
|
|
81
|
+
const { getInstalledSkillsPerHarness } = await import('../src/utils/skills-directory.js');
|
|
82
|
+
const skills = await getInstalledSkillsPerHarness();
|
|
83
|
+
const sharedEntries = skills.filter((s) => s.skillId === 'shared');
|
|
84
|
+
expect(sharedEntries).toHaveLength(1);
|
|
85
|
+
// claude-code is scanned before agents in precedence order so it wins.
|
|
86
|
+
expect(sharedEntries[0]?.harness).toBe('claude-code');
|
|
87
|
+
});
|
|
88
|
+
it('contentHash is populated for a skill with a readable SKILL.md', async () => {
|
|
89
|
+
const body = '# my tool\n';
|
|
90
|
+
const { content } = await plantSkill(path.join(homeDir, '.claude', 'skills'), 'my-tool', body);
|
|
91
|
+
const { getInstalledSkillsPerHarness } = await import('../src/utils/skills-directory.js');
|
|
92
|
+
const skills = await getInstalledSkillsPerHarness();
|
|
93
|
+
const entry = skills.find((s) => s.skillId === 'my-tool');
|
|
94
|
+
expect(entry).toBeDefined();
|
|
95
|
+
const expectedHash = createHash('sha256').update(content, 'utf8').digest('hex');
|
|
96
|
+
expect(entry?.contentHash).toBe(expectedHash);
|
|
97
|
+
});
|
|
98
|
+
it('contentHash is null for a skill directory without a SKILL.md', async () => {
|
|
99
|
+
// Directory exists but has no SKILL.md — scanner still includes it.
|
|
100
|
+
const dir = path.join(homeDir, '.claude', 'skills', 'bare-dir');
|
|
101
|
+
await mkdir(dir, { recursive: true });
|
|
102
|
+
const { getInstalledSkillsPerHarness } = await import('../src/utils/skills-directory.js');
|
|
103
|
+
const skills = await getInstalledSkillsPerHarness();
|
|
104
|
+
const entry = skills.find((s) => s.skillId === 'bare-dir');
|
|
105
|
+
expect(entry).toBeDefined();
|
|
106
|
+
expect(entry?.contentHash).toBeNull();
|
|
107
|
+
});
|
|
108
|
+
it('version field reflects the SKILL.md version front-matter', async () => {
|
|
109
|
+
await plantSkill(path.join(homeDir, '.claude', 'skills'), 'versioned', '# v\n');
|
|
110
|
+
const { getInstalledSkillsPerHarness } = await import('../src/utils/skills-directory.js');
|
|
111
|
+
const skills = await getInstalledSkillsPerHarness();
|
|
112
|
+
const entry = skills.find((s) => s.skillId === 'versioned');
|
|
113
|
+
expect(entry?.version).toBe('1.0.0');
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
//# sourceMappingURL=skills-directory-per-harness.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills-directory-per-harness.test.js","sourceRoot":"","sources":["../../tests/skills-directory-per-harness.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACzE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAChC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AACjC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAExE,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;AACzC,MAAM,oBAAoB,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;AAEvD,IAAI,OAAe,CAAA;AACnB,IAAI,MAAc,CAAA;AAElB,UAAU,CAAC,KAAK,IAAI,EAAE;IACpB,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,qBAAqB,CAAC,CAAC,CAAA;IACnE,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,cAAc,CAAC,CAAC,CAAA;IAC3D,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,OAAO,CAAA;IAC7B,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,GAAG,OAAO,CAAA;IACpC,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,CAAA;IAChD,EAAE,CAAC,YAAY,EAAE,CAAA;AACnB,CAAC,CAAC,CAAA;AAEF,SAAS,CAAC,KAAK,IAAI,EAAE;IACnB,EAAE,CAAC,eAAe,EAAE,CAAA;IACpB,IAAI,aAAa,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;;QACtD,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,aAAa,CAAA;IACxC,IAAI,oBAAoB,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;;QACpE,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,GAAG,oBAAoB,CAAA;IACtD,MAAM,OAAO,CAAC,GAAG,CAAC;QAChB,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QAC7C,EAAE,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;KAC7C,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF;;;GAGG;AACH,KAAK,UAAU,UAAU,CACvB,UAAkB,EAClB,EAAU,EACV,OAAe,UAAU;IAEzB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC,CAAA;IACrC,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACrC,MAAM,OAAO,GAAG,cAAc,EAAE,0BAA0B,IAAI,EAAE,CAAA;IAChE,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;IAC7D,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,CAAA;AACzB,CAAC;AAED,QAAQ,CAAC,yCAAyC,EAAE,GAAG,EAAE;IACvD,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,EAAE,4BAA4B,EAAE,GAAG,MAAM,MAAM,CAAC,kCAAkC,CAAC,CAAA;QACzF,MAAM,MAAM,GAAG,MAAM,4BAA4B,EAAE,CAAA;QACnD,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IAC5B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4EAA4E,EAAE,KAAK,IAAI,EAAE;QAC1F,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,QAAQ,EAAE,mBAAmB,CAAC,CAAA;QACxF,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,QAAQ,EAAE,mBAAmB,CAAC,CAAA;QAExF,MAAM,EAAE,4BAA4B,EAAE,GAAG,MAAM,MAAM,CAAC,kCAAkC,CAAC,CAAA;QACzF,MAAM,MAAM,GAAG,MAAM,4BAA4B,EAAE,CAAA;QAEnD,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAA;QAClE,MAAM,CAAC,aAAa,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QACrC,MAAM,SAAS,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAA;QACrD,MAAM,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAA;QAC1C,MAAM,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,wEAAwE;QACxE,qEAAqE;QACrE,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAA;QAC/D,MAAM,UAAU,CAAC,eAAe,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAA;QAEzD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;QAClD,MAAM,KAAK,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC9C,wEAAwE;QACxE,0EAA0E;QAC1E,MAAM,OAAO,CAAC,eAAe,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAA;QAEjE,MAAM,EAAE,4BAA4B,EAAE,GAAG,MAAM,MAAM,CAAC,kCAAkC,CAAC,CAAA;QACzF,MAAM,MAAM,GAAG,MAAM,4BAA4B,EAAE,CAAA;QAEnD,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAA;QAClE,MAAM,CAAC,aAAa,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QACrC,uEAAuE;QACvE,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;IACvD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;QAC7E,MAAM,IAAI,GAAG,aAAa,CAAA;QAC1B,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,CAAA;QAE9F,MAAM,EAAE,4BAA4B,EAAE,GAAG,MAAM,MAAM,CAAC,kCAAkC,CAAC,CAAA;QACzF,MAAM,MAAM,GAAG,MAAM,4BAA4B,EAAE,CAAA;QAEnD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,SAAS,CAAC,CAAA;QACzD,MAAM,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAA;QAE3B,MAAM,YAAY,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAC/E,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;IAC/C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;QAC5E,oEAAoE;QACpE,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAA;QAC/D,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAErC,MAAM,EAAE,4BAA4B,EAAE,GAAG,MAAM,MAAM,CAAC,kCAAkC,CAAC,CAAA;QACzF,MAAM,MAAM,GAAG,MAAM,4BAA4B,EAAE,CAAA;QAEnD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,UAAU,CAAC,CAAA;QAC1D,MAAM,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAA;QAC3B,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,QAAQ,EAAE,CAAA;IACvC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;QACxE,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,CAAA;QAE/E,MAAM,EAAE,4BAA4B,EAAE,GAAG,MAAM,MAAM,CAAC,kCAAkC,CAAC,CAAA;QACzF,MAAM,MAAM,GAAG,MAAM,4BAA4B,EAAE,CAAA;QAEnD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,WAAW,CAAC,CAAA;QAC3D,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACtC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skillsmith/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "CLI tools for Skillsmith skill discovery and authentication",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@inquirer/prompts": "7.10.1",
|
|
20
|
-
"@skillsmith/core": "^0.
|
|
21
|
-
"@skillsmith/mcp-server": "^0.
|
|
20
|
+
"@skillsmith/core": "^0.9.0",
|
|
21
|
+
"@skillsmith/mcp-server": "^0.6.0",
|
|
22
22
|
"chalk": "5.6.2",
|
|
23
23
|
"chokidar": "4.0.3",
|
|
24
24
|
"cli-table3": "0.6.5",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"login.post-login-sync.test.d.ts","sourceRoot":"","sources":["../../../src/commands/login.post-login-sync.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
// SMI-4917 Bug 3: post-login registry auto-sync.
|
|
2
|
-
// PLS-1: device-code success path runs the post-login sync.
|
|
3
|
-
// PLS-2: a failed post-login sync is non-fatal — login still exits 0.
|
|
4
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
5
|
-
import { mockDeviceCodeSuccess } from './login.test-helpers.js';
|
|
6
|
-
vi.mock('readline', () => {
|
|
7
|
-
const createInterface = vi.fn();
|
|
8
|
-
return { default: { createInterface }, createInterface };
|
|
9
|
-
});
|
|
10
|
-
vi.mock('@skillsmith/core', () => ({
|
|
11
|
-
loadCredentials: vi.fn(),
|
|
12
|
-
storeCredentials: vi.fn(),
|
|
13
|
-
getApiKey: vi.fn(),
|
|
14
|
-
getApiBaseUrl: vi.fn().mockReturnValue('https://api.skillsmith.app/functions/v1'),
|
|
15
|
-
storeApiKey: vi.fn(),
|
|
16
|
-
isValidApiKeyFormat: vi.fn(),
|
|
17
|
-
}));
|
|
18
|
-
vi.mock('@inquirer/prompts', () => ({ password: vi.fn() }));
|
|
19
|
-
vi.mock('open', () => ({ default: vi.fn() }));
|
|
20
|
-
// postLoginSync (SMI-4917) opens a DB and runs runRegistrySync — both stubbed.
|
|
21
|
-
const mockOpenCliDatabase = vi.fn();
|
|
22
|
-
const mockRunRegistrySync = vi.fn();
|
|
23
|
-
vi.mock('../utils/open-database.js', () => ({
|
|
24
|
-
openCliDatabase: (...args) => mockOpenCliDatabase(...args),
|
|
25
|
-
}));
|
|
26
|
-
vi.mock('./run-registry-sync.js', () => ({
|
|
27
|
-
runRegistrySync: (...args) => mockRunRegistrySync(...args),
|
|
28
|
-
}));
|
|
29
|
-
vi.mock('ora', () => {
|
|
30
|
-
const spinner = {
|
|
31
|
-
start: vi.fn(() => spinner),
|
|
32
|
-
succeed: vi.fn(() => spinner),
|
|
33
|
-
warn: vi.fn(() => spinner),
|
|
34
|
-
fail: vi.fn(() => spinner),
|
|
35
|
-
stop: vi.fn(() => spinner),
|
|
36
|
-
text: '',
|
|
37
|
-
};
|
|
38
|
-
return { default: vi.fn(() => spinner) };
|
|
39
|
-
});
|
|
40
|
-
import { createLoginCommand } from './login.js';
|
|
41
|
-
import { loadCredentials, storeCredentials } from '@skillsmith/core';
|
|
42
|
-
const mockLoadCredentials = vi.mocked(loadCredentials);
|
|
43
|
-
const mockStoreCredentials = vi.mocked(storeCredentials);
|
|
44
|
-
async function runCommand(args = []) {
|
|
45
|
-
const cmd = createLoginCommand();
|
|
46
|
-
await cmd.parseAsync(['node', 'login', ...args]);
|
|
47
|
-
}
|
|
48
|
-
describe('SMI-4917 Bug 3: postLoginSync', () => {
|
|
49
|
-
let consoleLogSpy;
|
|
50
|
-
let consoleErrorSpy;
|
|
51
|
-
let processExitSpy;
|
|
52
|
-
let originalEnv;
|
|
53
|
-
let originalFetch;
|
|
54
|
-
beforeEach(() => {
|
|
55
|
-
vi.clearAllMocks();
|
|
56
|
-
vi.useFakeTimers();
|
|
57
|
-
originalEnv = { ...process.env };
|
|
58
|
-
originalFetch = global.fetch;
|
|
59
|
-
process.env['CI'] = 'true';
|
|
60
|
-
delete process.env['SKILLSMITH_API_KEY'];
|
|
61
|
-
mockLoadCredentials.mockResolvedValue(null);
|
|
62
|
-
mockStoreCredentials.mockResolvedValue(undefined);
|
|
63
|
-
mockOpenCliDatabase.mockResolvedValue({ close: vi.fn() });
|
|
64
|
-
mockRunRegistrySync.mockResolvedValue({
|
|
65
|
-
success: true,
|
|
66
|
-
skillsAdded: 0,
|
|
67
|
-
skillsUpdated: 0,
|
|
68
|
-
skillsUnchanged: 0,
|
|
69
|
-
totalProcessed: 0,
|
|
70
|
-
errors: [],
|
|
71
|
-
durationMs: 1,
|
|
72
|
-
dryRun: false,
|
|
73
|
-
});
|
|
74
|
-
consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
|
|
75
|
-
consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
76
|
-
processExitSpy = vi
|
|
77
|
-
.spyOn(process, 'exit')
|
|
78
|
-
.mockImplementation((code) => {
|
|
79
|
-
vi.clearAllTimers();
|
|
80
|
-
throw new Error(`process.exit(${code ?? 0})`);
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
afterEach(() => {
|
|
84
|
-
vi.useRealTimers();
|
|
85
|
-
process.env = originalEnv;
|
|
86
|
-
global.fetch = originalFetch;
|
|
87
|
-
consoleLogSpy.mockRestore();
|
|
88
|
-
consoleErrorSpy.mockRestore();
|
|
89
|
-
processExitSpy.mockRestore();
|
|
90
|
-
});
|
|
91
|
-
it('PLS-1: device-code success path runs the post-login registry sync', async () => {
|
|
92
|
-
mockDeviceCodeSuccess();
|
|
93
|
-
mockRunRegistrySync.mockResolvedValue({
|
|
94
|
-
success: true,
|
|
95
|
-
skillsAdded: 12,
|
|
96
|
-
skillsUpdated: 0,
|
|
97
|
-
skillsUnchanged: 0,
|
|
98
|
-
totalProcessed: 12,
|
|
99
|
-
errors: [],
|
|
100
|
-
durationMs: 1,
|
|
101
|
-
dryRun: false,
|
|
102
|
-
});
|
|
103
|
-
const run = runCommand();
|
|
104
|
-
run.catch(() => { });
|
|
105
|
-
await vi.runAllTimersAsync();
|
|
106
|
-
await expect(run).rejects.toThrow('process.exit(0)');
|
|
107
|
-
expect(mockRunRegistrySync).toHaveBeenCalledTimes(1);
|
|
108
|
-
});
|
|
109
|
-
it('PLS-2: a failed post-login sync is non-fatal — login still exits 0', async () => {
|
|
110
|
-
mockDeviceCodeSuccess();
|
|
111
|
-
// Sync fails; credentials were already persisted, so login must still succeed.
|
|
112
|
-
mockRunRegistrySync.mockRejectedValue(new Error('registry unreachable'));
|
|
113
|
-
const run = runCommand();
|
|
114
|
-
run.catch(() => { });
|
|
115
|
-
await vi.runAllTimersAsync();
|
|
116
|
-
await expect(run).rejects.toThrow('process.exit(0)');
|
|
117
|
-
expect(mockStoreCredentials).toHaveBeenCalled();
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
//# sourceMappingURL=login.post-login-sync.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"login.post-login-sync.test.js","sourceRoot":"","sources":["../../../src/commands/login.post-login-sync.test.ts"],"names":[],"mappings":"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"}
|