specweave 1.0.271 → 1.0.273

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 (138) hide show
  1. package/CLAUDE.md +28 -28
  2. package/bin/specweave.js +13 -0
  3. package/dist/dashboard/assets/index-BKdLA_6x.js +11 -0
  4. package/dist/dashboard/assets/index-Cs3Zq6E2.css +1 -0
  5. package/dist/dashboard/index.html +2 -2
  6. package/dist/src/cli/commands/detect-intent.js +1 -1
  7. package/dist/src/cli/commands/detect-intent.js.map +1 -1
  8. package/dist/src/cli/commands/judge-skill.d.ts.map +1 -1
  9. package/dist/src/cli/commands/judge-skill.js +11 -0
  10. package/dist/src/cli/commands/judge-skill.js.map +1 -1
  11. package/dist/src/cli/commands/migrate-to-umbrella.d.ts.map +1 -1
  12. package/dist/src/cli/commands/migrate-to-umbrella.js +97 -2
  13. package/dist/src/cli/commands/migrate-to-umbrella.js.map +1 -1
  14. package/dist/src/cli/commands/migrate-to-vskill.d.ts +43 -0
  15. package/dist/src/cli/commands/migrate-to-vskill.d.ts.map +1 -0
  16. package/dist/src/cli/commands/migrate-to-vskill.js +144 -0
  17. package/dist/src/cli/commands/migrate-to-vskill.js.map +1 -0
  18. package/dist/src/cli/commands/refresh-marketplace.d.ts +4 -23
  19. package/dist/src/cli/commands/refresh-marketplace.d.ts.map +1 -1
  20. package/dist/src/cli/commands/refresh-marketplace.js +15 -1061
  21. package/dist/src/cli/commands/refresh-marketplace.js.map +1 -1
  22. package/dist/src/cli/commands/refresh-plugins.d.ts +28 -0
  23. package/dist/src/cli/commands/refresh-plugins.d.ts.map +1 -0
  24. package/dist/src/cli/commands/refresh-plugins.js +272 -0
  25. package/dist/src/cli/commands/refresh-plugins.js.map +1 -0
  26. package/dist/src/cli/commands/uninstall.d.ts +11 -0
  27. package/dist/src/cli/commands/uninstall.d.ts.map +1 -0
  28. package/dist/src/cli/commands/uninstall.js +164 -0
  29. package/dist/src/cli/commands/uninstall.js.map +1 -0
  30. package/dist/src/cli/helpers/init/claude-plugin-enabler.d.ts +6 -2
  31. package/dist/src/cli/helpers/init/claude-plugin-enabler.d.ts.map +1 -1
  32. package/dist/src/cli/helpers/init/claude-plugin-enabler.js +6 -2
  33. package/dist/src/cli/helpers/init/claude-plugin-enabler.js.map +1 -1
  34. package/dist/src/cli/helpers/init/instruction-file-merger.d.ts +5 -0
  35. package/dist/src/cli/helpers/init/instruction-file-merger.d.ts.map +1 -1
  36. package/dist/src/cli/helpers/init/instruction-file-merger.js +18 -0
  37. package/dist/src/cli/helpers/init/instruction-file-merger.js.map +1 -1
  38. package/dist/src/cli/helpers/init/plugin-installer.d.ts +1 -1
  39. package/dist/src/cli/helpers/init/plugin-installer.d.ts.map +1 -1
  40. package/dist/src/cli/helpers/init/plugin-installer.js +98 -364
  41. package/dist/src/cli/helpers/init/plugin-installer.js.map +1 -1
  42. package/dist/src/cli/workers/marketplace-scanner-worker.d.ts +73 -0
  43. package/dist/src/cli/workers/marketplace-scanner-worker.d.ts.map +1 -0
  44. package/dist/src/cli/workers/marketplace-scanner-worker.js +405 -0
  45. package/dist/src/cli/workers/marketplace-scanner-worker.js.map +1 -0
  46. package/dist/src/config/types.d.ts +2 -2
  47. package/dist/src/core/background/job-launcher.d.ts +24 -0
  48. package/dist/src/core/background/job-launcher.d.ts.map +1 -1
  49. package/dist/src/core/background/job-launcher.js +80 -0
  50. package/dist/src/core/background/job-launcher.js.map +1 -1
  51. package/dist/src/core/background/types.d.ts +20 -2
  52. package/dist/src/core/background/types.d.ts.map +1 -1
  53. package/dist/src/core/fabric/registry-schema.d.ts +117 -0
  54. package/dist/src/core/fabric/registry-schema.d.ts.map +1 -1
  55. package/dist/src/core/fabric/registry-schema.js +37 -1
  56. package/dist/src/core/fabric/registry-schema.js.map +1 -1
  57. package/dist/src/core/fabric/security-judge.d.ts.map +1 -1
  58. package/dist/src/core/fabric/security-judge.js +38 -17
  59. package/dist/src/core/fabric/security-judge.js.map +1 -1
  60. package/dist/src/core/fabric/submission-queue-types.d.ts +83 -0
  61. package/dist/src/core/fabric/submission-queue-types.d.ts.map +1 -0
  62. package/dist/src/core/fabric/submission-queue-types.js +8 -0
  63. package/dist/src/core/fabric/submission-queue-types.js.map +1 -0
  64. package/dist/src/core/fabric/submission-queue.d.ts +65 -0
  65. package/dist/src/core/fabric/submission-queue.d.ts.map +1 -0
  66. package/dist/src/core/fabric/submission-queue.js +267 -0
  67. package/dist/src/core/fabric/submission-queue.js.map +1 -0
  68. package/dist/src/core/lazy-loading/llm-plugin-detector.d.ts +5 -3
  69. package/dist/src/core/lazy-loading/llm-plugin-detector.d.ts.map +1 -1
  70. package/dist/src/core/lazy-loading/llm-plugin-detector.js +66 -13
  71. package/dist/src/core/lazy-loading/llm-plugin-detector.js.map +1 -1
  72. package/dist/src/core/migration/umbrella-migrator.d.ts +9 -0
  73. package/dist/src/core/migration/umbrella-migrator.d.ts.map +1 -1
  74. package/dist/src/core/migration/umbrella-migrator.js +38 -4
  75. package/dist/src/core/migration/umbrella-migrator.js.map +1 -1
  76. package/dist/src/core/session/plugin-install-detector.d.ts.map +1 -1
  77. package/dist/src/core/session/plugin-install-detector.js +3 -2
  78. package/dist/src/core/session/plugin-install-detector.js.map +1 -1
  79. package/dist/src/dashboard/server/dashboard-server.d.ts.map +1 -1
  80. package/dist/src/dashboard/server/dashboard-server.js +115 -3
  81. package/dist/src/dashboard/server/dashboard-server.js.map +1 -1
  82. package/dist/src/dashboard/server/data/cost-aggregator.d.ts +0 -1
  83. package/dist/src/dashboard/server/data/cost-aggregator.d.ts.map +1 -1
  84. package/dist/src/dashboard/server/data/cost-aggregator.js +0 -1
  85. package/dist/src/dashboard/server/data/cost-aggregator.js.map +1 -1
  86. package/dist/src/dashboard/server/data/marketplace-aggregator.d.ts +27 -0
  87. package/dist/src/dashboard/server/data/marketplace-aggregator.d.ts.map +1 -0
  88. package/dist/src/dashboard/server/data/marketplace-aggregator.js +61 -0
  89. package/dist/src/dashboard/server/data/marketplace-aggregator.js.map +1 -0
  90. package/dist/src/dashboard/server/file-watcher.d.ts.map +1 -1
  91. package/dist/src/dashboard/server/file-watcher.js +1 -0
  92. package/dist/src/dashboard/server/file-watcher.js.map +1 -1
  93. package/dist/src/dashboard/types.d.ts +1 -1
  94. package/dist/src/dashboard/types.d.ts.map +1 -1
  95. package/dist/src/init/research/types.d.ts +1 -1
  96. package/dist/src/utils/cleanup-stale-plugins.d.ts +1 -1
  97. package/dist/src/utils/cleanup-stale-plugins.js +1 -1
  98. package/dist/src/utils/docs-preview/docusaurus-setup.d.ts.map +1 -1
  99. package/dist/src/utils/docs-preview/docusaurus-setup.js +9 -6
  100. package/dist/src/utils/docs-preview/docusaurus-setup.js.map +1 -1
  101. package/dist/src/utils/vskill-resolver.d.ts +24 -0
  102. package/dist/src/utils/vskill-resolver.d.ts.map +1 -0
  103. package/dist/src/utils/vskill-resolver.js +98 -0
  104. package/dist/src/utils/vskill-resolver.js.map +1 -0
  105. package/package.json +3 -1
  106. package/plugins/specweave/PLUGIN.md +1 -1
  107. package/plugins/specweave/hooks/user-prompt-submit.sh +147 -55
  108. package/plugins/specweave/hooks/v2/dispatchers/session-start.sh +1 -1
  109. package/plugins/specweave/skills/npm/SKILL.md +6 -6
  110. package/plugins/specweave/skills/update-instructions/SKILL.md +1 -1
  111. package/plugins/specweave-ado/PLUGIN.md +1 -1
  112. package/plugins/specweave-backend/PLUGIN.md +1 -1
  113. package/plugins/specweave-blockchain/PLUGIN.md +1 -1
  114. package/plugins/specweave-confluent/PLUGIN.md +1 -1
  115. package/plugins/specweave-cost-optimizer/PLUGIN.md +1 -1
  116. package/plugins/specweave-desktop/PLUGIN.md +1 -1
  117. package/plugins/specweave-diagrams/PLUGIN.md +1 -1
  118. package/plugins/specweave-docs/PLUGIN.md +1 -1
  119. package/plugins/specweave-figma/PLUGIN.md +1 -1
  120. package/plugins/specweave-frontend/PLUGIN.md +1 -1
  121. package/plugins/specweave-github/PLUGIN.md +1 -1
  122. package/plugins/specweave-infrastructure/PLUGIN.md +1 -1
  123. package/plugins/specweave-jira/PLUGIN.md +1 -1
  124. package/plugins/specweave-kafka/PLUGIN.md +1 -1
  125. package/plugins/specweave-kafka-streams/PLUGIN.md +1 -1
  126. package/plugins/specweave-kubernetes/PLUGIN.md +1 -1
  127. package/plugins/specweave-ml/PLUGIN.md +1 -1
  128. package/plugins/specweave-mobile/PLUGIN.md +1 -1
  129. package/plugins/specweave-mobile/README.md +2 -2
  130. package/plugins/specweave-n8n/PLUGIN.md +1 -1
  131. package/plugins/specweave-payments/PLUGIN.md +1 -1
  132. package/plugins/specweave-release/PLUGIN.md +1 -1
  133. package/plugins/specweave-release/commands/npm.md +6 -6
  134. package/plugins/specweave-testing/PLUGIN.md +1 -1
  135. package/scripts/preuninstall.cjs +34 -0
  136. package/src/templates/CLAUDE.md.template +3 -3
  137. package/dist/dashboard/assets/index-DNnisM2Y.css +0 -1
  138. package/dist/dashboard/assets/index-ldLuSpfZ.js +0 -11
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Submission Queue - Type Definitions
3
+ *
4
+ * Types for the marketplace skill submission pipeline.
5
+ * Skills flow: discovered → queued → scanning → tier1_passed/failed → tier2_pending → verified/rejected
6
+ */
7
+ export type SubmissionStatus = 'discovered' | 'queued' | 'scanning' | 'tier1_passed' | 'tier1_failed' | 'tier2_pending' | 'verified' | 'rejected';
8
+ export interface Tier1Result {
9
+ passed: boolean;
10
+ findings: number;
11
+ score: number;
12
+ }
13
+ export interface Tier2Result {
14
+ verdict: string;
15
+ score: number;
16
+ threats: string[];
17
+ }
18
+ export interface SkillSubmission {
19
+ id: string;
20
+ repoFullName: string;
21
+ repoUrl: string;
22
+ skillPath: string;
23
+ author: string;
24
+ stars: number;
25
+ lastUpdated: string;
26
+ status: SubmissionStatus;
27
+ tier1Result?: Tier1Result;
28
+ tier2Result?: Tier2Result;
29
+ discoveredAt: string;
30
+ updatedAt: string;
31
+ rejectedReason?: string;
32
+ }
33
+ export interface GitHubRepoInfo {
34
+ fullName: string;
35
+ htmlUrl: string;
36
+ description: string | null;
37
+ owner: string;
38
+ stars: number;
39
+ lastUpdated: string;
40
+ skillPath: string;
41
+ }
42
+ export interface ScannerStatus {
43
+ isRunning: boolean;
44
+ lastScanTime: string | null;
45
+ reposScanned: number;
46
+ reposDiscovered: number;
47
+ rateLimitRemaining: number | null;
48
+ rateLimitReset: string | null;
49
+ checkpoint: {
50
+ lastCursor: string;
51
+ seenRepos: string[];
52
+ } | null;
53
+ }
54
+ export interface SubmissionInsights {
55
+ totalDiscovered: number;
56
+ totalVerified: number;
57
+ totalRejected: number;
58
+ totalPending: number;
59
+ tier1PassRate: number;
60
+ tier2PassRate: number;
61
+ discoveryTimeline: Array<{
62
+ date: string;
63
+ count: number;
64
+ }>;
65
+ statusDistribution: Record<SubmissionStatus, number>;
66
+ }
67
+ export interface SubmissionQueueData {
68
+ submissions: SkillSubmission[];
69
+ lastUpdated: string;
70
+ version: number;
71
+ }
72
+ export interface SubmissionFilter {
73
+ status?: SubmissionStatus;
74
+ limit?: number;
75
+ offset?: number;
76
+ }
77
+ export interface PaginatedSubmissions {
78
+ items: SkillSubmission[];
79
+ total: number;
80
+ limit: number;
81
+ offset: number;
82
+ }
83
+ //# sourceMappingURL=submission-queue-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"submission-queue-types.d.ts","sourceRoot":"","sources":["../../../../src/core/fabric/submission-queue-types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,MAAM,gBAAgB,GACxB,YAAY,GACZ,QAAQ,GACR,UAAU,GACV,cAAc,GACd,cAAc,GACd,eAAe,GACf,UAAU,GACV,UAAU,CAAC;AAEf,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,gBAAgB,CAAC;IACzB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE;QACV,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,EAAE,CAAC;KACrB,GAAG,IAAI,CAAC;CACV;AAED,MAAM,WAAW,kBAAkB;IACjC,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,KAAK,CAAC;QACvB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;IACH,kBAAkB,EAAE,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Submission Queue - Type Definitions
3
+ *
4
+ * Types for the marketplace skill submission pipeline.
5
+ * Skills flow: discovered → queued → scanning → tier1_passed/failed → tier2_pending → verified/rejected
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=submission-queue-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"submission-queue-types.js","sourceRoot":"","sources":["../../../../src/core/fabric/submission-queue-types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Submission Queue
3
+ *
4
+ * File-based queue for marketplace skill submissions.
5
+ * Skills flow: discovered -> queued -> scanning -> tier1_passed/failed -> tier2_pending -> verified/rejected
6
+ *
7
+ * Features:
8
+ * - File-based persistence at .specweave/state/skill-submissions.json
9
+ * - Deduplication by repo full name
10
+ * - Status transition validation
11
+ * - Backup before write (.bak file)
12
+ * - Recovery from corrupted JSON
13
+ * - Filtering and pagination
14
+ * - Aggregated insights/analytics
15
+ */
16
+ import type { GitHubRepoInfo, SkillSubmission, SubmissionStatus, SubmissionFilter, PaginatedSubmissions, SubmissionInsights } from './submission-queue-types.js';
17
+ export declare class SubmissionQueue {
18
+ private projectPath;
19
+ private filePath;
20
+ private data;
21
+ constructor(projectPath: string);
22
+ /**
23
+ * Add a submission to the queue from GitHub repo info.
24
+ * Deduplicates by repoFullName -- returns existing entry if already present.
25
+ */
26
+ addSubmission(info: GitHubRepoInfo): SkillSubmission;
27
+ /**
28
+ * Update the status of a submission.
29
+ * Validates that the transition is allowed.
30
+ * Returns null if the ID is not found or transition is invalid.
31
+ */
32
+ updateStatus(id: string, newStatus: SubmissionStatus): SkillSubmission | null;
33
+ /**
34
+ * Approve a submission (set status to verified).
35
+ * Only works from approvable statuses (tier1_passed, tier2_pending).
36
+ */
37
+ approve(id: string): SkillSubmission | null;
38
+ /**
39
+ * Reject a submission with a reason.
40
+ * Can reject from any non-terminal status.
41
+ */
42
+ reject(id: string, reason: string): SkillSubmission | null;
43
+ /**
44
+ * Get a single submission by ID.
45
+ */
46
+ getById(id: string): SkillSubmission | null;
47
+ /**
48
+ * Get submissions with optional filtering and pagination.
49
+ */
50
+ getSubmissions(filter: SubmissionFilter): PaginatedSubmissions;
51
+ /**
52
+ * Get aggregated insights about the submission pipeline.
53
+ */
54
+ getInsights(): SubmissionInsights;
55
+ /**
56
+ * Load queue data from disk with backup recovery.
57
+ */
58
+ private load;
59
+ /**
60
+ * Save queue data to disk.
61
+ * Creates a .bak backup of the previous file before writing.
62
+ */
63
+ private save;
64
+ }
65
+ //# sourceMappingURL=submission-queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"submission-queue.d.ts","sourceRoot":"","sources":["../../../../src/core/fabric/submission-queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,gBAAgB,EAEhB,gBAAgB,EAChB,oBAAoB,EACpB,kBAAkB,EACnB,MAAM,6BAA6B,CAAC;AAgCrC,qBAAa,eAAe;IAId,OAAO,CAAC,WAAW;IAH/B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,IAAI,CAAsB;gBAEd,WAAW,EAAE,MAAM;IAKvC;;;OAGG;IACH,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,eAAe;IA2BpD;;;;OAIG;IACH,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,gBAAgB,GAAG,eAAe,GAAG,IAAI;IAiB7E;;;OAGG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI;IAgB3C;;;OAGG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI;IAiB1D;;OAEG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI;IAI3C;;OAEG;IACH,cAAc,CAAC,MAAM,EAAE,gBAAgB,GAAG,oBAAoB;IAgB9D;;OAEG;IACH,WAAW,IAAI,kBAAkB;IAgEjC;;OAEG;IACH,OAAO,CAAC,IAAI;IAqCZ;;;OAGG;IACH,OAAO,CAAC,IAAI;CAmBb"}
@@ -0,0 +1,267 @@
1
+ /**
2
+ * Submission Queue
3
+ *
4
+ * File-based queue for marketplace skill submissions.
5
+ * Skills flow: discovered -> queued -> scanning -> tier1_passed/failed -> tier2_pending -> verified/rejected
6
+ *
7
+ * Features:
8
+ * - File-based persistence at .specweave/state/skill-submissions.json
9
+ * - Deduplication by repo full name
10
+ * - Status transition validation
11
+ * - Backup before write (.bak file)
12
+ * - Recovery from corrupted JSON
13
+ * - Filtering and pagination
14
+ * - Aggregated insights/analytics
15
+ */
16
+ import * as fs from 'fs';
17
+ import * as path from 'path';
18
+ import * as crypto from 'crypto';
19
+ const QUEUE_FILE = '.specweave/state/skill-submissions.json';
20
+ /**
21
+ * Valid status transitions map.
22
+ * Each key lists the statuses it can transition TO.
23
+ */
24
+ const VALID_TRANSITIONS = {
25
+ 'discovered': ['queued', 'rejected'],
26
+ 'queued': ['scanning', 'rejected'],
27
+ 'scanning': ['tier1_passed', 'tier1_failed', 'rejected'],
28
+ 'tier1_passed': ['tier2_pending', 'verified', 'rejected'],
29
+ 'tier1_failed': ['queued', 'rejected'],
30
+ 'tier2_pending': ['verified', 'rejected'],
31
+ 'verified': [],
32
+ 'rejected': [],
33
+ };
34
+ /** Statuses from which approve() can set verified */
35
+ const APPROVABLE_STATUSES = ['tier1_passed', 'tier2_pending'];
36
+ /** Statuses from which reject() can set rejected (all non-terminal) */
37
+ const REJECTABLE_STATUSES = [
38
+ 'discovered', 'queued', 'scanning', 'tier1_passed', 'tier1_failed', 'tier2_pending',
39
+ ];
40
+ /** Pending statuses (not yet verified or rejected) */
41
+ const PENDING_STATUSES = [
42
+ 'discovered', 'queued', 'scanning', 'tier1_passed', 'tier1_failed', 'tier2_pending',
43
+ ];
44
+ export class SubmissionQueue {
45
+ constructor(projectPath) {
46
+ this.projectPath = projectPath;
47
+ this.filePath = path.join(projectPath, QUEUE_FILE);
48
+ this.data = this.load();
49
+ }
50
+ /**
51
+ * Add a submission to the queue from GitHub repo info.
52
+ * Deduplicates by repoFullName -- returns existing entry if already present.
53
+ */
54
+ addSubmission(info) {
55
+ const existing = this.data.submissions.find(s => s.repoFullName === info.fullName);
56
+ if (existing) {
57
+ return existing;
58
+ }
59
+ const now = new Date().toISOString();
60
+ const submission = {
61
+ id: crypto.randomUUID().slice(0, 12),
62
+ repoFullName: info.fullName,
63
+ repoUrl: info.htmlUrl,
64
+ skillPath: info.skillPath,
65
+ author: info.owner,
66
+ stars: info.stars,
67
+ lastUpdated: info.lastUpdated,
68
+ status: 'discovered',
69
+ discoveredAt: now,
70
+ updatedAt: now,
71
+ };
72
+ this.data.submissions.push(submission);
73
+ this.save();
74
+ return submission;
75
+ }
76
+ /**
77
+ * Update the status of a submission.
78
+ * Validates that the transition is allowed.
79
+ * Returns null if the ID is not found or transition is invalid.
80
+ */
81
+ updateStatus(id, newStatus) {
82
+ const submission = this.data.submissions.find(s => s.id === id);
83
+ if (!submission) {
84
+ return null;
85
+ }
86
+ const allowed = VALID_TRANSITIONS[submission.status];
87
+ if (!allowed || !allowed.includes(newStatus)) {
88
+ return null;
89
+ }
90
+ submission.status = newStatus;
91
+ submission.updatedAt = new Date().toISOString();
92
+ this.save();
93
+ return submission;
94
+ }
95
+ /**
96
+ * Approve a submission (set status to verified).
97
+ * Only works from approvable statuses (tier1_passed, tier2_pending).
98
+ */
99
+ approve(id) {
100
+ const submission = this.data.submissions.find(s => s.id === id);
101
+ if (!submission) {
102
+ return null;
103
+ }
104
+ if (!APPROVABLE_STATUSES.includes(submission.status)) {
105
+ return null;
106
+ }
107
+ submission.status = 'verified';
108
+ submission.updatedAt = new Date().toISOString();
109
+ this.save();
110
+ return submission;
111
+ }
112
+ /**
113
+ * Reject a submission with a reason.
114
+ * Can reject from any non-terminal status.
115
+ */
116
+ reject(id, reason) {
117
+ const submission = this.data.submissions.find(s => s.id === id);
118
+ if (!submission) {
119
+ return null;
120
+ }
121
+ if (!REJECTABLE_STATUSES.includes(submission.status)) {
122
+ return null;
123
+ }
124
+ submission.status = 'rejected';
125
+ submission.rejectedReason = reason;
126
+ submission.updatedAt = new Date().toISOString();
127
+ this.save();
128
+ return submission;
129
+ }
130
+ /**
131
+ * Get a single submission by ID.
132
+ */
133
+ getById(id) {
134
+ return this.data.submissions.find(s => s.id === id) ?? null;
135
+ }
136
+ /**
137
+ * Get submissions with optional filtering and pagination.
138
+ */
139
+ getSubmissions(filter) {
140
+ let items = [...this.data.submissions];
141
+ if (filter.status) {
142
+ items = items.filter(s => s.status === filter.status);
143
+ }
144
+ const total = items.length;
145
+ const offset = filter.offset ?? 0;
146
+ const limit = filter.limit ?? (items.length || 20);
147
+ items = items.slice(offset, offset + limit);
148
+ return { items, total, limit, offset };
149
+ }
150
+ /**
151
+ * Get aggregated insights about the submission pipeline.
152
+ */
153
+ getInsights() {
154
+ const submissions = this.data.submissions;
155
+ const statusDistribution = {
156
+ 'discovered': 0,
157
+ 'queued': 0,
158
+ 'scanning': 0,
159
+ 'tier1_passed': 0,
160
+ 'tier1_failed': 0,
161
+ 'tier2_pending': 0,
162
+ 'verified': 0,
163
+ 'rejected': 0,
164
+ };
165
+ for (const sub of submissions) {
166
+ statusDistribution[sub.status]++;
167
+ }
168
+ // Tier 1 pass rate: tier1_passed / (tier1_passed + tier1_failed)
169
+ // Count those that reached tier1_passed or beyond (excluding tier1_failed path)
170
+ const tier1Passed = statusDistribution['tier1_passed'] +
171
+ statusDistribution['tier2_pending'] +
172
+ statusDistribution['verified'];
173
+ const tier1Failed = statusDistribution['tier1_failed'];
174
+ const tier1Evaluated = tier1Passed + tier1Failed;
175
+ const tier1PassRate = tier1Evaluated > 0
176
+ ? Math.round((tier1Passed / tier1Evaluated) * 100)
177
+ : 0;
178
+ // Tier 2 pass rate: verified / (verified + tier2_pending)
179
+ const tier2Passed = statusDistribution['verified'];
180
+ const tier2Total = tier2Passed + statusDistribution['tier2_pending'];
181
+ const tier2PassRate = tier2Total > 0
182
+ ? Math.round((tier2Passed / tier2Total) * 100)
183
+ : 0;
184
+ // Pending count
185
+ const totalPending = PENDING_STATUSES.reduce((sum, status) => sum + statusDistribution[status], 0);
186
+ // Discovery timeline (group by date)
187
+ const dayCounts = new Map();
188
+ for (const sub of submissions) {
189
+ const date = sub.discoveredAt.split('T')[0];
190
+ dayCounts.set(date, (dayCounts.get(date) || 0) + 1);
191
+ }
192
+ const discoveryTimeline = Array.from(dayCounts.entries())
193
+ .map(([date, count]) => ({ date, count }))
194
+ .sort((a, b) => a.date.localeCompare(b.date));
195
+ return {
196
+ totalDiscovered: submissions.length,
197
+ totalVerified: statusDistribution['verified'],
198
+ totalRejected: statusDistribution['rejected'],
199
+ totalPending,
200
+ tier1PassRate,
201
+ tier2PassRate,
202
+ discoveryTimeline,
203
+ statusDistribution,
204
+ };
205
+ }
206
+ /**
207
+ * Load queue data from disk with backup recovery.
208
+ */
209
+ load() {
210
+ const emptyData = {
211
+ submissions: [],
212
+ lastUpdated: new Date().toISOString(),
213
+ version: 1,
214
+ };
215
+ // Try loading main file
216
+ try {
217
+ if (fs.existsSync(this.filePath)) {
218
+ const content = fs.readFileSync(this.filePath, 'utf-8');
219
+ const data = JSON.parse(content);
220
+ if (data && Array.isArray(data.submissions)) {
221
+ return data;
222
+ }
223
+ }
224
+ }
225
+ catch {
226
+ // Main file corrupted, try backup
227
+ }
228
+ // Try backup file
229
+ const backupPath = this.filePath + '.bak';
230
+ try {
231
+ if (fs.existsSync(backupPath)) {
232
+ const content = fs.readFileSync(backupPath, 'utf-8');
233
+ const data = JSON.parse(content);
234
+ if (data && Array.isArray(data.submissions)) {
235
+ return data;
236
+ }
237
+ }
238
+ }
239
+ catch {
240
+ // Backup also corrupted
241
+ }
242
+ return emptyData;
243
+ }
244
+ /**
245
+ * Save queue data to disk.
246
+ * Creates a .bak backup of the previous file before writing.
247
+ */
248
+ save() {
249
+ const dir = path.dirname(this.filePath);
250
+ if (!fs.existsSync(dir)) {
251
+ fs.mkdirSync(dir, { recursive: true });
252
+ }
253
+ // Create backup of existing file before overwriting
254
+ if (fs.existsSync(this.filePath)) {
255
+ const backupPath = this.filePath + '.bak';
256
+ try {
257
+ fs.copyFileSync(this.filePath, backupPath);
258
+ }
259
+ catch {
260
+ // Non-fatal: continue saving even if backup fails
261
+ }
262
+ }
263
+ this.data.lastUpdated = new Date().toISOString();
264
+ fs.writeFileSync(this.filePath, JSON.stringify(this.data, null, 2));
265
+ }
266
+ }
267
+ //# sourceMappingURL=submission-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"submission-queue.js","sourceRoot":"","sources":["../../../../src/core/fabric/submission-queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AAWjC,MAAM,UAAU,GAAG,yCAAyC,CAAC;AAE7D;;;GAGG;AACH,MAAM,iBAAiB,GAAiD;IACtE,YAAY,EAAE,CAAC,QAAQ,EAAE,UAAU,CAAC;IACpC,QAAQ,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC;IAClC,UAAU,EAAE,CAAC,cAAc,EAAE,cAAc,EAAE,UAAU,CAAC;IACxD,cAAc,EAAE,CAAC,eAAe,EAAE,UAAU,EAAE,UAAU,CAAC;IACzD,cAAc,EAAE,CAAC,QAAQ,EAAE,UAAU,CAAC;IACtC,eAAe,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC;IACzC,UAAU,EAAE,EAAE;IACd,UAAU,EAAE,EAAE;CACf,CAAC;AAEF,qDAAqD;AACrD,MAAM,mBAAmB,GAAuB,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;AAElF,uEAAuE;AACvE,MAAM,mBAAmB,GAAuB;IAC9C,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe;CACpF,CAAC;AAEF,sDAAsD;AACtD,MAAM,gBAAgB,GAAuB;IAC3C,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe;CACpF,CAAC;AAEF,MAAM,OAAO,eAAe;IAI1B,YAAoB,WAAmB;QAAnB,gBAAW,GAAX,WAAW,CAAQ;QACrC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;QACnD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC1B,CAAC;IAED;;;OAGG;IACH,aAAa,CAAC,IAAoB;QAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CACzC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,KAAK,IAAI,CAAC,QAAQ,CACtC,CAAC;QACF,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,UAAU,GAAoB;YAClC,EAAE,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;YACpC,YAAY,EAAE,IAAI,CAAC,QAAQ;YAC3B,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,MAAM,EAAE,IAAI,CAAC,KAAK;YAClB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,MAAM,EAAE,YAAY;YACpB,YAAY,EAAE,GAAG;YACjB,SAAS,EAAE,GAAG;SACf,CAAC;QAEF,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,OAAO,UAAU,CAAC;IACpB,CAAC;IAED;;;;OAIG;IACH,YAAY,CAAC,EAAU,EAAE,SAA2B;QAClD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAChE,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,OAAO,GAAG,iBAAiB,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QACrD,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YAC7C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,UAAU,CAAC,MAAM,GAAG,SAAS,CAAC;QAC9B,UAAU,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAChD,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,OAAO,UAAU,CAAC;IACpB,CAAC;IAED;;;OAGG;IACH,OAAO,CAAC,EAAU;QAChB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAChE,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACrD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,UAAU,CAAC,MAAM,GAAG,UAAU,CAAC;QAC/B,UAAU,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAChD,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,OAAO,UAAU,CAAC;IACpB,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,EAAU,EAAE,MAAc;QAC/B,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAChE,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACrD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,UAAU,CAAC,MAAM,GAAG,UAAU,CAAC;QAC/B,UAAU,CAAC,cAAc,GAAG,MAAM,CAAC;QACnC,UAAU,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAChD,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,OAAO,UAAU,CAAC;IACpB,CAAC;IAED;;OAEG;IACH,OAAO,CAAC,EAAU;QAChB,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,IAAI,CAAC;IAC9D,CAAC;IAED;;OAEG;IACH,cAAc,CAAC,MAAwB;QACrC,IAAI,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAEvC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClB,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC;QACxD,CAAC;QAED,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC;QAC3B,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;QAClC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;QAEnD,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC;QAE5C,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IACzC,CAAC;IAED;;OAEG;IACH,WAAW;QACT,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC;QAE1C,MAAM,kBAAkB,GAAqC;YAC3D,YAAY,EAAE,CAAC;YACf,QAAQ,EAAE,CAAC;YACX,UAAU,EAAE,CAAC;YACb,cAAc,EAAE,CAAC;YACjB,cAAc,EAAE,CAAC;YACjB,eAAe,EAAE,CAAC;YAClB,UAAU,EAAE,CAAC;YACb,UAAU,EAAE,CAAC;SACd,CAAC;QAEF,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;YAC9B,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QACnC,CAAC;QAED,iEAAiE;QACjE,gFAAgF;QAChF,MAAM,WAAW,GAAG,kBAAkB,CAAC,cAAc,CAAC;YACpD,kBAAkB,CAAC,eAAe,CAAC;YACnC,kBAAkB,CAAC,UAAU,CAAC,CAAC;QACjC,MAAM,WAAW,GAAG,kBAAkB,CAAC,cAAc,CAAC,CAAC;QACvD,MAAM,cAAc,GAAG,WAAW,GAAG,WAAW,CAAC;QACjD,MAAM,aAAa,GAAG,cAAc,GAAG,CAAC;YACtC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,GAAG,cAAc,CAAC,GAAG,GAAG,CAAC;YAClD,CAAC,CAAC,CAAC,CAAC;QAEN,0DAA0D;QAC1D,MAAM,WAAW,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;QACnD,MAAM,UAAU,GAAG,WAAW,GAAG,kBAAkB,CAAC,eAAe,CAAC,CAAC;QACrE,MAAM,aAAa,GAAG,UAAU,GAAG,CAAC;YAClC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,GAAG,UAAU,CAAC,GAAG,GAAG,CAAC;YAC9C,CAAC,CAAC,CAAC,CAAC;QAEN,gBAAgB;QAChB,MAAM,YAAY,GAAG,gBAAgB,CAAC,MAAM,CAC1C,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,GAAG,GAAG,kBAAkB,CAAC,MAAM,CAAC,EACjD,CAAC,CACF,CAAC;QAEF,qCAAqC;QACrC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;QAC5C,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;YAC9B,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5C,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACtD,CAAC;QACD,MAAM,iBAAiB,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;aACtD,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;aACzC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAEhD,OAAO;YACL,eAAe,EAAE,WAAW,CAAC,MAAM;YACnC,aAAa,EAAE,kBAAkB,CAAC,UAAU,CAAC;YAC7C,aAAa,EAAE,kBAAkB,CAAC,UAAU,CAAC;YAC7C,YAAY;YACZ,aAAa;YACb,aAAa;YACb,iBAAiB;YACjB,kBAAkB;SACnB,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,IAAI;QACV,MAAM,SAAS,GAAwB;YACrC,WAAW,EAAE,EAAE;YACf,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACrC,OAAO,EAAE,CAAC;SACX,CAAC;QAEF,wBAAwB;QACxB,IAAI,CAAC;YACH,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACjC,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBACxD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAwB,CAAC;gBACxD,IAAI,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;oBAC5C,OAAO,IAAI,CAAC;gBACd,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,kCAAkC;QACpC,CAAC;QAED,kBAAkB;QAClB,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC;QAC1C,IAAI,CAAC;YACH,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC9B,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;gBACrD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAwB,CAAC;gBACxD,IAAI,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;oBAC5C,OAAO,IAAI,CAAC;gBACd,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,wBAAwB;QAC1B,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;;OAGG;IACK,IAAI;QACV,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzC,CAAC;QAED,oDAAoD;QACpD,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YACjC,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC;YAC1C,IAAI,CAAC;gBACH,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;YAC7C,CAAC;YAAC,MAAM,CAAC;gBACP,kDAAkD;YACpD,CAAC;QACH,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,WAAW,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACjD,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACtE,CAAC;CACF"}
@@ -306,10 +306,12 @@ export declare function isClaudeCliAvailable(): ClaudeCliStatus;
306
306
  export declare function detectPluginsViaLLM(userPrompt: string, timeout?: number, // v1.0.159: Reduced to 15s with --setting-sources "" optimization (CLI starts in <1s)
307
307
  activeIncrements?: ActiveIncrementContext[]): Promise<LLMDetectionResult>;
308
308
  /**
309
- * Install a SpecWeave plugin using Claude CLI
309
+ * Install a SpecWeave plugin using vskill
310
310
  *
311
- * Uses `claude plugin install <name>` which is the official API.
312
- * This properly registers the plugin in installed_plugins.json.
311
+ * Uses vskill add with --plugin and --plugin-dir flags for local
312
+ * plugin directory installation with security scanning.
313
+ *
314
+ * Fast-path: If plugin is already in vskill.lock, skip installation.
313
315
  *
314
316
  * @param pluginName - Name of the plugin to install
315
317
  * @param timeout - Timeout in milliseconds
@@ -1 +1 @@
1
- {"version":3,"file":"llm-plugin-detector.d.ts","sourceRoot":"","sources":["../../../../src/core/lazy-loading/llm-plugin-detector.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"llm-plugin-detector.d.ts","sourceRoot":"","sources":["../../../../src/core/lazy-loading/llm-plugin-detector.ts"],"names":[],"mappings":"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"}
@@ -17,9 +17,9 @@ import * as os from 'os';
17
17
  import * as fs from 'fs';
18
18
  import * as path from 'path';
19
19
  import { consoleLogger as logger } from '../../utils/logger.js';
20
+ import { resolveVskillPath as _resolveVskillPath, resolveSpecweaveDir as _resolveSpecweaveDir } from '../../utils/vskill-resolver.js';
20
21
  // IMPORTANT: Use canonical Claude CLI detection from utils (handles shell functions, nvm, etc.)
21
22
  import { detectClaudeCli, getCleanEnv } from '../../utils/claude-cli-detector.js';
22
- import { getPluginScope, getScopeArgs } from '../types/plugin-scope.js';
23
23
  // ============================================================
24
24
  // Prompt safety constants and truncation utilities (v1.0.254)
25
25
  //
@@ -870,10 +870,44 @@ Which plugins should be loaded?`;
870
870
  }
871
871
  }
872
872
  /**
873
- * Install a SpecWeave plugin using Claude CLI
873
+ * Check if a plugin is already installed via vskill lockfile
874
874
  *
875
- * Uses `claude plugin install <name>` which is the official API.
876
- * This properly registers the plugin in installed_plugins.json.
875
+ * Reads vskill.lock from cwd and checks if the plugin has an entry.
876
+ * This provides a fast-path to skip installation when plugin is
877
+ * already present with a matching hash.
878
+ *
879
+ * @param pluginName - Name of the plugin to check
880
+ * @returns true if plugin is in the lockfile
881
+ */
882
+ function isPluginInVskillLock(pluginName) {
883
+ try {
884
+ const lockPath = path.join(process.cwd(), 'vskill.lock');
885
+ if (!fs.existsSync(lockPath)) {
886
+ return false;
887
+ }
888
+ const content = fs.readFileSync(lockPath, 'utf-8');
889
+ const lock = JSON.parse(content);
890
+ return lock.skills && pluginName in lock.skills;
891
+ }
892
+ catch {
893
+ return false;
894
+ }
895
+ }
896
+ /** Resolve vskill path from this module's location */
897
+ function resolveVskillCliPath() {
898
+ return _resolveVskillPath(__dirname);
899
+ }
900
+ /** Resolve specweave source directory */
901
+ function resolveSpecweaveDir() {
902
+ return _resolveSpecweaveDir(__dirname);
903
+ }
904
+ /**
905
+ * Install a SpecWeave plugin using vskill
906
+ *
907
+ * Uses vskill add with --plugin and --plugin-dir flags for local
908
+ * plugin directory installation with security scanning.
909
+ *
910
+ * Fast-path: If plugin is already in vskill.lock, skip installation.
877
911
  *
878
912
  * @param pluginName - Name of the plugin to install
879
913
  * @param timeout - Timeout in milliseconds
@@ -890,7 +924,7 @@ export async function installPluginViaCli(pluginName, timeout = 30000) {
890
924
  error: `Unknown plugin: ${pluginName}`,
891
925
  };
892
926
  }
893
- // Check CLI availability
927
+ // Check CLI availability (still needed for detect-intent etc.)
894
928
  const cliStatus = isClaudeCliAvailable();
895
929
  if (!cliStatus.available) {
896
930
  return {
@@ -899,14 +933,33 @@ export async function installPluginViaCli(pluginName, timeout = 30000) {
899
933
  error: cliStatus.error,
900
934
  };
901
935
  }
902
- // Determine marketplace: sw-* @specweave, others @claude-plugins-official
903
- const marketplace = isSW ? 'specweave' : 'claude-plugins-official';
904
- const fullPluginName = `${pluginName}@${marketplace}`;
936
+ // Fast-path: Check vskill.lock - skip if already installed
937
+ if (isPluginInVskillLock(pluginName)) {
938
+ logger.debug(`Plugin ${pluginName} already in vskill.lock, skipping installation`);
939
+ return {
940
+ success: true,
941
+ plugin: pluginName,
942
+ alreadyInstalled: true,
943
+ };
944
+ }
945
+ // Install via vskill
905
946
  try {
906
- // Domain plugins (sw-frontend, sw-github, etc.) → project scope
907
- // Core plugin (sw) → user scope
908
- const scopeArgs = getScopeArgs(getPluginScope(pluginName, marketplace));
909
- const result = executeClaudeCli(['plugin', 'install', fullPluginName, ...scopeArgs], timeout);
947
+ const vskillPath = resolveVskillCliPath();
948
+ const pluginDir = resolveSpecweaveDir();
949
+ const result = spawnSync('node', [
950
+ vskillPath,
951
+ 'add',
952
+ pluginDir,
953
+ '--plugin', pluginName,
954
+ '--plugin-dir', pluginDir,
955
+ '--force', // Auto-accept scan results during lazy loading
956
+ ], {
957
+ encoding: 'utf8',
958
+ timeout,
959
+ maxBuffer: 1024 * 1024,
960
+ windowsHide: true,
961
+ cwd: process.cwd(),
962
+ });
910
963
  // Handle spawn errors
911
964
  if (result.error) {
912
965
  return {
@@ -920,7 +973,7 @@ export async function installPluginViaCli(pluginName, timeout = 30000) {
920
973
  const stderr = result.stderr || '';
921
974
  const combined = `${stdout} ${stderr}`.toLowerCase();
922
975
  // Already installed is a success
923
- if (combined.includes('already installed')) {
976
+ if (combined.includes('already')) {
924
977
  return {
925
978
  success: true,
926
979
  plugin: pluginName,