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.
- package/CLAUDE.md +28 -28
- package/bin/specweave.js +13 -0
- package/dist/dashboard/assets/index-BKdLA_6x.js +11 -0
- package/dist/dashboard/assets/index-Cs3Zq6E2.css +1 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/src/cli/commands/detect-intent.js +1 -1
- package/dist/src/cli/commands/detect-intent.js.map +1 -1
- package/dist/src/cli/commands/judge-skill.d.ts.map +1 -1
- package/dist/src/cli/commands/judge-skill.js +11 -0
- package/dist/src/cli/commands/judge-skill.js.map +1 -1
- package/dist/src/cli/commands/migrate-to-umbrella.d.ts.map +1 -1
- package/dist/src/cli/commands/migrate-to-umbrella.js +97 -2
- package/dist/src/cli/commands/migrate-to-umbrella.js.map +1 -1
- package/dist/src/cli/commands/migrate-to-vskill.d.ts +43 -0
- package/dist/src/cli/commands/migrate-to-vskill.d.ts.map +1 -0
- package/dist/src/cli/commands/migrate-to-vskill.js +144 -0
- package/dist/src/cli/commands/migrate-to-vskill.js.map +1 -0
- package/dist/src/cli/commands/refresh-marketplace.d.ts +4 -23
- package/dist/src/cli/commands/refresh-marketplace.d.ts.map +1 -1
- package/dist/src/cli/commands/refresh-marketplace.js +15 -1061
- package/dist/src/cli/commands/refresh-marketplace.js.map +1 -1
- package/dist/src/cli/commands/refresh-plugins.d.ts +28 -0
- package/dist/src/cli/commands/refresh-plugins.d.ts.map +1 -0
- package/dist/src/cli/commands/refresh-plugins.js +272 -0
- package/dist/src/cli/commands/refresh-plugins.js.map +1 -0
- package/dist/src/cli/commands/uninstall.d.ts +11 -0
- package/dist/src/cli/commands/uninstall.d.ts.map +1 -0
- package/dist/src/cli/commands/uninstall.js +164 -0
- package/dist/src/cli/commands/uninstall.js.map +1 -0
- package/dist/src/cli/helpers/init/claude-plugin-enabler.d.ts +6 -2
- package/dist/src/cli/helpers/init/claude-plugin-enabler.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/claude-plugin-enabler.js +6 -2
- package/dist/src/cli/helpers/init/claude-plugin-enabler.js.map +1 -1
- package/dist/src/cli/helpers/init/instruction-file-merger.d.ts +5 -0
- package/dist/src/cli/helpers/init/instruction-file-merger.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/instruction-file-merger.js +18 -0
- package/dist/src/cli/helpers/init/instruction-file-merger.js.map +1 -1
- package/dist/src/cli/helpers/init/plugin-installer.d.ts +1 -1
- package/dist/src/cli/helpers/init/plugin-installer.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/plugin-installer.js +98 -364
- package/dist/src/cli/helpers/init/plugin-installer.js.map +1 -1
- package/dist/src/cli/workers/marketplace-scanner-worker.d.ts +73 -0
- package/dist/src/cli/workers/marketplace-scanner-worker.d.ts.map +1 -0
- package/dist/src/cli/workers/marketplace-scanner-worker.js +405 -0
- package/dist/src/cli/workers/marketplace-scanner-worker.js.map +1 -0
- package/dist/src/config/types.d.ts +2 -2
- package/dist/src/core/background/job-launcher.d.ts +24 -0
- package/dist/src/core/background/job-launcher.d.ts.map +1 -1
- package/dist/src/core/background/job-launcher.js +80 -0
- package/dist/src/core/background/job-launcher.js.map +1 -1
- package/dist/src/core/background/types.d.ts +20 -2
- package/dist/src/core/background/types.d.ts.map +1 -1
- package/dist/src/core/fabric/registry-schema.d.ts +117 -0
- package/dist/src/core/fabric/registry-schema.d.ts.map +1 -1
- package/dist/src/core/fabric/registry-schema.js +37 -1
- package/dist/src/core/fabric/registry-schema.js.map +1 -1
- package/dist/src/core/fabric/security-judge.d.ts.map +1 -1
- package/dist/src/core/fabric/security-judge.js +38 -17
- package/dist/src/core/fabric/security-judge.js.map +1 -1
- package/dist/src/core/fabric/submission-queue-types.d.ts +83 -0
- package/dist/src/core/fabric/submission-queue-types.d.ts.map +1 -0
- package/dist/src/core/fabric/submission-queue-types.js +8 -0
- package/dist/src/core/fabric/submission-queue-types.js.map +1 -0
- package/dist/src/core/fabric/submission-queue.d.ts +65 -0
- package/dist/src/core/fabric/submission-queue.d.ts.map +1 -0
- package/dist/src/core/fabric/submission-queue.js +267 -0
- package/dist/src/core/fabric/submission-queue.js.map +1 -0
- package/dist/src/core/lazy-loading/llm-plugin-detector.d.ts +5 -3
- package/dist/src/core/lazy-loading/llm-plugin-detector.d.ts.map +1 -1
- package/dist/src/core/lazy-loading/llm-plugin-detector.js +66 -13
- package/dist/src/core/lazy-loading/llm-plugin-detector.js.map +1 -1
- package/dist/src/core/migration/umbrella-migrator.d.ts +9 -0
- package/dist/src/core/migration/umbrella-migrator.d.ts.map +1 -1
- package/dist/src/core/migration/umbrella-migrator.js +38 -4
- package/dist/src/core/migration/umbrella-migrator.js.map +1 -1
- package/dist/src/core/session/plugin-install-detector.d.ts.map +1 -1
- package/dist/src/core/session/plugin-install-detector.js +3 -2
- package/dist/src/core/session/plugin-install-detector.js.map +1 -1
- package/dist/src/dashboard/server/dashboard-server.d.ts.map +1 -1
- package/dist/src/dashboard/server/dashboard-server.js +115 -3
- package/dist/src/dashboard/server/dashboard-server.js.map +1 -1
- package/dist/src/dashboard/server/data/cost-aggregator.d.ts +0 -1
- package/dist/src/dashboard/server/data/cost-aggregator.d.ts.map +1 -1
- package/dist/src/dashboard/server/data/cost-aggregator.js +0 -1
- package/dist/src/dashboard/server/data/cost-aggregator.js.map +1 -1
- package/dist/src/dashboard/server/data/marketplace-aggregator.d.ts +27 -0
- package/dist/src/dashboard/server/data/marketplace-aggregator.d.ts.map +1 -0
- package/dist/src/dashboard/server/data/marketplace-aggregator.js +61 -0
- package/dist/src/dashboard/server/data/marketplace-aggregator.js.map +1 -0
- package/dist/src/dashboard/server/file-watcher.d.ts.map +1 -1
- package/dist/src/dashboard/server/file-watcher.js +1 -0
- package/dist/src/dashboard/server/file-watcher.js.map +1 -1
- package/dist/src/dashboard/types.d.ts +1 -1
- package/dist/src/dashboard/types.d.ts.map +1 -1
- package/dist/src/init/research/types.d.ts +1 -1
- package/dist/src/utils/cleanup-stale-plugins.d.ts +1 -1
- package/dist/src/utils/cleanup-stale-plugins.js +1 -1
- package/dist/src/utils/docs-preview/docusaurus-setup.d.ts.map +1 -1
- package/dist/src/utils/docs-preview/docusaurus-setup.js +9 -6
- package/dist/src/utils/docs-preview/docusaurus-setup.js.map +1 -1
- package/dist/src/utils/vskill-resolver.d.ts +24 -0
- package/dist/src/utils/vskill-resolver.d.ts.map +1 -0
- package/dist/src/utils/vskill-resolver.js +98 -0
- package/dist/src/utils/vskill-resolver.js.map +1 -0
- package/package.json +3 -1
- package/plugins/specweave/PLUGIN.md +1 -1
- package/plugins/specweave/hooks/user-prompt-submit.sh +147 -55
- package/plugins/specweave/hooks/v2/dispatchers/session-start.sh +1 -1
- package/plugins/specweave/skills/npm/SKILL.md +6 -6
- package/plugins/specweave/skills/update-instructions/SKILL.md +1 -1
- package/plugins/specweave-ado/PLUGIN.md +1 -1
- package/plugins/specweave-backend/PLUGIN.md +1 -1
- package/plugins/specweave-blockchain/PLUGIN.md +1 -1
- package/plugins/specweave-confluent/PLUGIN.md +1 -1
- package/plugins/specweave-cost-optimizer/PLUGIN.md +1 -1
- package/plugins/specweave-desktop/PLUGIN.md +1 -1
- package/plugins/specweave-diagrams/PLUGIN.md +1 -1
- package/plugins/specweave-docs/PLUGIN.md +1 -1
- package/plugins/specweave-figma/PLUGIN.md +1 -1
- package/plugins/specweave-frontend/PLUGIN.md +1 -1
- package/plugins/specweave-github/PLUGIN.md +1 -1
- package/plugins/specweave-infrastructure/PLUGIN.md +1 -1
- package/plugins/specweave-jira/PLUGIN.md +1 -1
- package/plugins/specweave-kafka/PLUGIN.md +1 -1
- package/plugins/specweave-kafka-streams/PLUGIN.md +1 -1
- package/plugins/specweave-kubernetes/PLUGIN.md +1 -1
- package/plugins/specweave-ml/PLUGIN.md +1 -1
- package/plugins/specweave-mobile/PLUGIN.md +1 -1
- package/plugins/specweave-mobile/README.md +2 -2
- package/plugins/specweave-n8n/PLUGIN.md +1 -1
- package/plugins/specweave-payments/PLUGIN.md +1 -1
- package/plugins/specweave-release/PLUGIN.md +1 -1
- package/plugins/specweave-release/commands/npm.md +6 -6
- package/plugins/specweave-testing/PLUGIN.md +1 -1
- package/scripts/preuninstall.cjs +34 -0
- package/src/templates/CLAUDE.md.template +3 -3
- package/dist/dashboard/assets/index-DNnisM2Y.css +0 -1
- 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
|
|
309
|
+
* Install a SpecWeave plugin using vskill
|
|
310
310
|
*
|
|
311
|
-
* Uses
|
|
312
|
-
*
|
|
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":"AAAA;;;;;;;;;;;;;GAaG;
|
|
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
|
-
*
|
|
873
|
+
* Check if a plugin is already installed via vskill lockfile
|
|
874
874
|
*
|
|
875
|
-
*
|
|
876
|
-
* This
|
|
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
|
-
//
|
|
903
|
-
|
|
904
|
-
|
|
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
|
-
|
|
907
|
-
|
|
908
|
-
const
|
|
909
|
-
|
|
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
|
|
976
|
+
if (combined.includes('already')) {
|
|
924
977
|
return {
|
|
925
978
|
success: true,
|
|
926
979
|
plugin: pluginName,
|