@skillshub-labs/cli 0.1.17 → 0.1.19

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 (28) hide show
  1. package/README.md +28 -12
  2. package/bin/skills-hub +193 -15
  3. package/data/official-presets/catalog.json +436 -0
  4. package/data/official-presets/policies/policy-azure-cloud.md +18 -0
  5. package/data/official-presets/policies/policy-cloudflare-edge.md +18 -0
  6. package/data/official-presets/policies/policy-fastapi-py.md +31 -0
  7. package/data/official-presets/policies/policy-fullstack-web.md +24 -0
  8. package/data/official-presets/policies/policy-go-service.md +31 -0
  9. package/data/official-presets/policies/policy-hf-ml.md +18 -0
  10. package/data/official-presets/policies/policy-langchain-apps.md +18 -0
  11. package/data/official-presets/policies/policy-literature-review.md +18 -0
  12. package/data/official-presets/policies/policy-monorepo-turbo.md +31 -0
  13. package/data/official-presets/policies/policy-nextjs-ts-strict.md +31 -0
  14. package/data/official-presets/policies/policy-node-api-ts.md +31 -0
  15. package/data/official-presets/policies/policy-python-api.md +18 -0
  16. package/data/official-presets/policies/policy-release-ci.md +18 -0
  17. package/data/official-presets/policies/policy-release-maintainer.md +31 -0
  18. package/data/official-presets/policies/policy-scientific-discovery.md +18 -0
  19. package/data/official-presets/policies/policy-scientific-python.md +31 -0
  20. package/data/official-presets/policies/policy-security-audit.md +18 -0
  21. package/data/official-presets/policies/policy-web-frontend.md +18 -0
  22. package/lib/core/kit-core.d.ts +14 -3
  23. package/lib/core/kit-core.mjs +327 -20
  24. package/lib/core/kit-types.ts +128 -3
  25. package/lib/services/kit-loadout-import.mjs +599 -0
  26. package/lib/services/kit-service.d.ts +90 -2
  27. package/lib/services/kit-service.mjs +665 -38
  28. package/package.json +9 -1
@@ -29,6 +29,7 @@ function ensureDb() {
29
29
  id TEXT PRIMARY KEY,
30
30
  name TEXT NOT NULL,
31
31
  description TEXT,
32
+ import_source_json TEXT,
32
33
  created_at INTEGER NOT NULL,
33
34
  updated_at INTEGER NOT NULL
34
35
  );
