@skillsmith/cli 0.6.4 → 0.7.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/src/commands/audit-sources.action.d.ts.map +1 -1
  4. package/dist/src/commands/audit-sources.action.js +26 -5
  5. package/dist/src/commands/audit-sources.action.js.map +1 -1
  6. package/dist/src/commands/diff.d.ts.map +1 -1
  7. package/dist/src/commands/diff.js +36 -15
  8. package/dist/src/commands/diff.js.map +1 -1
  9. package/dist/src/commands/diff.test.js +22 -0
  10. package/dist/src/commands/diff.test.js.map +1 -1
  11. package/dist/src/commands/index.d.ts +1 -0
  12. package/dist/src/commands/index.d.ts.map +1 -1
  13. package/dist/src/commands/index.js +2 -0
  14. package/dist/src/commands/index.js.map +1 -1
  15. package/dist/src/commands/inventory.action.d.ts +55 -0
  16. package/dist/src/commands/inventory.action.d.ts.map +1 -0
  17. package/dist/src/commands/inventory.action.js +179 -0
  18. package/dist/src/commands/inventory.action.js.map +1 -0
  19. package/dist/src/commands/inventory.action.test.d.ts +19 -0
  20. package/dist/src/commands/inventory.action.test.d.ts.map +1 -0
  21. package/dist/src/commands/inventory.action.test.js +371 -0
  22. package/dist/src/commands/inventory.action.test.js.map +1 -0
  23. package/dist/src/commands/inventory.d.ts +21 -0
  24. package/dist/src/commands/inventory.d.ts.map +1 -0
  25. package/dist/src/commands/inventory.js +42 -0
  26. package/dist/src/commands/inventory.js.map +1 -0
  27. package/dist/src/index.js +3 -1
  28. package/dist/src/index.js.map +1 -1
  29. package/dist/src/utils/skills-directory.d.ts +42 -0
  30. package/dist/src/utils/skills-directory.d.ts.map +1 -1
  31. package/dist/src/utils/skills-directory.js +76 -0
  32. package/dist/src/utils/skills-directory.js.map +1 -1
  33. package/dist/tests/e2e/audit-sources-affix.test.d.ts +11 -0
  34. package/dist/tests/e2e/audit-sources-affix.test.d.ts.map +1 -0
  35. package/dist/tests/e2e/audit-sources-affix.test.js +121 -0
  36. package/dist/tests/e2e/audit-sources-affix.test.js.map +1 -0
  37. package/dist/tests/e2e/audit-sources-roundtrip.test.js +32 -0
  38. package/dist/tests/e2e/audit-sources-roundtrip.test.js.map +1 -1
  39. package/dist/tests/skills-directory-per-harness.test.d.ts +2 -0
  40. package/dist/tests/skills-directory-per-harness.test.d.ts.map +1 -0
  41. package/dist/tests/skills-directory-per-harness.test.js +116 -0
  42. package/dist/tests/skills-directory-per-harness.test.js.map +1 -0
  43. package/package.json +3 -3
