nova-terminal-assistant 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of nova-terminal-assistant might be problematic. Click here for more details.

Files changed (192) hide show
  1. package/README.md +358 -0
  2. package/bin/nova +38 -0
  3. package/bin/nova.js +12 -0
  4. package/package.json +67 -0
  5. package/src/cli/commands/SmartCompletion.ts +458 -0
  6. package/src/cli/index.ts +5 -0
  7. package/src/cli/startup/IFlowRepl.ts +212 -0
  8. package/src/cli/startup/InkBasedRepl.ts +1056 -0
  9. package/src/cli/startup/InteractiveRepl.ts +2833 -0
  10. package/src/cli/startup/NovaApp.ts +1861 -0
  11. package/src/cli/startup/index.ts +4 -0
  12. package/src/cli/startup/parseArgs.ts +293 -0
  13. package/src/cli/test-modules.ts +27 -0
  14. package/src/cli/ui/IFlowDropdown.ts +425 -0
  15. package/src/cli/ui/ModernReplUI.ts +276 -0
  16. package/src/cli/ui/SimpleSelector2.ts +215 -0
  17. package/src/cli/ui/components/ConfirmDialog.ts +176 -0
  18. package/src/cli/ui/components/ErrorPanel.ts +364 -0
  19. package/src/cli/ui/components/InkAppRunner.tsx +67 -0
  20. package/src/cli/ui/components/InkComponents.tsx +613 -0
  21. package/src/cli/ui/components/NovaInkApp.tsx +312 -0
  22. package/src/cli/ui/components/ProgressBar.ts +177 -0
  23. package/src/cli/ui/components/ProgressIndicator.ts +298 -0
  24. package/src/cli/ui/components/QuickActions.ts +396 -0
  25. package/src/cli/ui/components/SimpleErrorPanel.ts +231 -0
  26. package/src/cli/ui/components/StatusBar.ts +194 -0
  27. package/src/cli/ui/components/ThinkingBlockRenderer.ts +401 -0
  28. package/src/cli/ui/components/index.ts +27 -0
  29. package/src/cli/ui/ink-prototype.tsx +347 -0
  30. package/src/cli/utils/CliUI.ts +336 -0
  31. package/src/cli/utils/CompletionHelper.ts +388 -0
  32. package/src/cli/utils/EnhancedCompleter.test.ts +226 -0
  33. package/src/cli/utils/EnhancedCompleter.ts +513 -0
  34. package/src/cli/utils/ErrorEnhancer.ts +429 -0
  35. package/src/cli/utils/OutputFormatter.ts +193 -0
  36. package/src/cli/utils/index.ts +9 -0
  37. package/src/core/agents/AgentOrchestrator.ts +515 -0
  38. package/src/core/agents/index.ts +17 -0
  39. package/src/core/audit/AuditLogger.ts +509 -0
  40. package/src/core/audit/index.ts +11 -0
  41. package/src/core/auth/AuthManager.d.ts.map +1 -0
  42. package/src/core/auth/AuthManager.ts +138 -0
  43. package/src/core/auth/index.d.ts.map +1 -0
  44. package/src/core/auth/index.ts +2 -0
  45. package/src/core/config/ConfigManager.d.ts.map +1 -0
  46. package/src/core/config/ConfigManager.test.ts +183 -0
  47. package/src/core/config/ConfigManager.ts +1219 -0
  48. package/src/core/config/index.d.ts.map +1 -0
  49. package/src/core/config/index.ts +1 -0
  50. package/src/core/context/ContextBuilder.d.ts.map +1 -0
  51. package/src/core/context/ContextBuilder.ts +171 -0
  52. package/src/core/context/ContextCompressor.d.ts.map +1 -0
  53. package/src/core/context/ContextCompressor.ts +642 -0
  54. package/src/core/context/LayeredMemoryManager.ts +657 -0
  55. package/src/core/context/MemoryDiscovery.d.ts.map +1 -0
  56. package/src/core/context/MemoryDiscovery.ts +175 -0
  57. package/src/core/context/defaultSystemPrompt.d.ts.map +1 -0
  58. package/src/core/context/defaultSystemPrompt.ts +35 -0
  59. package/src/core/context/index.d.ts.map +1 -0
  60. package/src/core/context/index.ts +22 -0
  61. package/src/core/extensions/SkillGenerator.ts +421 -0
  62. package/src/core/extensions/SkillInstaller.d.ts.map +1 -0
  63. package/src/core/extensions/SkillInstaller.ts +257 -0
  64. package/src/core/extensions/SkillRegistry.d.ts.map +1 -0
  65. package/src/core/extensions/SkillRegistry.ts +361 -0
  66. package/src/core/extensions/SkillValidator.ts +525 -0
  67. package/src/core/extensions/index.ts +15 -0
  68. package/src/core/index.d.ts.map +1 -0
  69. package/src/core/index.ts +42 -0
  70. package/src/core/mcp/McpManager.d.ts.map +1 -0
  71. package/src/core/mcp/McpManager.ts +632 -0
  72. package/src/core/mcp/index.d.ts.map +1 -0
  73. package/src/core/mcp/index.ts +2 -0
  74. package/src/core/model/ModelClient.d.ts.map +1 -0
  75. package/src/core/model/ModelClient.ts +217 -0
  76. package/src/core/model/ModelConnectionTester.ts +363 -0
  77. package/src/core/model/ModelValidator.ts +348 -0
  78. package/src/core/model/index.d.ts.map +1 -0
  79. package/src/core/model/index.ts +6 -0
  80. package/src/core/model/providers/AnthropicProvider.d.ts.map +1 -0
  81. package/src/core/model/providers/AnthropicProvider.ts +279 -0
  82. package/src/core/model/providers/CodingPlanProvider.d.ts.map +1 -0
  83. package/src/core/model/providers/CodingPlanProvider.ts +210 -0
  84. package/src/core/model/providers/OllamaCloudProvider.d.ts.map +1 -0
  85. package/src/core/model/providers/OllamaCloudProvider.ts +405 -0
  86. package/src/core/model/providers/OllamaManager.d.ts.map +1 -0
  87. package/src/core/model/providers/OllamaManager.ts +201 -0
  88. package/src/core/model/providers/OllamaProvider.d.ts.map +1 -0
  89. package/src/core/model/providers/OllamaProvider.ts +73 -0
  90. package/src/core/model/providers/OpenAICompatibleProvider.d.ts.map +1 -0
  91. package/src/core/model/providers/OpenAICompatibleProvider.ts +327 -0
  92. package/src/core/model/providers/OpenAIProvider.d.ts.map +1 -0
  93. package/src/core/model/providers/OpenAIProvider.ts +29 -0
  94. package/src/core/model/providers/index.d.ts.map +1 -0
  95. package/src/core/model/providers/index.ts +12 -0
  96. package/src/core/model/types.d.ts.map +1 -0
  97. package/src/core/model/types.ts +77 -0
  98. package/src/core/security/ApprovalManager.d.ts.map +1 -0
  99. package/src/core/security/ApprovalManager.ts +174 -0
  100. package/src/core/security/FileFilter.d.ts.map +1 -0
  101. package/src/core/security/FileFilter.ts +141 -0
  102. package/src/core/security/HookExecutor.d.ts.map +1 -0
  103. package/src/core/security/HookExecutor.ts +178 -0
  104. package/src/core/security/SandboxExecutor.ts +447 -0
  105. package/src/core/security/index.d.ts.map +1 -0
  106. package/src/core/security/index.ts +8 -0
  107. package/src/core/session/AgentLoop.d.ts.map +1 -0
  108. package/src/core/session/AgentLoop.ts +501 -0
  109. package/src/core/session/SessionManager.d.ts.map +1 -0
  110. package/src/core/session/SessionManager.test.ts +183 -0
  111. package/src/core/session/SessionManager.ts +460 -0
  112. package/src/core/session/index.d.ts.map +1 -0
  113. package/src/core/session/index.ts +3 -0
  114. package/src/core/telemetry/Telemetry.d.ts.map +1 -0
  115. package/src/core/telemetry/Telemetry.ts +90 -0
  116. package/src/core/telemetry/TelemetryService.ts +531 -0
  117. package/src/core/telemetry/index.d.ts.map +1 -0
  118. package/src/core/telemetry/index.ts +12 -0
  119. package/src/core/testing/AutoFixer.ts +385 -0
  120. package/src/core/testing/ErrorAnalyzer.ts +499 -0
  121. package/src/core/testing/TestRunner.ts +265 -0
  122. package/src/core/testing/agent-cli-tests.ts +538 -0
  123. package/src/core/testing/index.ts +11 -0
  124. package/src/core/tools/ToolRegistry.d.ts.map +1 -0
  125. package/src/core/tools/ToolRegistry.test.ts +206 -0
  126. package/src/core/tools/ToolRegistry.ts +260 -0
  127. package/src/core/tools/impl/EditFileTool.d.ts.map +1 -0
  128. package/src/core/tools/impl/EditFileTool.ts +97 -0
  129. package/src/core/tools/impl/ListDirectoryTool.d.ts.map +1 -0
  130. package/src/core/tools/impl/ListDirectoryTool.ts +142 -0
  131. package/src/core/tools/impl/MemoryTool.d.ts.map +1 -0
  132. package/src/core/tools/impl/MemoryTool.ts +102 -0
  133. package/src/core/tools/impl/ReadFileTool.d.ts.map +1 -0
  134. package/src/core/tools/impl/ReadFileTool.ts +58 -0
  135. package/src/core/tools/impl/SearchContentTool.d.ts.map +1 -0
  136. package/src/core/tools/impl/SearchContentTool.ts +94 -0
  137. package/src/core/tools/impl/SearchFileTool.d.ts.map +1 -0
  138. package/src/core/tools/impl/SearchFileTool.ts +61 -0
  139. package/src/core/tools/impl/ShellTool.d.ts.map +1 -0
  140. package/src/core/tools/impl/ShellTool.ts +118 -0
  141. package/src/core/tools/impl/TaskTool.d.ts.map +1 -0
  142. package/src/core/tools/impl/TaskTool.ts +207 -0
  143. package/src/core/tools/impl/TodoTool.d.ts.map +1 -0
  144. package/src/core/tools/impl/TodoTool.ts +122 -0
  145. package/src/core/tools/impl/WebFetchTool.d.ts.map +1 -0
  146. package/src/core/tools/impl/WebFetchTool.ts +103 -0
  147. package/src/core/tools/impl/WebSearchTool.d.ts.map +1 -0
  148. package/src/core/tools/impl/WebSearchTool.ts +89 -0
  149. package/src/core/tools/impl/WriteFileTool.d.ts.map +1 -0
  150. package/src/core/tools/impl/WriteFileTool.ts +49 -0
  151. package/src/core/tools/impl/index.d.ts.map +1 -0
  152. package/src/core/tools/impl/index.ts +16 -0
  153. package/src/core/tools/index.d.ts.map +1 -0
  154. package/src/core/tools/index.ts +7 -0
  155. package/src/core/tools/schemas/execution.d.ts.map +1 -0
  156. package/src/core/tools/schemas/execution.ts +42 -0
  157. package/src/core/tools/schemas/file.d.ts.map +1 -0
  158. package/src/core/tools/schemas/file.ts +119 -0
  159. package/src/core/tools/schemas/index.d.ts.map +1 -0
  160. package/src/core/tools/schemas/index.ts +11 -0
  161. package/src/core/tools/schemas/memory.d.ts.map +1 -0
  162. package/src/core/tools/schemas/memory.ts +52 -0
  163. package/src/core/tools/schemas/orchestration.d.ts.map +1 -0
  164. package/src/core/tools/schemas/orchestration.ts +44 -0
  165. package/src/core/tools/schemas/search.d.ts.map +1 -0
  166. package/src/core/tools/schemas/search.ts +112 -0
  167. package/src/core/tools/schemas/todo.d.ts.map +1 -0
  168. package/src/core/tools/schemas/todo.ts +32 -0
  169. package/src/core/tools/schemas/web.d.ts.map +1 -0
  170. package/src/core/tools/schemas/web.ts +86 -0
  171. package/src/core/types/config.d.ts.map +1 -0
  172. package/src/core/types/config.ts +200 -0
  173. package/src/core/types/errors.d.ts.map +1 -0
  174. package/src/core/types/errors.ts +204 -0
  175. package/src/core/types/index.d.ts.map +1 -0
  176. package/src/core/types/index.ts +8 -0
  177. package/src/core/types/session.d.ts.map +1 -0
  178. package/src/core/types/session.ts +216 -0
  179. package/src/core/types/tools.d.ts.map +1 -0
  180. package/src/core/types/tools.ts +157 -0
  181. package/src/core/utils/CheckpointManager.d.ts.map +1 -0
  182. package/src/core/utils/CheckpointManager.ts +327 -0
  183. package/src/core/utils/Logger.d.ts.map +1 -0
  184. package/src/core/utils/Logger.ts +98 -0
  185. package/src/core/utils/RetryManager.ts +471 -0
  186. package/src/core/utils/TokenCounter.d.ts.map +1 -0
  187. package/src/core/utils/TokenCounter.ts +414 -0
  188. package/src/core/utils/VectorMemoryStore.ts +440 -0
  189. package/src/core/utils/helpers.d.ts.map +1 -0
  190. package/src/core/utils/helpers.ts +89 -0
  191. package/src/core/utils/index.d.ts.map +1 -0
  192. package/src/core/utils/index.ts +19 -0