@@ -50,6 +51,7 @@ function ensureDb() {
50
51
  description TEXT,
51
52
  policy_id TEXT NOT NULL,
52
53
  loadout_id TEXT NOT NULL,
54
+ managed_source_json TEXT,
53
55
  last_applied_at INTEGER,
54
56
  last_applied_target_json TEXT,
55
57
  created_at INTEGER NOT NULL,
@@ -62,10 +64,21 @@ function ensureDb() {
62
64
  CREATE INDEX IF NOT EXISTS idx_kit_presets_loadout_id
63
65
  ON kit_presets(loadout_id);
64
66
  `)
67
+ ensureColumn(dbInstance, 'kit_loadouts', 'import_source_json', 'TEXT')
68
+ ensureColumn(dbInstance, 'kit_presets', 'managed_source_json', 'TEXT')
65
69
 
66
70
  return dbInstance
67
71
  }
68
72
 
73
+ function ensureColumn(db, tableName, columnName, definition) {
74
+ const columns = db.prepare(`PRAGMA table_info(${tableName})`).all()
75
+ if (columns.some((column) => column?.name === columnName)) {
76
+ return
77
+ }
78
+
79
+ db.exec(`ALTER TABLE ${tableName} ADD COLUMN ${columnName} ${definition}`)
80
+ }
81
+
69
82
  function getDbPath() {
70
83
  return DB_PATH
71
84
  }
@@ -102,6 +115,193 @@ function toOptionalText(value) {
102
115
  return normalized || undefined
103
116
  }
104
117
 
118
+ function normalizeLoadoutImportSource(value) {
119
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
120
+ return undefined
121
+ }
122
+
123
+ const repoWebUrl = String(value.repoWebUrl || '').trim()
124
+ const repoUrl = String(value.repoUrl || '').trim()
125
+ const originalUrl = String(value.originalUrl || '').trim()
126
+ const branch = toOptionalText(value.branch)
127
+ const rootSubdir = String(value.rootSubdir || '').trim() || '/'
128
+ const importedAt = String(value.importedAt || '').trim()
129
+ const lastSourceUpdatedAt = String(value.lastSourceUpdatedAt || '').trim()
130
+ const lastSafetyCheck = normalizeKitSafetyCheck(value.lastSafetyCheck)
131
+
132
+ if (!repoWebUrl || !repoUrl || !originalUrl || !importedAt || !lastSourceUpdatedAt) {
133
+ return undefined
134
+ }
135
+
136
+ return {
137
+ repoWebUrl,
138
+ repoUrl,
139
+ originalUrl,
140
+ branch,
141
+ rootSubdir,
142
+ importedAt,
143
+ lastSourceUpdatedAt,
144
+ lastSafetyCheck,
145
+ }
146
+ }
147
+
148
+ function normalizeKitSafetyCheck(value) {
149
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
150
+ return undefined
151
+ }
152
+
153
+ const checkedAt = Number(value.checkedAt)
154
+ const status = value.status === 'warn' ? 'warn' : 'pass'
155
+ const scannedFiles = Number(value.scannedFiles)
156
+ const warnings = Array.isArray(value.warnings)
157
+ ? value.warnings.map((entry) => String(entry || '').trim()).filter(Boolean)
158
+ : []
159
+ const flaggedFiles = Array.isArray(value.flaggedFiles)
160
+ ? value.flaggedFiles.map((entry) => String(entry || '').trim()).filter(Boolean)
161
+ : []
162
+
163
+ if (!Number.isFinite(checkedAt) || !Number.isFinite(scannedFiles)) {
164
+ return undefined
165
+ }
166
+
167
+ return {
168
+ checkedAt,
169
+ status,
170
+ scannedFiles,
171
+ warnings,
172
+ flaggedFiles,
173
+ }
174
+ }
175
+
176
+ function normalizeManagedPolicyBaseline(value) {
177
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
178
+ return undefined
179
+ }
180
+
181
+ const id = String(value.id || '').trim()
182
+ const name = String(value.name || '').trim()
183
+ const content = String(value.content || '').trim()
184
+ const description = toOptionalText(value.description)
185
+
186
+ if (!id || !name || !content) {
187
+ return undefined
188
+ }
189
+
190
+ return {
191
+ id,
192
+ name,
193
+ description,
194
+ content,
195
+ }
196
+ }
197
+
198
+ function normalizeManagedLoadoutBaseline(value) {
199
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
200
+ return undefined
201
+ }
202
+
203
+ const id = String(value.id || '').trim()
204
+ const name = String(value.name || '').trim()
205
+ const description = toOptionalText(value.description)
206
+ const items = normalizeLoadoutItems(value.items || [])
207
+
208
+ if (!id || !name || items.length === 0) {
209
+ return undefined
210
+ }
211
+
212
+ return {
213
+ id,
214
+ name,
215
+ description,
216
+ items,
217
+ }
218
+ }
219
+
220
+ function normalizeManagedSecurityChecks(value) {
221
+ if (!Array.isArray(value)) {
222
+ return []
223
+ }
224
+
225
+ return value
226
+ .map((entry) => {
227
+ if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
228
+ return null
229
+ }
230
+
231
+ const sourceId = String(entry.sourceId || '').trim()
232
+ const sourceName = String(entry.sourceName || '').trim()
233
+ const check = normalizeKitSafetyCheck(entry.check)
234
+ if (!sourceId || !sourceName || !check) {
235
+ return null
236
+ }
237
+
238
+ return {
239
+ sourceId,
240
+ sourceName,
241
+ check,
242
+ }
243
+ })
244
+ .filter(Boolean)
245
+ }
246
+
247
+ function normalizeManagedSource(value) {
248
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
249
+ return undefined
250
+ }
251
+
252
+ if (String(value.kind || '').trim() !== 'official_preset') {
253
+ return undefined
254
+ }
255
+
256
+ const presetId = String(value.presetId || '').trim()
257
+ const presetName = String(value.presetName || '').trim()
258
+ const catalogVersion = Number(value.catalogVersion)
259
+ const installedAt = Number(value.installedAt)
260
+ const lastRestoredAt = value.lastRestoredAt == null ? undefined : Number(value.lastRestoredAt)
261
+ const restoreCount = Number(value.restoreCount)
262
+ const baseline = value.baseline
263
+
264
+ if (!baseline || typeof baseline !== 'object' || Array.isArray(baseline)) {
265
+ return undefined
266
+ }
267
+
268
+ const name = String(baseline.name || '').trim()
269
+ const description = toOptionalText(baseline.description)
270
+ const policy = normalizeManagedPolicyBaseline(baseline.policy)
271
+ const loadout = normalizeManagedLoadoutBaseline(baseline.loadout)
272
+ const securityChecks = normalizeManagedSecurityChecks(value.securityChecks)
273
+
274
+ if (
275
+ !presetId ||
276
+ !presetName ||
277
+ !name ||
278
+ !policy ||
279
+ !loadout ||
280
+ !Number.isFinite(catalogVersion) ||
281
+ !Number.isFinite(installedAt) ||
282
+ !Number.isFinite(restoreCount)
283
+ ) {
284
+ return undefined
285
+ }
286
+
287
+ return {
288
+ kind: 'official_preset',
289
+ presetId,
290
+ presetName,
291
+ catalogVersion,
292
+ installedAt,
293
+ lastRestoredAt: Number.isFinite(lastRestoredAt) ? lastRestoredAt : undefined,
294
+ restoreCount,
295
+ baseline: {
296
+ name,
297
+ description,
298
+ policy,
299
+ loadout,
300
+ },
301
+ securityChecks,
302
+ }
303
+ }
304
+
105
305
  function normalizeLoadoutItems(items) {
106
306
  if (!Array.isArray(items)) {
107
307
  throw new Error('Skills package items must be an array')
@@ -157,6 +357,7 @@ function parseLoadoutRow(row, items) {
157
357
  name: row.name,
158
358
  description: row.description || undefined,
159
359
  items,
360
+ importSource: normalizeLoadoutImportSource(parseJsonSafe(row.import_source_json, undefined)),
160
361
  createdAt: row.created_at,
161
362
  updatedAt: row.updated_at,
162
363
  }
@@ -168,12 +369,13 @@ function parseKitRow(row) {
168
369
  id: row.id,
169
370
  name: row.name,
170
371
  description: row.description || undefined,
171
- policyId: row.policy_id,
172
- loadoutId: row.loadout_id,
372
+ policyId: row.policy_id || undefined,
373
+ loadoutId: row.loadout_id || undefined,
173
374
  lastAppliedAt: row.last_applied_at || undefined,
174
375
  lastAppliedTarget: row.last_applied_target_json
175
376
  ? parseJsonSafe(row.last_applied_target_json, undefined)
176
377
  : undefined,
378
+ managedSource: normalizeManagedSource(parseJsonSafe(row.managed_source_json, undefined)),
177
379
  createdAt: row.created_at,
178
380
  updatedAt: row.updated_at,
179
381
  }
@@ -302,7 +504,7 @@ function listKitLoadouts() {
302
504
  const db = ensureDb()
303
505
  const rows = db
304
506
  .prepare(
305
- `SELECT id, name, description, created_at, updated_at
507
+ `SELECT id, name, description, import_source_json, created_at, updated_at
306
508
  FROM kit_loadouts
307
509
  ORDER BY updated_at DESC, name ASC`
308
510
  )
@@ -316,7 +518,7 @@ function getKitLoadoutById(id) {
316
518
  const db = ensureDb()
317
519
  const row = db
318
520
  .prepare(
319
- `SELECT id, name, description, created_at, updated_at
521
+ `SELECT id, name, description, import_source_json, created_at, updated_at
320
522
  FROM kit_loadouts
321
523
  WHERE id = ?`
322
524
  )
@@ -335,12 +537,13 @@ function addKitLoadout(input) {
335
537
  const items = normalizeLoadoutItems(input?.items || [])
336
538
 
337
539
  db.prepare(
338
- `INSERT INTO kit_loadouts (id, name, description, created_at, updated_at)
339
- VALUES (@id, @name, @description, @createdAt, @updatedAt)`
540
+ `INSERT INTO kit_loadouts (id, name, description, import_source_json, created_at, updated_at)
541
+ VALUES (@id, @name, @description, @importSourceJson, @createdAt, @updatedAt)`
340
542
  ).run({
341
543
  id,
342
544
  name,
343
545
  description: toOptionalText(input?.description) || null,
546
+ importSourceJson: JSON.stringify(normalizeLoadoutImportSource(input?.importSource) || null),
344
547
  createdAt: ts,
345
548
  updatedAt: ts,
346
549
  })
@@ -384,12 +587,17 @@ function updateKitLoadout(input) {
384
587
  ? existing.description || null
385
588
  : toOptionalText(input.description) || null
386
589
  const nextItems = input?.items === undefined ? existing.items : normalizeLoadoutItems(input.items)
590
+ const nextImportSource =
591
+ input?.importSource === undefined
592
+ ? existing.importSource || null
593
+ : normalizeLoadoutImportSource(input.importSource) || null
387
594
 
388
595
  const db = ensureDb()
389
596
  const updateLoadout = db.prepare(
390
597
  `UPDATE kit_loadouts
391
598
  SET name = @name,
392
599
  description = @description,
600
+ import_source_json = @importSourceJson,
393
601
  updated_at = @updatedAt
394
602
  WHERE id = @id`
395
603
  )
@@ -404,6 +612,7 @@ function updateKitLoadout(input) {
404
612
  id,
405
613
  name: nextName,
406
614
  description: nextDescription,
615
+ importSourceJson: JSON.stringify(nextImportSource),
407
616
  updatedAt: nowTs(),
408
617
  })
409
618
 
@@ -448,7 +657,7 @@ function listKits() {
448
657
  const db = ensureDb()
449
658
  const rows = db
450
659
  .prepare(
451
- `SELECT id, name, description, policy_id, loadout_id, last_applied_at, last_applied_target_json,
660
+ `SELECT id, name, description, policy_id, loadout_id, managed_source_json, last_applied_at, last_applied_target_json,
452
661
  created_at, updated_at
453
662
  FROM kit_presets
454
663
  ORDER BY updated_at DESC, name ASC`
@@ -462,7 +671,7 @@ function getKitById(id) {
462
671
  const db = ensureDb()
463
672
  const row = db
464
673
  .prepare(
465
- `SELECT id, name, description, policy_id, loadout_id, last_applied_at, last_applied_target_json,
674
+ `SELECT id, name, description, policy_id, loadout_id, managed_source_json, last_applied_at, last_applied_target_json,
466
675
  created_at, updated_at
467
676
  FROM kit_presets
468
677
  WHERE id = ?`
@@ -472,11 +681,11 @@ function getKitById(id) {
472
681
  }
473
682
 
474
683
  function ensureKitRefsExist(policyId, loadoutId) {
475
- if (!getKitPolicyById(policyId)) {
684
+ if (policyId && !getKitPolicyById(policyId)) {
476
685
  throw new Error(`AGENTS.md not found: ${policyId}`)
477
686
  }
478
687
 
479
- if (!getKitLoadoutById(loadoutId)) {
688
+ if (loadoutId && !getKitLoadoutById(loadoutId)) {
480
689
  throw new Error(`Skills package not found: ${loadoutId}`)
481
690
  }
482
691
  }
@@ -489,24 +698,25 @@ function addKit(input) {
489
698
  const name = requireName(input?.name, 'kit name')
490
699
  const policyId = String(input?.policyId || '').trim()
491
700
  const loadoutId = String(input?.loadoutId || '').trim()
492
- if (!policyId || !loadoutId) {
493
- throw new Error('Kit must include both AGENTS.md and Skills package')
701
+ if (!policyId && !loadoutId) {
702
+ throw new Error('Kit must include at least AGENTS.md or Skills package')
494
703
  }
495
704
 
496
705
  ensureKitRefsExist(policyId, loadoutId)
497
706
 
498
707
  db.prepare(
499
708
  `INSERT INTO kit_presets (
500
- id, name, description, policy_id, loadout_id, created_at, updated_at
709
+ id, name, description, policy_id, loadout_id, managed_source_json, created_at, updated_at
501
710
  ) VALUES (
502
- @id, @name, @description, @policyId, @loadoutId, @createdAt, @updatedAt
711
+ @id, @name, @description, @policyId, @loadoutId, @managedSourceJson, @createdAt, @updatedAt
503
712
  )`
504
713
  ).run({
505
714
  id,
506
715
  name,
507
716
  description: toOptionalText(input?.description) || null,
508
- policyId,
509
- loadoutId,
717
+ policyId: policyId || '',
718
+ loadoutId: loadoutId || '',
719
+ managedSourceJson: JSON.stringify(normalizeManagedSource(input?.managedSource) || null),
510
720
  createdAt: ts,
511
721
  updatedAt: ts,
512
722
  })
@@ -534,9 +744,13 @@ function updateKit(input) {
534
744
  input?.policyId === undefined ? existing.policyId : String(input.policyId || '').trim()
535
745
  const nextLoadoutId =
536
746
  input?.loadoutId === undefined ? existing.loadoutId : String(input.loadoutId || '').trim()
747
+ const nextManagedSource =
748
+ input?.managedSource === undefined
749
+ ? existing.managedSource || null
750
+ : normalizeManagedSource(input.managedSource) || null
537
751
 
538
- if (!nextPolicyId || !nextLoadoutId) {
539
- throw new Error('Kit must include both AGENTS.md and Skills package')
752
+ if (!nextPolicyId && !nextLoadoutId) {
753
+ throw new Error('Kit must include at least AGENTS.md or Skills package')
540
754
  }
541
755
 
542
756
  ensureKitRefsExist(nextPolicyId, nextLoadoutId)
@@ -548,14 +762,16 @@ function updateKit(input) {
548
762
  description = @description,
549
763
  policy_id = @policyId,
550
764
  loadout_id = @loadoutId,
765
+ managed_source_json = @managedSourceJson,
551
766
  updated_at = @updatedAt
552
767
  WHERE id = @id`
553
768
  ).run({
554
769
  id,
555
770
  name: nextName,
556
771
  description: nextDescription,
557
- policyId: nextPolicyId,
558
- loadoutId: nextLoadoutId,
772
+ policyId: nextPolicyId || '',
773
+ loadoutId: nextLoadoutId || '',
774
+ managedSourceJson: JSON.stringify(nextManagedSource),
559
775
  updatedAt: nowTs(),
560
776
  })
561
777
 
@@ -569,6 +785,96 @@ function deleteKit(id) {
569
785
  return result.changes > 0
570
786
  }
571
787
 
788
+ function upsertPolicyBaseline(db, baseline, updatedAt) {
789
+ const existing = getKitPolicyById(baseline.id)
790
+ db.prepare(
791
+ `INSERT OR REPLACE INTO kit_policies (id, name, description, content, created_at, updated_at)
792
+ VALUES (@id, @name, @description, @content, @createdAt, @updatedAt)`
793
+ ).run({
794
+ id: baseline.id,
795
+ name: baseline.name,
796
+ description: baseline.description || null,
797
+ content: baseline.content,
798
+ createdAt: existing?.createdAt || updatedAt,
799
+ updatedAt,
800
+ })
801
+ }
802
+
803
+ function upsertLoadoutBaseline(db, baseline, updatedAt) {
804
+ const existing = getKitLoadoutById(baseline.id)
805
+ db.prepare(
806
+ `INSERT OR REPLACE INTO kit_loadouts (id, name, description, import_source_json, created_at, updated_at)
807
+ VALUES (@id, @name, @description, @importSourceJson, @createdAt, @updatedAt)`
808
+ ).run({
809
+ id: baseline.id,
810
+ name: baseline.name,
811
+ description: baseline.description || null,
812
+ importSourceJson: JSON.stringify(null),
813
+ createdAt: existing?.createdAt || updatedAt,
814
+ updatedAt,
815
+ })
816
+
817
+ db.prepare(`DELETE FROM kit_loadout_items WHERE loadout_id = ?`).run(baseline.id)
818
+ const insertItem = db.prepare(
819
+ `INSERT INTO kit_loadout_items (loadout_id, skill_path, mode, sort_order)
820
+ VALUES (@loadoutId, @skillPath, @mode, @sortOrder)`
821
+ )
822
+
823
+ for (const item of baseline.items) {
824
+ insertItem.run({
825
+ loadoutId: baseline.id,
826
+ skillPath: item.skillPath,
827
+ mode: item.mode,
828
+ sortOrder: item.sortOrder,
829
+ })
830
+ }
831
+ }
832
+
833
+ function restoreManagedKitBaseline(id) {
834
+ const existing = getKitById(id)
835
+ if (!existing) {
836
+ throw new Error(`Kit not found: ${id}`)
837
+ }
838
+ if (!existing.managedSource || existing.managedSource.kind !== 'official_preset') {
839
+ throw new Error('Only managed official kits can be restored')
840
+ }
841
+
842
+ const db = ensureDb()
843
+ const ts = nowTs()
844
+ const { baseline } = existing.managedSource
845
+ const nextManagedSource = {
846
+ ...existing.managedSource,
847
+ lastRestoredAt: ts,
848
+ restoreCount: Number(existing.managedSource.restoreCount || 0) + 1,
849
+ }
850
+
851
+ const tx = db.transaction(() => {
852
+ upsertPolicyBaseline(db, baseline.policy, ts)
853
+ upsertLoadoutBaseline(db, baseline.loadout, ts)
854
+ db.prepare(
855
+ `UPDATE kit_presets
856
+ SET name = @name,
857
+ description = @description,
858
+ policy_id = @policyId,
859
+ loadout_id = @loadoutId,
860
+ managed_source_json = @managedSourceJson,
861
+ updated_at = @updatedAt
862
+ WHERE id = @id`
863
+ ).run({
864
+ id,
865
+ name: baseline.name,
866
+ description: baseline.description || null,
867
+ policyId: baseline.policy.id,
868
+ loadoutId: baseline.loadout.id,
869
+ managedSourceJson: JSON.stringify(nextManagedSource),
870
+ updatedAt: ts,
871
+ })
872
+ })
873
+
874
+ tx()
875
+ return getKitById(id)
876
+ }
877
+
572
878
  function markKitApplied(input) {
573
879
  const id = String(input?.id || '').trim()
574
880
  if (!id) {
@@ -622,5 +928,6 @@ export {
622
928
  addKit,
623
929
  updateKit,
624
930
  deleteKit,
931
+ restoreManagedKitBaseline,
625
932
  markKitApplied,
626
933
  }
@@ -6,11 +6,23 @@ export interface KitLoadoutItem {
6
6
  sortOrder: number
7
7
  }
8
8
 
9
+ export interface KitLoadoutImportSource {
10
+ repoWebUrl: string
11
+ repoUrl: string
12
+ originalUrl: string
13
+ branch?: string
14
+ rootSubdir: string
15
+ importedAt: string
16
+ lastSourceUpdatedAt: string
17
+ lastSafetyCheck?: KitSafetyCheck
18
+ }
19
+
9
20
  export interface KitLoadoutRecord {
10
21
  id: string
11
22
  name: string
12
23
  description?: string
13
24
  items: KitLoadoutItem[]
25
+ importSource?: KitLoadoutImportSource
14
26
  createdAt: number
15
27
  updatedAt: number
16
28
  }
@@ -24,17 +36,63 @@ export interface KitPolicyRecord {
24
36
  updatedAt: number
25
37
  }
26
38
 
39
+ export interface KitSafetyCheck {
40
+ checkedAt: number
41
+ status: 'pass' | 'warn'
42
+ scannedFiles: number
43
+ warnings: string[]
44
+ flaggedFiles: string[]
45
+ }
46
+
47
+ export interface ManagedKitPolicyBaseline {
48
+ id: string
49
+ name: string
50
+ description?: string
51
+ content: string
52
+ }
53
+
54
+ export interface ManagedKitLoadoutBaseline {
55
+ id: string
56
+ name: string
57
+ description?: string
58
+ items: KitLoadoutItem[]
59
+ }
60
+
61
+ export interface ManagedKitSecurityCheck {
62
+ sourceId: string
63
+ sourceName: string
64
+ check: KitSafetyCheck
65
+ }
66
+
67
+ export interface ManagedKitSource {
68
+ kind: 'official_preset'
69
+ presetId: string
70
+ presetName: string
71
+ catalogVersion: number
72
+ installedAt: number
73
+ lastRestoredAt?: number
74
+ restoreCount: number
75
+ baseline: {
76
+ name: string
77
+ description?: string
78
+ policy: ManagedKitPolicyBaseline
79
+ loadout: ManagedKitLoadoutBaseline
80
+ }
81
+ securityChecks: ManagedKitSecurityCheck[]
82
+ }
83
+
27
84
  export interface KitRecord {
28
85
  id: string
29
86
  name: string
30
87
  description?: string
31
- policyId: string
32
- loadoutId: string
88
+ policyId?: string
89
+ loadoutId?: string
33
90
  lastAppliedAt?: number
34
91
  lastAppliedTarget?: {
35
92
  projectPath: string
36
93
  agentName: string
37
94
  }
95
+ managedSource?: ManagedKitSource
38
96
  createdAt: number
39
97
  updatedAt: number
40
98
  }
@@ -50,10 +108,77 @@ export interface KitApplySkillResult {
50
108
  export interface KitApplyResult {
51
109
  kitId: string
52
110
  kitName: string
53
- policyPath: string
111
+ policyPath?: string
112
+ policyFileName?: string
54
113
  projectPath: string
55
114
  agentName: string
56
115
  appliedAt: number
57
116
  overwroteAgentsMd?: boolean
58
117
  loadoutResults: KitApplySkillResult[]
59
118
  }
119
+
120
+ export interface KitLoadoutImportResult {
121
+ loadout: KitLoadoutRecord
122
+ loadoutStatus: 'created' | 'updated'
123
+ importedSkillPaths: string[]
124
+ overwrittenCount: number
125
+ removedCount: number
126
+ discoveredCount: number
127
+ source: KitLoadoutImportSource
128
+ }
129
+
130
+ export interface OfficialPresetSummary {
131
+ id: string
132
+ name: string
133
+ description?: string
134
+ policyName: string
135
+ sourceCount: number
136
+ skillCount: number
137
+ }
138
+
139
+ export interface OfficialPresetSource {
140
+ id: string
141
+ name: string
142
+ url: string
143
+ description?: string
144
+ selectedSkillDetails?: Array<{
145
+ name: string
146
+ description?: string
147
+ }>
148
+ selectedSkills: string[]
149
+ }
150
+
151
+ export interface OfficialPresetDetail {
152
+ id: string
153
+ name: string
154
+ description?: string
155
+ policy: {
156
+ name: string
157
+ description?: string
158
+ template: string
159
+ }
160
+ sources: OfficialPresetSource[]
161
+ skillCount: number
162
+ }
163
+
164
+ export interface OfficialPresetInstallResult {
165
+ preset: {
166
+ id: string
167
+ name: string
168
+ description?: string
169
+ }
170
+ policy: KitPolicyRecord
171
+ loadout: KitLoadoutRecord
172
+ kit: KitRecord
173
+ importedSources: Array<{
174
+ id: string
175
+ name: string
176
+ loadoutId: string
177
+ importedSkillCount: number
178
+ selectedSkillCount: number
179
+ }>
180
+ }
181
+
182
+ export interface OfficialPresetBatchInstallResult {
183
+ installed: OfficialPresetInstallResult[]
184
+ }