@@ -0,0 +1,371 @@
1
+ /**
2
+ * @fileoverview Tests for `skillsmith inventory` subcommands.
3
+ * @module @skillsmith/cli/commands/inventory.action.test
4
+ * @see SMI-5392 Wave 3 — CLI inventory push/status/forget-device (umbrella SMI-5382)
5
+ *
6
+ * Covers:
7
+ * push: renders applied / consent-off / disabled-locally output correctly
8
+ * push: maps each of the 4 typed errors to console.error + process.exit(1)
9
+ * status: prints device ID, last-push, opt-out flag, and harness presence
10
+ * forget-device: calls core forgetDevice and prints confirmation with prior ID
11
+ *
12
+ * instanceof strategy:
13
+ * @skillsmith/core is mocked with inline class definitions for the four error
14
+ * types. Because vi.mock factories are hoisted, both the source module and the
15
+ * test file receive the SAME class reference — so `err instanceof InventoryAuthError`
16
+ * inside inventoryPushActionImpl matches the errors thrown in tests.
17
+ */
18
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
19
+ // ---------------------------------------------------------------------------
20
+ // @skillsmith/core/telemetry — passthrough so withTelemetry has no side effects
21
+ // ---------------------------------------------------------------------------
22
+ vi.mock('@skillsmith/core/telemetry', () => ({
23
+ withTelemetry: (fn) => fn,
24
+ }));
25
+ // ---------------------------------------------------------------------------
26
+ // @skillsmith/core — mock functions; inline class definitions for error types
27
+ // so instanceof checks work (same reference in source + test).
28
+ // ---------------------------------------------------------------------------
29
+ vi.mock('@skillsmith/core', () => {
30
+ class InventoryAuthError extends Error {
31
+ constructor(msg = 'Not authenticated. Run `skillsmith login` and try again.') {
32
+ super(msg);
33
+ this.name = 'InventoryAuthError';
34
+ }
35
+ }
36
+ class InventoryConflictError extends Error {
37
+ constructor(msg = 'device_conflict') {
38
+ super(msg);
39
+ this.name = 'InventoryConflictError';
40
+ }
41
+ }
42
+ class InventoryValidationError extends Error {
43
+ constructor(msg = 'invalid payload') {
44
+ super(msg);
45
+ this.name = 'InventoryValidationError';
46
+ }
47
+ }
48
+ class InventoryUploadError extends Error {
49
+ constructor(msg) {
50
+ super(msg);
51
+ this.name = 'InventoryUploadError';
52
+ }
53
+ }
54
+ return {
55
+ pushInventory: vi.fn(),
56
+ getDeviceId: vi.fn(),
57
+ forgetDevice: vi.fn(),
58
+ getLastInventoryPushAt: vi.fn(),
59
+ isInventorySyncDisabledLocally: vi.fn(),
60
+ InventoryAuthError,
61
+ InventoryConflictError,
62
+ InventoryValidationError,
63
+ InventoryUploadError,
64
+ };
65
+ });
66
+ // ---------------------------------------------------------------------------
67
+ // @skillsmith/core/install — sync function, mock to return a fixed presence set
68
+ // ---------------------------------------------------------------------------
69
+ vi.mock('@skillsmith/core/install', () => ({
70
+ enumerateHarnessPresence: vi.fn(() => [
71
+ { harness: 'claude-code', present: true, path: '/mock/.claude/skills' },
72
+ { harness: 'cursor', present: false, path: '/mock/.cursor/skills' },
73
+ ]),
74
+ }));
75
+ // ---------------------------------------------------------------------------
76
+ // CLI utilities
77
+ // ---------------------------------------------------------------------------
78
+ vi.mock('../utils/skills-directory.js', () => ({
79
+ getInstalledSkillsPerHarness: vi.fn(() => Promise.resolve([])),
80
+ }));
81
+ vi.mock('../version.js', () => ({ VERSION: '0.0.0-test' }));
82
+ // ---------------------------------------------------------------------------
83
+ // Import after mocks are registered
84
+ // ---------------------------------------------------------------------------
85
+ import { runPush, runStatus, runForgetDevice, inventoryPushActionImpl, inventoryStatusActionImpl, inventoryForgetDeviceActionImpl, } from './inventory.action.js';
86
+ import { pushInventory, getDeviceId, forgetDevice, getLastInventoryPushAt, isInventorySyncDisabledLocally, InventoryAuthError, InventoryConflictError, InventoryValidationError, InventoryUploadError, } from '@skillsmith/core';
87
+ import { enumerateHarnessPresence } from '@skillsmith/core/install';
88
+ import { getInstalledSkillsPerHarness } from '../utils/skills-directory.js';
89
+ const pushInventoryMock = vi.mocked(pushInventory);
90
+ const getDeviceIdMock = vi.mocked(getDeviceId);
91
+ const forgetDeviceMock = vi.mocked(forgetDevice);
92
+ const getLastInventoryPushAtMock = vi.mocked(getLastInventoryPushAt);
93
+ const isInventorySyncDisabledLocallyMock = vi.mocked(isInventorySyncDisabledLocally);
94
+ const enumerateHarnessPresenceMock = vi.mocked(enumerateHarnessPresence);
95
+ const getInstalledSkillsPerHarnessMock = vi.mocked(getInstalledSkillsPerHarness);
96
+ // ---------------------------------------------------------------------------
97
+ // Console capture helper
98
+ // ---------------------------------------------------------------------------
99
+ function captureConsole() {
100
+ const log = [];
101
+ const err = [];
102
+ vi.spyOn(console, 'log').mockImplementation((...args) => log.push(args.join(' ')));
103
+ vi.spyOn(console, 'error').mockImplementation((...args) => err.push(args.join(' ')));
104
+ return {
105
+ log,
106
+ err,
107
+ all: () => [...log, ...err],
108
+ };
109
+ }
110
+ // ---------------------------------------------------------------------------
111
+ // Setup / teardown
112
+ // ---------------------------------------------------------------------------
113
+ beforeEach(() => {
114
+ vi.clearAllMocks();
115
+ // Defaults so tests that don't care about these still get sensible values.
116
+ getDeviceIdMock.mockReturnValue('test-device-uuid-1234');
117
+ getLastInventoryPushAtMock.mockReturnValue(undefined);
118
+ isInventorySyncDisabledLocallyMock.mockReturnValue(false);
119
+ getInstalledSkillsPerHarnessMock.mockResolvedValue([]);
120
+ });
121
+ afterEach(() => {
122
+ vi.restoreAllMocks();
123
+ });
124
+ // ---------------------------------------------------------------------------
125
+ // push — happy-path rendering
126
+ // ---------------------------------------------------------------------------
127
+ describe('inventory push — happy paths', () => {
128
+ it('prints dim note when sync is locally disabled (disabled_locally)', async () => {
129
+ pushInventoryMock.mockResolvedValue({
130
+ ok: true,
131
+ applied: false,
132
+ reason: 'disabled_locally',
133
+ });
134
+ const cap = captureConsole();
135
+ await runPush();
136
+ const output = cap.all().join('\n');
137
+ expect(output).toContain('SKILLSMITH_INVENTORY_DISABLE');
138
+ expect(output).toContain('nothing sent');
139
+ });
140
+ it('prints yellow consent-off message when server returns consent_disabled', async () => {
141
+ pushInventoryMock.mockResolvedValue({
142
+ ok: true,
143
+ applied: false,
144
+ reason: 'consent_disabled',
145
+ });
146
+ const cap = captureConsole();
147
+ await runPush();
148
+ const output = cap.all().join('\n');
149
+ expect(output).toContain('sync is OFF');
150
+ expect(output).toContain('nothing stored');
151
+ });
152
+ it('prints green success line with device_id and counts when applied=true', async () => {
153
+ pushInventoryMock.mockResolvedValue({
154
+ ok: true,
155
+ applied: true,
156
+ device_id: 'abc-device-123',
157
+ skills_present: 7,
158
+ skills_absent: 2,
159
+ });
160
+ const cap = captureConsole();
161
+ await runPush();
162
+ const output = cap.all().join('\n');
163
+ expect(output).toContain('abc-device-123');
164
+ expect(output).toContain('7 present');
165
+ expect(output).toContain('2 marked absent');
166
+ });
167
+ it('prints defensive raw result for unexpected ok/reason combo', async () => {
168
+ pushInventoryMock.mockResolvedValue({ ok: false, applied: false, reason: 'unknown_reason' });
169
+ const cap = captureConsole();
170
+ await runPush();
171
+ const output = cap.all().join('\n');
172
+ expect(output).toContain('unknown_reason');
173
+ });
174
+ });
175
+ // ---------------------------------------------------------------------------
176
+ // push — typed error mapping → process.exit(1)
177
+ // ---------------------------------------------------------------------------
178
+ describe('inventory push — typed error mapping', () => {
179
+ function mockExit() {
180
+ return vi.spyOn(process, 'exit').mockImplementation((code) => {
181
+ throw new Error(`process.exit(${String(code)})`);
182
+ });
183
+ }
184
+ it('maps InventoryAuthError → "Not logged in" message + exit(1)', async () => {
185
+ const exitSpy = mockExit();
186
+ pushInventoryMock.mockRejectedValue(new InventoryAuthError());
187
+ const cap = captureConsole();
188
+ await expect(inventoryPushActionImpl()).rejects.toThrow('process.exit(1)');
189
+ expect(exitSpy).toHaveBeenCalledWith(1);
190
+ expect(cap.err.join(' ')).toContain('Not logged in');
191
+ });
192
+ it('maps InventoryConflictError → "forget-device" hint + exit(1)', async () => {
193
+ const exitSpy = mockExit();
194
+ pushInventoryMock.mockRejectedValue(new InventoryConflictError());
195
+ const cap = captureConsole();
196
+ await expect(inventoryPushActionImpl()).rejects.toThrow('process.exit(1)');
197
+ expect(exitSpy).toHaveBeenCalledWith(1);
198
+ expect(cap.err.join(' ')).toContain('forget-device');
199
+ });
200
+ it('maps InventoryValidationError → server message + exit(1)', async () => {
201
+ const exitSpy = mockExit();
202
+ pushInventoryMock.mockRejectedValue(new InventoryValidationError('skill_id_too_long'));
203
+ const cap = captureConsole();
204
+ await expect(inventoryPushActionImpl()).rejects.toThrow('process.exit(1)');
205
+ expect(exitSpy).toHaveBeenCalledWith(1);
206
+ expect(cap.err.join(' ')).toContain('skill_id_too_long');
207
+ });
208
+ it('maps InventoryUploadError → "Inventory upload failed." prefix + exit(1)', async () => {
209
+ const exitSpy = mockExit();
210
+ pushInventoryMock.mockRejectedValue(new InventoryUploadError('HTTP 503'));
211
+ const cap = captureConsole();
212
+ await expect(inventoryPushActionImpl()).rejects.toThrow('process.exit(1)');
213
+ expect(exitSpy).toHaveBeenCalledWith(1);
214
+ expect(cap.err.join(' ')).toContain('Inventory upload failed.');
215
+ expect(cap.err.join(' ')).toContain('HTTP 503');
216
+ });
217
+ });
218
+ // ---------------------------------------------------------------------------
219
+ // status — read-only local view
220
+ // ---------------------------------------------------------------------------
221
+ describe('inventory status', () => {
222
+ it('shows device ID when registered', async () => {
223
+ getDeviceIdMock.mockReturnValue('my-stable-device-uuid');
224
+ const cap = captureConsole();
225
+ await runStatus();
226
+ expect(cap.log.join('\n')).toContain('my-stable-device-uuid');
227
+ });
228
+ it('shows placeholder when device not yet registered', async () => {
229
+ getDeviceIdMock.mockReturnValue(undefined);
230
+ const cap = captureConsole();
231
+ await runStatus();
232
+ expect(cap.log.join('\n')).toContain('not yet registered');
233
+ });
234
+ it('shows "never" when no push has occurred', async () => {
235
+ getLastInventoryPushAtMock.mockReturnValue(undefined);
236
+ const cap = captureConsole();
237
+ await runStatus();
238
+ expect(cap.log.join('\n')).toContain('never');
239
+ });
240
+ it('shows last push timestamp when present', async () => {
241
+ getLastInventoryPushAtMock.mockReturnValue('2026-01-15T10:00:00.000Z');
242
+ const cap = captureConsole();
243
+ await runStatus();
244
+ expect(cap.log.join('\n')).toContain('2026-01-15T10:00:00.000Z');
245
+ });
246
+ it('shows opt-out warning when SKILLSMITH_INVENTORY_DISABLE is set', async () => {
247
+ isInventorySyncDisabledLocallyMock.mockReturnValue(true);
248
+ const cap = captureConsole();
249
+ await runStatus();
250
+ expect(cap.log.join('\n')).toContain('SKILLSMITH_INVENTORY_DISABLE');
251
+ });
252
+ it('lists harness presence from enumerateHarnessPresence', async () => {
253
+ enumerateHarnessPresenceMock.mockReturnValue([
254
+ { harness: 'claude-code', present: true, path: '/mock/.claude/skills' },
255
+ { harness: 'cursor', present: false, path: '/mock/.cursor/skills' },
256
+ ]);
257
+ const cap = captureConsole();
258
+ await runStatus();
259
+ const out = cap.log.join('\n');
260
+ expect(out).toContain('claude-code');
261
+ expect(out).toContain('cursor');
262
+ });
263
+ it('shows skill count for present harnesses', async () => {
264
+ enumerateHarnessPresenceMock.mockReturnValue([
265
+ { harness: 'claude-code', present: true, path: '/mock/.claude/skills' },
266
+ ]);
267
+ getInstalledSkillsPerHarnessMock.mockResolvedValue([
268
+ {
269
+ harness: 'claude-code',
270
+ skillId: 'foo/bar',
271
+ version: '1.0.0',
272
+ contentHash: null,
273
+ path: '/mock/foo-bar',
274
+ },
275
+ {
276
+ harness: 'claude-code',
277
+ skillId: 'baz/qux',
278
+ version: null,
279
+ contentHash: null,
280
+ path: '/mock/baz-qux',
281
+ },
282
+ ]);
283
+ const cap = captureConsole();
284
+ await runStatus();
285
+ expect(cap.log.join('\n')).toContain('2 skills');
286
+ });
287
+ it('lists skill IDs under each harness when --verbose is passed', async () => {
288
+ enumerateHarnessPresenceMock.mockReturnValue([
289
+ { harness: 'claude-code', present: true, path: '/mock/.claude/skills' },
290
+ ]);
291
+ getInstalledSkillsPerHarnessMock.mockResolvedValue([
292
+ {
293
+ harness: 'claude-code',
294
+ skillId: 'author/my-skill',
295
+ version: '1.0.0',
296
+ contentHash: null,
297
+ path: '/mock/my-skill',
298
+ },
299
+ ]);
300
+ const cap = captureConsole();
301
+ await runStatus({ verbose: true });
302
+ expect(cap.log.join('\n')).toContain('author/my-skill');
303
+ });
304
+ it('does not list skill IDs when --verbose is not passed', async () => {
305
+ enumerateHarnessPresenceMock.mockReturnValue([
306
+ { harness: 'claude-code', present: true, path: '/mock/.claude/skills' },
307
+ ]);
308
+ getInstalledSkillsPerHarnessMock.mockResolvedValue([
309
+ {
310
+ harness: 'claude-code',
311
+ skillId: 'author/hidden-skill',
312
+ version: null,
313
+ contentHash: null,
314
+ path: '/mock/hidden',
315
+ },
316
+ ]);
317
+ const cap = captureConsole();
318
+ await runStatus({ verbose: false });
319
+ expect(cap.log.join('\n')).not.toContain('author/hidden-skill');
320
+ });
321
+ it('passes through errors from getInstalledSkillsPerHarness to inventoryStatusActionImpl', async () => {
322
+ getInstalledSkillsPerHarnessMock.mockRejectedValue(new Error('disk error'));
323
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((code) => {
324
+ throw new Error(`process.exit(${String(code)})`);
325
+ });
326
+ captureConsole();
327
+ await expect(inventoryStatusActionImpl({})).rejects.toThrow('process.exit(1)');
328
+ expect(exitSpy).toHaveBeenCalledWith(1);
329
+ });
330
+ });
331
+ // ---------------------------------------------------------------------------
332
+ // forget-device
333
+ // ---------------------------------------------------------------------------
334
+ describe('inventory forget-device', () => {
335
+ it('calls core forgetDevice', async () => {
336
+ getDeviceIdMock.mockReturnValue('old-device-uuid');
337
+ captureConsole();
338
+ await runForgetDevice();
339
+ expect(forgetDeviceMock).toHaveBeenCalledTimes(1);
340
+ });
341
+ it('confirms the previous device ID in output', async () => {
342
+ getDeviceIdMock.mockReturnValue('previous-device-abc');
343
+ const cap = captureConsole();
344
+ await runForgetDevice();
345
+ expect(cap.log.join('\n')).toContain('previous-device-abc');
346
+ });
347
+ it('shows "(none)" when there was no device ID to forget', async () => {
348
+ getDeviceIdMock.mockReturnValue(undefined);
349
+ const cap = captureConsole();
350
+ await runForgetDevice();
351
+ expect(cap.log.join('\n')).toContain('(none)');
352
+ });
353
+ it('mentions fresh device on next push', async () => {
354
+ getDeviceIdMock.mockReturnValue('any-device');
355
+ const cap = captureConsole();
356
+ await runForgetDevice();
357
+ expect(cap.log.join('\n')).toContain('fresh device');
358
+ });
359
+ it('passes through errors to inventoryForgetDeviceActionImpl + exit(1)', async () => {
360
+ forgetDeviceMock.mockImplementation(() => {
361
+ throw new Error('config write error');
362
+ });
363
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((code) => {
364
+ throw new Error(`process.exit(${String(code)})`);
365
+ });
366
+ captureConsole();
367
+ await expect(inventoryForgetDeviceActionImpl()).rejects.toThrow('process.exit(1)');
368
+ expect(exitSpy).toHaveBeenCalledWith(1);
369
+ });
370
+ });
371
+ //# sourceMappingURL=inventory.action.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inventory.action.test.js","sourceRoot":"","sources":["../../../src/commands/inventory.action.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @fileoverview `skillsmith inventory` command group — cross-harness inventory management.
3
+ * @module @skillsmith/cli/commands/inventory
4
+ * @see SMI-5392 Wave 3 — CLI `inventory` subcommands (umbrella SMI-5382).
5
+ * @see SMI-5128 sibling-split convention — action impls + withTelemetry wrappers
6
+ * live in inventory.action.ts; this file retains only the commander factory.
7
+ *
8
+ * Subcommands:
9
+ * skillsmith inventory push
10
+ * skillsmith inventory status [--verbose]
11
+ * skillsmith inventory forget-device
12
+ */
13
+ import { Command } from 'commander';
14
+ /**
15
+ * Build and return the `inventory` commander group with its three subcommands.
16
+ *
17
+ * @see SMI-5392
18
+ */
19
+ export declare function createInventoryCommand(): Command;
20
+ export { runPush, runStatus, runForgetDevice, inventoryPushActionImpl, inventoryStatusActionImpl, inventoryForgetDeviceActionImpl, } from './inventory.action.js';
21
+ //# sourceMappingURL=inventory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inventory.d.ts","sourceRoot":"","sources":["../../../src/commands/inventory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAYnC;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAsBhD;AAGD,OAAO,EACL,OAAO,EACP,SAAS,EACT,eAAe,EACf,uBAAuB,EACvB,yBAAyB,EACzB,+BAA+B,GAChC,MAAM,uBAAuB,CAAA"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @fileoverview `skillsmith inventory` command group — cross-harness inventory management.
3
+ * @module @skillsmith/cli/commands/inventory
4
+ * @see SMI-5392 Wave 3 — CLI `inventory` subcommands (umbrella SMI-5382).
5
+ * @see SMI-5128 sibling-split convention — action impls + withTelemetry wrappers
6
+ * live in inventory.action.ts; this file retains only the commander factory.
7
+ *
8
+ * Subcommands:
9
+ * skillsmith inventory push
10
+ * skillsmith inventory status [--verbose]
11
+ * skillsmith inventory forget-device
12
+ */
13
+ import { Command } from 'commander';
14
+ import { inventoryPushAction, inventoryStatusAction, inventoryForgetDeviceAction, } from './inventory.action.js';
15
+ // ---------------------------------------------------------------------------
16
+ // Command factory
17
+ // ---------------------------------------------------------------------------
18
+ /**
19
+ * Build and return the `inventory` commander group with its three subcommands.
20
+ *
21
+ * @see SMI-5392
22
+ */
23
+ export function createInventoryCommand() {
24
+ const inventory = new Command('inventory').description('Manage cross-harness skill inventory sync and device registration');
25
+ inventory
26
+ .command('push')
27
+ .description("Push this device's skill inventory snapshot to the registry")
28
+ .action(inventoryPushAction);
29
+ inventory
30
+ .command('status')
31
+ .description('Show local inventory state (read-only, no network calls)')
32
+ .option('--verbose', 'List individual skill IDs under each harness')
33
+ .action(inventoryStatusAction);
34
+ inventory
35
+ .command('forget-device')
36
+ .description('Clear the local device registration; the next push will create a fresh device')
37
+ .action(inventoryForgetDeviceAction);
38
+ return inventory;
39
+ }
40
+ // Internal exports for tests — sourced from inventory.action.ts (SMI-5128 split).
41
+ export { runPush, runStatus, runForgetDevice, inventoryPushActionImpl, inventoryStatusActionImpl, inventoryForgetDeviceActionImpl, } from './inventory.action.js';
42
+ //# sourceMappingURL=inventory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inventory.js","sourceRoot":"","sources":["../../../src/commands/inventory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,2BAA2B,GAC5B,MAAM,uBAAuB,CAAA;AAE9B,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E;;;;GAIG;AACH,MAAM,UAAU,sBAAsB;IACpC,MAAM,SAAS,GAAG,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC,WAAW,CACpD,mEAAmE,CACpE,CAAA;IAED,SAAS;SACN,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,6DAA6D,CAAC;SAC1E,MAAM,CAAC,mBAAmB,CAAC,CAAA;IAE9B,SAAS;SACN,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,0DAA0D,CAAC;SACvE,MAAM,CAAC,WAAW,EAAE,8CAA8C,CAAC;SACnE,MAAM,CAAC,qBAAqB,CAAC,CAAA;IAEhC,SAAS;SACN,OAAO,CAAC,eAAe,CAAC;SACxB,WAAW,CAAC,+EAA+E,CAAC;SAC5F,MAAM,CAAC,2BAA2B,CAAC,CAAA;IAEtC,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,kFAAkF;AAClF,OAAO,EACL,OAAO,EACP,SAAS,EACT,eAAe,EACf,uBAAuB,EACvB,yBAAyB,EACzB,+BAA+B,GAChC,MAAM,uBAAuB,CAAA"}
package/dist/src/index.js CHANGED
@@ -19,7 +19,7 @@
19
19
  * - setup: Install skillsmith skill for /skillsmith slash command (SMI-824, renamed from install-skill)