@@ -0,0 +1,525 @@
1
+ // ============================================================================
2
+ // SkillValidator - Validate skill definitions for quality and completeness
3
+ // Reference: WorkBuddy skill validation pipeline
4
+ // ============================================================================
5
+
6
+ import type { SkillDefinition, SkillMetadata } from './SkillRegistry.js';
7
+ import { readFile, stat, access } from 'node:fs/promises';
8
+ import { join, resolve } from 'node:path';
9
+
10
+ export interface ValidationIssue {
11
+ severity: 'error' | 'warning' | 'info';
12
+ code: string;
13
+ message: string;
14
+ suggestion?: string;
15
+ line?: number;
16
+ }
17
+
18
+ export interface ValidationResult {
19
+ valid: boolean;
20
+ issues: ValidationIssue[];
21
+ score: number; // 0-100 quality score
22
+ checkedAt: string;
23
+ }
24
+
25
+ // Validation rule definitions
26
+ const REQUIRED_METADATA_FIELDS: (keyof SkillMetadata)[] = ['name', 'description', 'version'];
27
+ const RECOMMENDED_METADATA_FIELDS: (keyof SkillMetadata)[] = ['tags', 'author', 'createdAt'];
28
+ const MIN_CONTENT_LENGTH = 100;
29
+ const RECOMMENDED_CONTENT_LENGTH = 500;
30
+ const MAX_CONTENT_LENGTH = 50000;
31
+
32
+ export class SkillValidator {
33
+ /**
34
+ * Validate a skill definition comprehensively.
35
+ */
36
+ async validate(skill: SkillDefinition): Promise<ValidationResult> {
37
+ const issues: ValidationIssue[] = [];
38
+
39
+ // Step 1: Metadata validation
40
+ this.validateMetadata(skill.metadata, issues);
41
+
42
+ // Step 2: Content validation
43
+ this.validateContent(skill.content, issues);
44
+
45
+ // Step 3: Structural validation
46
+ this.validateStructure(skill.content, issues);
47
+
48
+ // Step 4: Security validation
49
+ this.validateSecurity(skill.content, issues);
50
+
51
+ // Step 5: Quality scoring
52
+ this.validateQuality(skill, issues);
53
+
54
+ const hasErrors = issues.some((i) => i.severity === 'error');
55
+ const score = this.calculateScore(issues);
56
+
57
+ return {
58
+ valid: !hasErrors,
59
+ issues,
60
+ score,
61
+ checkedAt: new Date().toISOString(),
62
+ };
63
+ }
64
+
65
+ /**
66
+ * Quick validation - only checks for blocking errors.
67
+ */
68
+ quickValidate(skill: SkillDefinition): ValidationIssue[] {
69
+ const issues: ValidationIssue[] = [];
70
+
71
+ // Only check critical fields
72
+ if (!skill.metadata.name) {
73
+ issues.push({
74
+ severity: 'error',
75
+ code: 'MISSING_NAME',
76
+ message: 'Skill name is required',
77
+ suggestion: 'Add a unique kebab-case name for this skill',
78
+ });
79
+ }
80
+
81
+ if (!skill.metadata.description) {
82
+ issues.push({
83
+ severity: 'error',
84
+ code: 'MISSING_DESCRIPTION',
85
+ message: 'Skill description is required',
86
+ suggestion: 'Add a one-line description of what this skill does',
87
+ });
88
+ }
89
+
90
+ if (!skill.content || skill.content.length < 20) {
91
+ issues.push({
92
+ severity: 'error',
93
+ code: 'EMPTY_CONTENT',
94
+ message: 'Skill content is too short or empty',
95
+ suggestion: 'Add detailed instructions for the AI agent to follow',
96
+ });
97
+ }
98
+
99
+ return issues;
100
+ }
101
+
102
+ /**
103
+ * Validate a skill file on disk.
104
+ */
105
+ async validateFile(filePath: string): Promise<ValidationResult> {
106
+ try {
107
+ const content = await readFile(filePath, 'utf-8');
108
+
109
+ // Parse as markdown - extract YAML frontmatter if present
110
+ const { metadata, body } = this.parseSkillFile(content, filePath);
111
+
112
+ const skill: SkillDefinition = {
113
+ metadata,
114
+ content: body,
115
+ };
116
+
117
+ return this.validate(skill);
118
+ } catch (err: any) {
119
+ return {
120
+ valid: false,
121
+ issues: [
122
+ {
123
+ severity: 'error',
124
+ code: 'FILE_READ_ERROR',
125
+ message: `Cannot read skill file: ${err.message}`,
126
+ },
127
+ ],
128
+ score: 0,
129
+ checkedAt: new Date().toISOString(),
130
+ };
131
+ }
132
+ }
133
+
134
+ /**
135
+ * Compare two versions of a skill and report differences.
136
+ */
137
+ async diff(oldSkill: SkillDefinition, newSkill: SkillDefinition): Promise<ValidationIssue[]> {
138
+ const issues: ValidationIssue[] = [];
139
+
140
+ // Version check
141
+ if (oldSkill.metadata.version && newSkill.metadata.version) {
142
+ if (this.compareVersions(oldSkill.metadata.version, newSkill.metadata.version) > 0) {
143
+ issues.push({
144
+ severity: 'warning',
145
+ code: 'VERSION_DOWNGRADE',
146
+ message: `Version decreased from ${oldSkill.metadata.version} to ${newSkill.metadata.version}`,
147
+ suggestion: 'Version should only increase. Consider bumping the version number.',
148
+ });
149
+ }
150
+ }
151
+
152
+ // Content size change
153
+ const sizeDiff = newSkill.content.length - oldSkill.content.length;
154
+ if (Math.abs(sizeDiff) > oldSkill.content.length * 0.5 && sizeDiff < 0) {
155
+ issues.push({
156
+ severity: 'warning',
157
+ code: 'SIGNIFICANT_SHRINKAGE',
158
+ message: `Content reduced by ${Math.abs(sizeDiff)} characters (${Math.round(Math.abs(sizeDiff) / oldSkill.content.length * 100)}%)`,
159
+ suggestion: 'Verify that important content was not accidentally removed',
160
+ });
161
+ }
162
+
163
+ // Name change
164
+ if (oldSkill.metadata.name !== newSkill.metadata.name) {
165
+ issues.push({
166
+ severity: 'info',
167
+ code: 'NAME_CHANGED',
168
+ message: `Skill renamed from "${oldSkill.metadata.name}" to "${newSkill.metadata.name}"`,
169
+ });
170
+ }
171
+
172
+ // Tag changes
173
+ const oldTags = new Set(oldSkill.metadata.tags || []);
174
+ const newTags = new Set(newSkill.metadata.tags || []);
175
+ const removedTags = [...oldTags].filter((t) => !newTags.has(t));
176
+ const addedTags = [...newTags].filter((t) => !oldTags.has(t));
177
+
178
+ if (removedTags.length > 0) {
179
+ issues.push({
180
+ severity: 'info',
181
+ code: 'TAGS_REMOVED',
182
+ message: `Tags removed: ${removedTags.join(', ')}`,
183
+ });
184
+ }
185
+ if (addedTags.length > 0) {
186
+ issues.push({
187
+ severity: 'info',
188
+ code: 'TAGS_ADDED',
189
+ message: `Tags added: ${addedTags.join(', ')}`,
190
+ });
191
+ }
192
+
193
+ return issues;
194
+ }
195
+
196
+ // --- Private validation methods ---
197
+
198
+ private validateMetadata(metadata: SkillMetadata, issues: ValidationIssue[]): void {
199
+ // Required fields
200
+ for (const field of REQUIRED_METADATA_FIELDS) {
201
+ if (!metadata[field]) {
202
+ issues.push({
203
+ severity: 'error',
204
+ code: `MISSING_${field.toUpperCase()}`,
205
+ message: `Required metadata field "${field}" is missing or empty`,
206
+ suggestion: `Add "${field}" to the skill metadata`,
207
+ });
208
+ }
209
+ }
210
+
211
+ // Recommended fields
212
+ for (const field of RECOMMENDED_METADATA_FIELDS) {
213
+ if (!metadata[field]) {
214
+ issues.push({
215
+ severity: 'info',
216
+ code: `MISSING_RECOMMENDED_${field.toUpperCase()}`,
217
+ message: `Recommended metadata field "${field}" is missing`,
218
+ suggestion: `Consider adding "${field}" for better discoverability`,
219
+ });
220
+ }
221
+ }
222
+
223
+ // Name format validation
224
+ if (metadata.name) {
225
+ if (!/^[a-z0-9][a-z0-9-]*[a-z0-9]$/.test(metadata.name) && metadata.name.length > 1) {
226
+ issues.push({
227
+ severity: 'warning',
228
+ code: 'INVALID_NAME_FORMAT',
229
+ message: `Skill name "${metadata.name}" should be lowercase kebab-case`,
230
+ suggestion: 'Use only lowercase letters, numbers, and hyphens. Example: "react-component-generator"',
231
+ });
232
+ }
233
+
234
+ if (metadata.name.length > 50) {
235
+ issues.push({
236
+ severity: 'warning',
237
+ code: 'NAME_TOO_LONG',
238
+ message: `Skill name is ${metadata.name.length} characters, max 50 recommended`,
239
+ });
240
+ }
241
+ }
242
+
243
+ // Description length
244
+ if (metadata.description) {
245
+ if (metadata.description.length < 10) {
246
+ issues.push({
247
+ severity: 'warning',
248
+ code: 'DESCRIPTION_TOO_SHORT',
249
+ message: 'Description should be at least 10 characters for better discoverability',
250
+ });
251
+ } else if (metadata.description.length > 200) {
252
+ issues.push({
253
+ severity: 'info',
254
+ code: 'DESCRIPTION_TOO_LONG',
255
+ message: 'Description is long, consider keeping it under 200 characters for display',
256
+ });
257
+ }
258
+ }
259
+
260
+ // Version format
261
+ if (metadata.version) {
262
+ if (!/^\d+\.\d+\.\d+/.test(metadata.version)) {
263
+ issues.push({
264
+ severity: 'warning',
265
+ code: 'INVALID_VERSION_FORMAT',
266
+ message: `Version "${metadata.version}" does not follow semver (x.y.z)`,
267
+ suggestion: 'Use semantic versioning like "1.0.0", "0.2.1"',
268
+ });
269
+ }
270
+ }
271
+ }
272
+
273
+ private validateContent(content: string, issues: ValidationIssue[]): void {
274
+ if (!content || content.length === 0) {
275
+ issues.push({
276
+ severity: 'error',
277
+ code: 'EMPTY_CONTENT',
278
+ message: 'Skill content is empty',
279
+ suggestion: 'Add instructions, patterns, and examples for the AI agent',
280
+ });
281
+ return;
282
+ }
283
+
284
+ // Minimum content length
285
+ if (content.length < MIN_CONTENT_LENGTH) {
286
+ issues.push({
287
+ severity: 'warning',
288
+ code: 'CONTENT_TOO_SHORT',
289
+ message: `Content is ${content.length} characters, minimum recommended is ${MIN_CONTENT_LENGTH}`,
290
+ suggestion: 'Add more detailed instructions and examples to make the skill more useful',
291
+ });
292
+ }
293
+
294
+ // Maximum content length
295
+ if (content.length > MAX_CONTENT_LENGTH) {
296
+ issues.push({
297
+ severity: 'warning',
298
+ code: 'CONTENT_TOO_LONG',
299
+ message: `Content is ${content.length} characters, max recommended is ${MAX_CONTENT_LENGTH}`,
300
+ suggestion: 'Consider splitting into multiple specialized skills or trimming verbose sections',
301
+ });
302
+ }
303
+
304
+ // Check for placeholder content
305
+ const placeholderPatterns = [
306
+ /TODO.*implement/i,
307
+ /placeholder/i,
308
+ /FIXME/i,
309
+ /\[insert.*here\]/i,
310
+ /lorem ipsum/i,
311
+ /your content here/i,
312
+ ];
313
+
314
+ for (const pattern of placeholderPatterns) {
315
+ if (pattern.test(content)) {
316
+ issues.push({
317
+ severity: 'error',
318
+ code: 'PLACEHOLDER_CONTENT',
319
+ message: 'Content contains placeholder text that should be filled in',
320
+ suggestion: 'Replace all TODO/placeholder markers with actual instructions',
321
+ });
322
+ break;
323
+ }
324
+ }
325
+ }
326
+
327
+ private validateStructure(content: string, issues: ValidationIssue[]): void {
328
+ // Check for markdown headers (indicates good structure)
329
+ const headerMatches = content.match(/^#{1,3}\s+.+$/gm);
330
+ if (!headerMatches || headerMatches.length < 2) {
331
+ issues.push({
332
+ severity: 'info',
333
+ code: 'POOR_STRUCTURE',
334
+ message: 'Content lacks section headers for organization',
335
+ suggestion: 'Use markdown headers (##) to organize content into clear sections',
336
+ });
337
+ }
338
+
339
+ // Check for code examples
340
+ const codeBlockMatches = content.match(/```[\s\S]*?```/g);
341
+ if (!codeBlockMatches || codeBlockMatches.length === 0) {
342
+ issues.push({
343
+ severity: 'info',
344
+ code: 'NO_CODE_EXAMPLES',
345
+ message: 'No code examples found in the skill',
346
+ suggestion: 'Include code examples to help the agent understand the expected patterns',
347
+ });
348
+ }
349
+
350
+ // Check for numbered or bullet lists (indicates step-by-step instructions)
351
+ const listMatches = content.match(/(?:^[\d]+\.\s|^\s*[-*]\s)/gm);
352
+ if (!listMatches || listMatches.length < 2) {
353
+ issues.push({
354
+ severity: 'info',
355
+ code: 'NO_PROCEDURAL_STEPS',
356
+ message: 'No procedural steps found (numbered lists or bullet points)',
357
+ suggestion: 'Add step-by-step instructions for the agent to follow',
358
+ });
359
+ }
360
+
361
+ // Check for trigger/activation conditions
362
+ const triggerPatterns = [
363
+ /(?:when to use|trigger|activation|use this skill|when.*should)/i,
364
+ /(?:applicable|适用|触发)/i,
365
+ ];
366
+ const hasTrigger = triggerPatterns.some((p) => p.test(content));
367
+ if (!hasTrigger) {
368
+ issues.push({
369
+ severity: 'info',
370
+ code: 'NO_TRIGGER_CONDITIONS',
371
+ message: 'No trigger/activation conditions specified',
372
+ suggestion: 'Add a section describing when this skill should be activated (e.g., "Use this skill when...")',
373
+ });
374
+ }
375
+ }
376
+
377
+ private validateSecurity(content: string, issues: ValidationIssue[]): void {
378
+ // Check for potentially dangerous instructions
379
+ const dangerousPatterns = [
380
+ { pattern: /rm\s+-rf\s+\/|del\s+\/S\s+\/Q/i, message: 'Contains destructive file system commands', code: 'DANGEROUS_FS_COMMAND' },
381
+ { pattern: /DROP\s+TABLE|DELETE\s+FROM\s+\w+(?!\s+WHERE)/i, message: 'Contains potentially dangerous SQL without WHERE clause', code: 'DANGEROUS_SQL' },
382
+ { pattern: /eval\s*\(|Function\s*\(/, message: 'Contains eval() or Function() constructor usage', code: 'DANGEROUS_EVAL' },
383
+ { pattern: /curl.*\|\s*(?:bash|sh)/i, message: 'Contains pipe-to-shell pattern (curl | bash)', code: 'PIPE_TO_SHELL' },
384
+ ];
385
+
386
+ for (const { pattern, message, code } of dangerousPatterns) {
387
+ if (pattern.test(content)) {
388
+ issues.push({
389
+ severity: 'warning',
390
+ code,
391
+ message: `Security: ${message}`,
392
+ suggestion: 'Review and add safety guards. If intentional, document why this is needed.',
393
+ });
394
+ }
395
+ }
396
+ }
397
+
398
+ private validateQuality(skill: SkillDefinition, issues: ValidationIssue[]): void {
399
+ // Check for auto-generated flag without human review
400
+ if (skill.metadata.autoGenerated && !skill.metadata.reviewedAt) {
401
+ issues.push({
402
+ severity: 'info',
403
+ code: 'AUTO_GENERATED_UNREVIEWED',
404
+ message: 'Auto-generated skill has not been reviewed',
405
+ suggestion: 'Have a human review and update the "reviewedAt" field after verification',
406
+ });
407
+ }
408
+ }
409
+
410
+ /**
411
+ * Calculate a quality score (0-100) based on issues.
412
+ */
413
+ private calculateScore(issues: ValidationIssue[]): number {
414
+ let score = 100;
415
+
416
+ for (const issue of issues) {
417
+ switch (issue.severity) {
418
+ case 'error':
419
+ score -= 25;
420
+ break;
421
+ case 'warning':
422
+ score -= 10;
423
+ break;
424
+ case 'info':
425
+ score -= 3;
426
+ break;
427
+ }
428
+ }
429
+
430
+ // Bonus for having good content length
431
+ const contentIssues = issues.filter(
432
+ (i) => i.code.includes('CONTENT') && i.severity !== 'error'
433
+ );
434
+ if (contentIssues.length === 0) {
435
+ score += 5; // Bonus for good content sizing
436
+ }
437
+
438
+ return Math.max(0, Math.min(100, score));
439
+ }
440
+
441
+ /**
442
+ * Parse a SKILL.md file with optional YAML frontmatter.
443
+ */
444
+ private parseSkillFile(
445
+ content: string,
446
+ filePath: string
447
+ ): { metadata: SkillMetadata; body: string } {
448
+ const defaultMetadata: SkillMetadata = {
449
+ name: filePath ? filePath.replace(/\.md$/, '').split(/[\\/]/).pop() || 'unknown' : 'unknown',
450
+ description: '',
451
+ version: '0.1.0',
452
+ tags: [],
453
+ createdAt: new Date().toISOString(),
454
+ updatedAt: new Date().toISOString(),
455
+ };
456
+
457
+ // Check for YAML frontmatter
458
+ const frontmatterMatch = content.match(/^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/);
459
+ if (frontmatterMatch) {
460
+ const yamlContent = frontmatterMatch[1];
461
+ const body = frontmatterMatch[2].trim();
462
+
463
+ const metadata: Record<string, any> = {};
464
+ for (const line of yamlContent.split('\n')) {
465
+ const colonIndex = line.indexOf(':');
466
+ if (colonIndex === -1) continue;
467
+
468
+ const key = line.slice(0, colonIndex).trim();
469
+ let value = line.slice(colonIndex + 1).trim();
470
+
471
+ // Remove quotes
472
+ if ((value.startsWith('"') && value.endsWith('"')) ||
473
+ (value.startsWith("'") && value.endsWith("'"))) {
474
+ value = value.slice(1, -1);
475
+ }
476
+
477
+ // Parse arrays
478
+ if (value.startsWith('[') && value.endsWith(']')) {
479
+ try {
480
+ metadata[key] = JSON.parse(value);
481
+ } catch {
482
+ metadata[key] = value;
483
+ }
484
+ } else {
485
+ metadata[key] = value;
486
+ }
487
+ }
488
+
489
+ return {
490
+ metadata: {
491
+ ...defaultMetadata,
492
+ ...metadata,
493
+ name: metadata.name || defaultMetadata.name,
494
+ tags: metadata.tags || [],
495
+ },
496
+ body,
497
+ };
498
+ }
499
+
500
+ // No frontmatter - use defaults
501
+ return {
502
+ metadata: defaultMetadata,
503
+ body: content.trim(),
504
+ };
505
+ }
506
+
507
+ /**
508
+ * Compare two semver version strings.
509
+ * Returns: -1 (a < b), 0 (equal), 1 (a > b)
510
+ */
511
+ private compareVersions(a: string, b: string): number {
512
+ const parseVersion = (v: string): number[] =>
513
+ v.split('.').map((n) => parseInt(n, 10) || 0);
514
+
515
+ const va = parseVersion(a);
516
+ const vb = parseVersion(b);
517
+
518
+ for (let i = 0; i < 3; i++) {
519
+ if (va[i] < vb[i]) return -1;
520
+ if (va[i] > vb[i]) return 1;
521
+ }
522
+
523
+ return 0;
524
+ }
525
+ }
@@ -0,0 +1,15 @@
1
+ // ============================================================================
2
+ // extensions - Skill registry, auto-generation, validation, and installation
3
+ // ============================================================================
4
+
5
+ export { SkillRegistry } from './SkillRegistry.js';
6
+ export type { SkillMetadata, SkillDefinition, SkillSearchParams } from './SkillRegistry.js';
7
+ export { SkillGenerator } from './SkillGenerator.js';
8
+ export type { GenerationResult, GenerationOptions } from './SkillGenerator.js';
9
+ export { SkillValidator } from './SkillValidator.js';
10
+ export type { ValidationResult, ValidationIssue } from './SkillValidator.js';
11
+ export { SkillInstaller, POPULAR_SKILL_REPOS, installSuperpowers } from './SkillInstaller.js';
12
+ export type { SkillInstallOptions, InstalledSkill } from './SkillInstaller.js';
13
+
14
+ /** Skill type alias for convenience */
15
+ export type Skill = import('./SkillRegistry.js').SkillDefinition;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAKA,cAAc,kBAAkB,CAAC;AAGjC,cAAc,kBAAkB,CAAC;AAGjC,cAAc,kBAAkB,CAAC;AAGjC,cAAc,oBAAoB,CAAC;AAGnC,cAAc,oBAAoB,CAAC;AAGnC,cAAc,qBAAqB,CAAC;AAGpC,cAAc,gBAAgB,CAAC;AAG/B,cAAc,mBAAmB,CAAC;AAGlC,cAAc,iBAAiB,CAAC;AAGhC,cAAc,sBAAsB,CAAC;AAGrC,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,42 @@
1
+ // ============================================================================
2
+ // @nova-cli/core - Main barrel export
3
+ // ============================================================================
4
+
5
+ // Types
6
+ export * from './types/index.js';
7
+
8
+ // Tools
9
+ export * from './tools/index.js';
10
+
11
+ // Model
12
+ export * from './model/index.js';
13
+
14
+ // Session
15
+ export * from './session/index.js';
16
+
17
+ // Context
18
+ export * from './context/index.js';
19
+
20
+ // Security
21
+ export * from './security/index.js';
22
+
23
+ // MCP
24
+ export * from './mcp/index.js';
25
+
26
+ // Config
27
+ export * from './config/index.js';
28
+
29
+ // Auth
30
+ export * from './auth/index.js';
31
+
32
+ // Telemetry
33
+ export * from './telemetry/index.js';
34
+
35
+ // Utils
36
+ export * from './utils/index.js';
37
+
38
+ // Agents (Multi-agent orchestration)
39
+ export * from './agents/index.js';
40
+
41
+ // Audit (Audit logging)
42
+ export * from './audit/index.js';
@@ -0,0 +1 @@
1
+ {"version":3,"file":"McpManager.d.ts","sourceRoot":"","sources":["McpManager.ts"],"names":[],"mappings":"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"}