20
20
  */
21
21
  import { Command } from 'commander';
22
- import { createSearchCommand, createListCommand, createUpdateCommand, createRemoveCommand, createInitCommand, createValidateCommand, createPublishCommand, createSubagentCommand, createTransformCommand, createMcpInitCommand, createAnalyzeCommand, createRecommendCommand, createSyncCommand, createInstallCommand, createInstallSkillCommand, createLoginCommand, createLogoutCommand, createWhoamiCommand, createDiffCommand, createPinCommand, createUnpinCommand, createAuditCommand, createCreateCommand, createInfoCommand, createImportCommand, createImportLocalCommand, createConfigCommand, createTelemetryCommand, } from './commands/index.js';
22
+ import { createSearchCommand, createListCommand, createUpdateCommand, createRemoveCommand, createInitCommand, createValidateCommand, createPublishCommand, createSubagentCommand, createTransformCommand, createMcpInitCommand, createAnalyzeCommand, createRecommendCommand, createSyncCommand, createInstallCommand, createInstallSkillCommand, createLoginCommand, createLogoutCommand, createWhoamiCommand, createDiffCommand, createPinCommand, createUnpinCommand, createAuditCommand, createCreateCommand, createInfoCommand, createImportCommand, createImportLocalCommand, createConfigCommand, createTelemetryCommand, createInventoryCommand, } from './commands/index.js';
23
23
  import { displayStartupHeader } from './utils/license.js';
24
24
  import { checkNodeVersion } from './utils/node-version.js';
25
25
  import { readFileSync } from 'fs';
@@ -109,5 +109,7 @@ program.addCommand(createInfoCommand());
109
109
  program.addCommand(createConfigCommand());
110
110
  // SMI-5021 Wave 3: telemetry opt-in + Claude Code hook management
111
111
  program.addCommand(createTelemetryCommand());
112
+ // SMI-5392 Wave 3: cross-harness inventory push/status/forget-device
113
+ program.addCommand(createInventoryCommand());
112
114
  program.parse();
113
115
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
@@ -32,6 +32,48 @@ export interface InstalledSkill {
32
32
  * callers can render "installed via Cursor" badges.
33
33
  */
34
34
  export declare function getSkillsFromDirectory(skillsDir: string, dbPath?: string, installedVia?: ClientId | 'local'): Promise<InstalledSkill[]>;
35
+ /**
36
+ * Per-harness/skill entry produced by {@link getInstalledSkillsPerHarness}.
37
+ * Feeds the cross-harness inventory builder (SMI-5390).
38
+ *
39
+ * `contentHash` is the sha256 hex digest of the skill's raw SKILL.md
40
+ * content — used by the inventory service for registry drift detection.
41
+ * It is `null` when SKILL.md is absent or unreadable.
42
+ */
43
+ export interface HarnessSkillEntry {
44
+ /** Which harness directory the skill was found under. */
45
+ harness: ClientId | 'local';
46
+ /**
47
+ * Skill identifier: the `id` front-matter field when present (conventionally
48
+ * `author/name`), falling back to the `name` field, then the directory name.
49
+ */
50
+ skillId: string;
51
+ /** Installed version string, or `null` if absent. */
52
+ version: string | null;
53
+ /** sha256 hex digest of SKILL.md content; `null` if unreadable. */
54
+ contentHash: string | null;
55
+ /** Absolute path to the skill directory. */
56
+ path: string;
57
+ }
58
+ /**
59
+ * Returns one {@link HarnessSkillEntry} per (harness × skill) observed on
60
+ * disk, deduplicated by realpath only.
61
+ *
62
+ * Unlike {@link getInstalledSkills}, this function:
63
+ * - Does **not** deduplicate by skill name — the same skill present under two
64
+ * distinct harness directories appears as two rows (different `path`).
65
+ * - Does deduplicate by realpath — a symlinked alias such as
66
+ * `~/.agents/skills/foo` → `~/.claude/skills/foo` collapses to one row.
67
+ * - Enriches each surviving entry with a sha256 `contentHash` computed from
68
+ * the SKILL.md content, for registry drift detection.
69
+ *
70
+ * Precedence order (first realpath wins when a symlink is detected): local
71
+ * (repo) > claude-code > cursor > copilot > windsurf > agents. Inherits the
72
+ * SMI-4578 ordering so local overrides are still respected.
73
+ *
74
+ * @see SMI-5390
75
+ */
76
+ export declare function getInstalledSkillsPerHarness(): Promise<HarnessSkillEntry[]>;
35
77
  /**
36
78
  * Get list of installed skills across every client directory.
37
79
  *
@@ -1 +1 @@
1
- {"version":3,"file":"skills-directory.d.ts","sourceRoot":"","sources":["../../../src/utils/skills-directory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAIL,KAAK,SAAS,EACf,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAIL,KAAK,QAAQ,EACd,MAAM,0BAA0B,CAAA;AAGjC,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,SAAS,EAAE,SAAS,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,OAAO,CAAA;IACnB;;;;OAIG;IACH,YAAY,EAAE,QAAQ,GAAG,OAAO,CAAA;CACjC;AAiBD;;;;;;;;;;;;GAYG;AACH,wBAAsB,sBAAsB,CAC1C,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,MAAM,EACf,YAAY,GAAE,QAAQ,GAAG,OAA0B,GAClD,OAAO,CAAC,cAAc,EAAE,CAAC,CAsG3B;AAgBD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAwCnF"}
1
+ {"version":3,"file":"skills-directory.d.ts","sourceRoot":"","sources":["../../../src/utils/skills-directory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAIL,KAAK,SAAS,EACf,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAIL,KAAK,QAAQ,EACd,MAAM,0BAA0B,CAAA;AAGjC,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,SAAS,EAAE,SAAS,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,OAAO,CAAA;IACnB;;;;OAIG;IACH,YAAY,EAAE,QAAQ,GAAG,OAAO,CAAA;CACjC;AAiBD;;;;;;;;;;;;GAYG;AACH,wBAAsB,sBAAsB,CAC1C,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,MAAM,EACf,YAAY,GAAE,QAAQ,GAAG,OAA0B,GAClD,OAAO,CAAC,cAAc,EAAE,CAAC,CAsG3B;AAgBD;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAChC,yDAAyD;IACzD,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAA;IAC3B;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAA;IACf,qDAAqD;IACrD,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,mEAAmE;IACnE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAA;CACb;AAuBD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAyCjF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAwCnF"}
@@ -148,6 +148,82 @@ async function safeRealpath(p) {
148
148
  return p;
149
149
  }
150
150
  }
151
+ /**
152
+ * Reads `<skillPath>/SKILL.md`, returns its sha256 hex content hash and the
153
+ * `id` front-matter field. Both are `null` on any read/parse error.
154
+ * @internal
155
+ */
156
+ async function readSkillMd(skillPath) {
157
+ try {
158
+ const content = await readFile(join(skillPath, 'SKILL.md'), 'utf-8');
159
+ const contentHash = createHash('sha256').update(content, 'utf8').digest('hex');
160
+ const parser = new SkillParser();
161
+ const parsed = parser.parse(content);
162
+ const parsedAny = parsed;
163
+ const skillId = parsedAny['id'] ?? null;
164
+ return { contentHash, skillId };
165
+ }
166
+ catch {
167
+ return { contentHash: null, skillId: null };
168
+ }
169
+ }
170
+ /**
171
+ * Returns one {@link HarnessSkillEntry} per (harness × skill) observed on
172
+ * disk, deduplicated by realpath only.
173
+ *
174
+ * Unlike {@link getInstalledSkills}, this function:
175
+ * - Does **not** deduplicate by skill name — the same skill present under two
176
+ * distinct harness directories appears as two rows (different `path`).
177
+ * - Does deduplicate by realpath — a symlinked alias such as
178
+ * `~/.agents/skills/foo` → `~/.claude/skills/foo` collapses to one row.
179
+ * - Enriches each surviving entry with a sha256 `contentHash` computed from
180
+ * the SKILL.md content, for registry drift detection.
181
+ *
182
+ * Precedence order (first realpath wins when a symlink is detected): local
183
+ * (repo) > claude-code > cursor > copilot > windsurf > agents. Inherits the
184
+ * SMI-4578 ordering so local overrides are still respected.
185
+ *
186
+ * @see SMI-5390
187
+ */
188
+ export async function getInstalledSkillsPerHarness() {
189
+ const localScan = getSkillsFromDirectory(getLocalSkillsDir(), undefined, 'local');
190
+ const clientScans = CLIENT_IDS.map((client) => getSkillsFromDirectory(CLIENT_NATIVE_PATHS[client], undefined, client));
191
+ const [localSkills, ...clientSkillsLists] = await Promise.all([localScan, ...clientScans]);
192
+ // Same precedence order as getInstalledSkills — local first, then
193
+ // canonical, then remaining clients.
194
+ const ordered = [...localSkills];
195
+ const canonicalIdx = CLIENT_IDS.indexOf(CANONICAL_CLIENT);
196
+ if (canonicalIdx >= 0 && clientSkillsLists[canonicalIdx]) {
197
+ ordered.push(...clientSkillsLists[canonicalIdx]);
198
+ }
199
+ for (let i = 0; i < CLIENT_IDS.length; i++) {
200
+ if (i === canonicalIdx)
201
+ continue;
202
+ const list = clientSkillsLists[i];
203
+ if (list)
204
+ ordered.push(...list);
205
+ }
206
+ // Realpath-only dedup: collapses symlinked aliases (same inode) but keeps
207
+ // the same skill independently installed under two different harnesses as
208
+ // two distinct rows.
209
+ const seenPaths = new Set();
210
+ const out = [];
211
+ for (const skill of ordered) {
212
+ const rp = await safeRealpath(skill.path);
213
+ if (seenPaths.has(rp))
214
+ continue;
215
+ seenPaths.add(rp);
216
+ const { contentHash, skillId: parsedId } = await readSkillMd(skill.path);
217
+ out.push({
218
+ harness: skill.installedVia,
219
+ skillId: parsedId ?? skill.name,
220
+ version: skill.version,
221
+ contentHash,
222
+ path: skill.path,
223
+ });
224
+ }
225
+ return out;
226
+ }
151
227
  /**
152
228
  * Get list of installed skills across every client directory.
153
229
  *