@bluefly/openstandardagents 0.3.0 → 0.3.1

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 (87) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/README.md +58 -218
  3. package/dist/cli/commands/diff.command.d.ts +7 -0
  4. package/dist/cli/commands/diff.command.d.ts.map +1 -0
  5. package/dist/cli/commands/diff.command.js +181 -0
  6. package/dist/cli/commands/diff.command.js.map +1 -0
  7. package/dist/cli/commands/docs.command.d.ts +7 -0
  8. package/dist/cli/commands/docs.command.d.ts.map +1 -0
  9. package/dist/cli/commands/docs.command.js +274 -0
  10. package/dist/cli/commands/docs.command.js.map +1 -0
  11. package/dist/cli/commands/lint.command.d.ts +7 -0
  12. package/dist/cli/commands/lint.command.d.ts.map +1 -0
  13. package/dist/cli/commands/lint.command.js +342 -0
  14. package/dist/cli/commands/lint.command.js.map +1 -0
  15. package/dist/cli/commands/serve.command.d.ts +7 -0
  16. package/dist/cli/commands/serve.command.d.ts.map +1 -0
  17. package/dist/cli/commands/serve.command.js +232 -0
  18. package/dist/cli/commands/serve.command.js.map +1 -0
  19. package/dist/cli/index.js +4 -0
  20. package/dist/cli/index.js.map +1 -1
  21. package/dist/di-container.d.ts.map +1 -1
  22. package/dist/di-container.js +3 -0
  23. package/dist/di-container.js.map +1 -1
  24. package/dist/services/git.service.d.ts +40 -0
  25. package/dist/services/git.service.d.ts.map +1 -0
  26. package/dist/services/git.service.js +122 -0
  27. package/dist/services/git.service.js.map +1 -0
  28. package/dist/spec/v0.3.1/UNIFIED-SCHEMA.md +120 -0
  29. package/dist/spec/v0.3.1/adapters/drupal.md +541 -0
  30. package/dist/spec/v0.3.1/adapters/symfony.md +659 -0
  31. package/dist/spec/v0.3.1/agent-test.schema.json +75 -0
  32. package/dist/spec/v0.3.1/examples/drupal-content-writer.ossa.yaml +110 -0
  33. package/dist/spec/v0.3.1/examples/drupal-moderation-assistant.ossa.yaml +96 -0
  34. package/dist/spec/v0.3.1/examples/quick-wins/complete-agent-with-quick-wins.ossa.yaml +144 -0
  35. package/dist/spec/v0.3.1/extensions/drupal.md +417 -0
  36. package/dist/spec/v0.3.1/ossa-0.3.0.schema.json +2787 -0
  37. package/dist/spec/v0.3.1/ossa-0.3.1.schema.json +2806 -0
  38. package/dist/spec/v0.3.1/protocols/sse.md +494 -0
  39. package/dist/spec/v0.3.1/protocols/webrtc.md +600 -0
  40. package/dist/spec/v0.3.1/protocols/websocket.md +362 -0
  41. package/dist/spec/v0.3.1/schemas/agent-unified.yaml +165 -0
  42. package/dist/spec/v0.3.1/schemas/capabilities.yaml +102 -0
  43. package/dist/spec/v0.3.1/schemas/functions.yaml +75 -0
  44. package/dist/spec/v0.3.1/schemas/messaging/channel.schema.json +245 -0
  45. package/dist/spec/v0.3.1/schemas/messaging/delivery-receipt.schema.json +192 -0
  46. package/dist/spec/v0.3.1/schemas/messaging/message.schema.json +205 -0
  47. package/dist/spec/v0.3.1/schemas/messaging/subscription.schema.json +214 -0
  48. package/dist/spec/v0.3.1/schemas/runtime.yaml +102 -0
  49. package/dist/spec/v0.3.1/schemas/taxonomy.yaml +533 -0
  50. package/dist/spec/v0.3.1/schemas/unified-llm.yaml +91 -0
  51. package/dist/spec/v0.3.1/taxonomy.yaml +256 -0
  52. package/dist/testing/fixtures.d.ts.map +1 -1
  53. package/dist/testing/fixtures.js +3 -2
  54. package/dist/testing/fixtures.js.map +1 -1
  55. package/package.json +3 -31
  56. package/spec/v0.3.1/UNIFIED-SCHEMA.md +120 -0
  57. package/spec/v0.3.1/adapters/drupal.md +541 -0
  58. package/spec/v0.3.1/adapters/symfony.md +659 -0
  59. package/spec/v0.3.1/agent-test.schema.json +75 -0
  60. package/spec/v0.3.1/examples/drupal-content-writer.ossa.yaml +110 -0
  61. package/spec/v0.3.1/examples/drupal-moderation-assistant.ossa.yaml +96 -0
  62. package/spec/v0.3.1/examples/quick-wins/complete-agent-with-quick-wins.ossa.yaml +144 -0
  63. package/spec/v0.3.1/extensions/drupal.md +417 -0
  64. package/spec/v0.3.1/ossa-0.3.0.schema.json +2787 -0
  65. package/spec/v0.3.1/ossa-0.3.1.schema.json +2806 -0
  66. package/spec/v0.3.1/protocols/sse.md +494 -0
  67. package/spec/v0.3.1/protocols/webrtc.md +600 -0
  68. package/spec/v0.3.1/protocols/websocket.md +362 -0
  69. package/spec/v0.3.1/schemas/agent-unified.yaml +165 -0
  70. package/spec/v0.3.1/schemas/capabilities.yaml +102 -0
  71. package/spec/v0.3.1/schemas/functions.yaml +75 -0
  72. package/spec/v0.3.1/schemas/messaging/channel.schema.json +245 -0
  73. package/spec/v0.3.1/schemas/messaging/delivery-receipt.schema.json +192 -0
  74. package/spec/v0.3.1/schemas/messaging/message.schema.json +205 -0
  75. package/spec/v0.3.1/schemas/messaging/subscription.schema.json +214 -0
  76. package/spec/v0.3.1/schemas/runtime.yaml +102 -0
  77. package/spec/v0.3.1/schemas/taxonomy.yaml +533 -0
  78. package/spec/v0.3.1/schemas/unified-llm.yaml +91 -0
  79. package/spec/v0.3.1/taxonomy.yaml +256 -0
  80. package/dist/types/generated/ossa-0.3.0.types.d.ts +0 -316
  81. package/dist/types/generated/ossa-0.3.0.types.d.ts.map +0 -1
  82. package/dist/types/generated/ossa-0.3.0.types.js +0 -8
  83. package/dist/types/generated/ossa-0.3.0.types.js.map +0 -1
  84. package/dist/types/generated/ossa-0.3.0.zod.d.ts +0 -17
  85. package/dist/types/generated/ossa-0.3.0.zod.d.ts.map +0 -1
  86. package/dist/types/generated/ossa-0.3.0.zod.js +0 -3
  87. package/dist/types/generated/ossa-0.3.0.zod.js.map +0 -1
@@ -0,0 +1,274 @@
1
+ /**
2
+ * OSSA Docs Command
3
+ * Generate documentation from agent manifests
4
+ */
5
+ import chalk from 'chalk';
6
+ import { Command } from 'commander';
7
+ import * as fs from 'fs';
8
+ import * as path from 'path';
9
+ import { container } from '../../di-container.js';
10
+ import { ManifestRepository } from '../../repositories/manifest.repository.js';
11
+ function generateMarkdown(manifests) {
12
+ let md = '# OSSA Agent Documentation\n\n';
13
+ md += `Generated from ${manifests.length} agent manifest(s)\n\n`;
14
+ for (const { manifest, path: filePath } of manifests) {
15
+ const name = manifest.metadata?.name || manifest.agent?.name || 'Unknown';
16
+ const version = manifest.metadata?.version || manifest.agent?.version || 'Unknown';
17
+ const description = manifest.metadata?.description || manifest.agent?.description || '';
18
+ md += `## ${name}\n\n`;
19
+ md += `**Version:** ${version}\n\n`;
20
+ if (description) {
21
+ md += `${description}\n\n`;
22
+ }
23
+ // Role
24
+ if (manifest.spec?.role || manifest.agent?.role) {
25
+ md += `### Role\n\n${manifest.spec?.role || manifest.agent?.role}\n\n`;
26
+ }
27
+ // LLM Configuration
28
+ const llm = manifest.spec?.llm || manifest.agent?.llm;
29
+ if (llm) {
30
+ md += `### LLM Configuration\n\n`;
31
+ md += `- **Provider:** ${llm.provider || 'N/A'}\n`;
32
+ md += `- **Model:** ${llm.model || 'N/A'}\n`;
33
+ if (llm.temperature !== undefined) {
34
+ md += `- **Temperature:** ${llm.temperature}\n`;
35
+ }
36
+ md += `\n`;
37
+ }
38
+ // Capabilities
39
+ const capabilities = manifest.agent?.capabilities || [];
40
+ if (capabilities.length > 0) {
41
+ md += `### Capabilities\n\n`;
42
+ for (const cap of capabilities) {
43
+ md += `#### ${cap.name}\n\n`;
44
+ if (cap.description) {
45
+ md += `${cap.description}\n\n`;
46
+ }
47
+ md += `**Input Schema:**\n\`\`\`json\n${JSON.stringify(cap.input_schema, null, 2)}\n\`\`\`\n\n`;
48
+ md += `**Output Schema:**\n\`\`\`json\n${JSON.stringify(cap.output_schema, null, 2)}\n\`\`\`\n\n`;
49
+ }
50
+ }
51
+ // Tools
52
+ if (manifest.spec?.tools && manifest.spec.tools.length > 0) {
53
+ md += `### Tools\n\n`;
54
+ for (const tool of manifest.spec.tools) {
55
+ md += `- **${tool.name || tool.type}** (${tool.type})\n`;
56
+ }
57
+ md += `\n`;
58
+ }
59
+ md += `---\n\n`;
60
+ }
61
+ return md;
62
+ }
63
+ function generateHTML(manifests) {
64
+ let html = `<!DOCTYPE html>
65
+ <html>
66
+ <head>
67
+ <title>OSSA Agent Documentation</title>
68
+ <style>
69
+ body { font-family: system-ui, sans-serif; max-width: 1200px; margin: 0 auto; padding: 20px; }
70
+ h1 { color: #333; }
71
+ h2 { color: #555; border-bottom: 2px solid #eee; padding-bottom: 10px; }
72
+ h3 { color: #777; }
73
+ code { background: #f5f5f5; padding: 2px 6px; border-radius: 3px; }
74
+ pre { background: #f5f5f5; padding: 15px; border-radius: 5px; overflow-x: auto; }
75
+ .nav { background: #f9f9f9; padding: 15px; border-radius: 5px; margin-bottom: 20px; }
76
+ .nav a { margin-right: 15px; text-decoration: none; color: #0066cc; }
77
+ </style>
78
+ </head>
79
+ <body>
80
+ <h1>OSSA Agent Documentation</h1>
81
+ <p>Generated from ${manifests.length} agent manifest(s)</p>
82
+ <div class="nav">
83
+ `;
84
+ for (const { manifest } of manifests) {
85
+ const name = manifest.metadata?.name || manifest.agent?.name || 'Unknown';
86
+ html += ` <a href="#${name.toLowerCase().replace(/\s+/g, '-')}">${name}</a>\n`;
87
+ }
88
+ html += ` </div>\n`;
89
+ for (const { manifest } of manifests) {
90
+ const name = manifest.metadata?.name || manifest.agent?.name || 'Unknown';
91
+ const version = manifest.metadata?.version || manifest.agent?.version || 'Unknown';
92
+ const description = manifest.metadata?.description || manifest.agent?.description || '';
93
+ html += ` <h2 id="${name.toLowerCase().replace(/\s+/g, '-')}">${name}</h2>\n`;
94
+ html += ` <p><strong>Version:</strong> ${version}</p>\n`;
95
+ if (description) {
96
+ html += ` <p>${description}</p>\n`;
97
+ }
98
+ if (manifest.spec?.role || manifest.agent?.role) {
99
+ html += ` <h3>Role</h3>\n <p>${manifest.spec?.role || manifest.agent?.role}</p>\n`;
100
+ }
101
+ const llm = manifest.spec?.llm || manifest.agent?.llm;
102
+ if (llm) {
103
+ html += ` <h3>LLM Configuration</h3>\n <ul>\n`;
104
+ html += ` <li><strong>Provider:</strong> ${llm.provider || 'N/A'}</li>\n`;
105
+ html += ` <li><strong>Model:</strong> ${llm.model || 'N/A'}</li>\n`;
106
+ if (llm.temperature !== undefined) {
107
+ html += ` <li><strong>Temperature:</strong> ${llm.temperature}</li>\n`;
108
+ }
109
+ html += ` </ul>\n`;
110
+ }
111
+ const capabilities = manifest.agent?.capabilities || [];
112
+ if (capabilities.length > 0) {
113
+ html += ` <h3>Capabilities</h3>\n`;
114
+ for (const cap of capabilities) {
115
+ html += ` <h4>${cap.name}</h4>\n`;
116
+ if (cap.description) {
117
+ html += ` <p>${cap.description}</p>\n`;
118
+ }
119
+ html += ` <p><strong>Input Schema:</strong></p>\n`;
120
+ html += ` <pre><code>${JSON.stringify(cap.input_schema, null, 2)}</code></pre>\n`;
121
+ html += ` <p><strong>Output Schema:</strong></p>\n`;
122
+ html += ` <pre><code>${JSON.stringify(cap.output_schema, null, 2)}</code></pre>\n`;
123
+ }
124
+ }
125
+ html += ` <hr>\n`;
126
+ }
127
+ html += `</body>\n</html>`;
128
+ return html;
129
+ }
130
+ function generateOpenAPI(manifests) {
131
+ const openapi = {
132
+ openapi: '3.1.0',
133
+ info: {
134
+ title: 'OSSA Agents API',
135
+ version: '0.3.0',
136
+ description: 'API documentation generated from OSSA agent manifests',
137
+ },
138
+ paths: {},
139
+ components: {
140
+ schemas: {},
141
+ },
142
+ };
143
+ for (const { manifest } of manifests) {
144
+ const agentName = manifest.metadata?.name || manifest.agent?.name || 'agent';
145
+ const capabilities = manifest.agent?.capabilities || [];
146
+ for (const cap of capabilities) {
147
+ const path = `/agents/${agentName}/capabilities/${cap.name}`;
148
+ openapi.paths[path] = {
149
+ post: {
150
+ summary: cap.description || cap.name,
151
+ requestBody: {
152
+ content: {
153
+ 'application/json': {
154
+ schema: cap.input_schema || {},
155
+ },
156
+ },
157
+ },
158
+ responses: {
159
+ '200': {
160
+ description: 'Success',
161
+ content: {
162
+ 'application/json': {
163
+ schema: cap.output_schema || {},
164
+ },
165
+ },
166
+ },
167
+ },
168
+ },
169
+ };
170
+ }
171
+ }
172
+ return openapi;
173
+ }
174
+ function generateCatalog(manifests) {
175
+ return {
176
+ version: '0.3.0',
177
+ generated: new Date().toISOString(),
178
+ agents: manifests.map(({ manifest, path: filePath }) => ({
179
+ name: manifest.metadata?.name || manifest.agent?.name,
180
+ version: manifest.metadata?.version || manifest.agent?.version,
181
+ description: manifest.metadata?.description || manifest.agent?.description,
182
+ role: manifest.spec?.role || manifest.agent?.role,
183
+ source: filePath,
184
+ capabilities: (manifest.agent?.capabilities || []).map((cap) => ({
185
+ name: cap.name,
186
+ description: cap.description,
187
+ })),
188
+ })),
189
+ };
190
+ }
191
+ export const docsCommand = new Command('docs')
192
+ .argument('<path>', 'Path to OSSA manifest or directory')
193
+ .option('-f, --format <format>', 'Output format (markdown, html, openapi, catalog)', 'markdown')
194
+ .option('-o, --output <dir>', 'Output directory', '.')
195
+ .option('--catalog', 'Generate agent catalog JSON')
196
+ .description('Generate documentation from OSSA agent manifests')
197
+ .action(async (manifestPath, options) => {
198
+ try {
199
+ const manifestRepo = container.get(ManifestRepository);
200
+ const manifests = [];
201
+ const stat = fs.statSync(manifestPath);
202
+ if (stat.isDirectory()) {
203
+ const findManifests = async (dir) => {
204
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
205
+ for (const entry of entries) {
206
+ const fullPath = path.join(dir, entry.name);
207
+ if (entry.isDirectory() && entry.name !== 'node_modules' && entry.name !== 'dist') {
208
+ await findManifests(fullPath);
209
+ }
210
+ else if (entry.isFile() &&
211
+ (entry.name.endsWith('.ossa.yaml') || entry.name.endsWith('.ossa.yml'))) {
212
+ try {
213
+ const manifest = await manifestRepo.load(fullPath);
214
+ manifests.push({ path: fullPath, manifest });
215
+ }
216
+ catch (error) {
217
+ console.warn(chalk.yellow(`Failed to load ${fullPath}: ${error.message}`));
218
+ }
219
+ }
220
+ }
221
+ };
222
+ await findManifests(manifestPath);
223
+ }
224
+ else {
225
+ const manifest = await manifestRepo.load(manifestPath);
226
+ manifests.push({ path: manifestPath, manifest });
227
+ }
228
+ if (manifests.length === 0) {
229
+ console.error(chalk.red('No valid OSSA manifests found'));
230
+ process.exit(1);
231
+ }
232
+ const outputDir = path.resolve(options.output || '.');
233
+ if (!fs.existsSync(outputDir)) {
234
+ fs.mkdirSync(outputDir, { recursive: true });
235
+ }
236
+ console.log(chalk.blue(`Generating ${options.format} documentation from ${manifests.length} manifest(s)...`));
237
+ let output;
238
+ let filename;
239
+ if (options.format === 'markdown' || options.format === 'md') {
240
+ output = generateMarkdown(manifests);
241
+ filename = 'docs.md';
242
+ }
243
+ else if (options.format === 'html') {
244
+ output = generateHTML(manifests);
245
+ filename = 'docs.html';
246
+ }
247
+ else if (options.format === 'openapi') {
248
+ const openapi = generateOpenAPI(manifests);
249
+ output = JSON.stringify(openapi, null, 2);
250
+ filename = 'openapi.json';
251
+ }
252
+ else if (options.format === 'catalog' || options.catalog) {
253
+ const catalog = generateCatalog(manifests);
254
+ output = JSON.stringify(catalog, null, 2);
255
+ filename = 'catalog.json';
256
+ }
257
+ else {
258
+ console.error(chalk.red(`Unknown format: ${options.format}`));
259
+ console.log(chalk.blue('Available formats: markdown, html, openapi, catalog'));
260
+ process.exit(1);
261
+ }
262
+ const outputPath = path.join(outputDir, filename);
263
+ fs.writeFileSync(outputPath, output, 'utf-8');
264
+ console.log(chalk.green(`✓ Documentation written to ${outputPath}`));
265
+ }
266
+ catch (error) {
267
+ console.error(chalk.red('[ERROR]'), error.message);
268
+ if (error.stack) {
269
+ console.error(chalk.gray(error.stack));
270
+ }
271
+ process.exit(1);
272
+ }
273
+ });
274
+ //# sourceMappingURL=docs.command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs.command.js","sourceRoot":"","sources":["../../../src/cli/commands/docs.command.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * OSSA Lint Command
3
+ * Lint OSSA agent manifests against best practices
4
+ */
5
+ import { Command } from 'commander';
6
+ export declare const lintCommand: Command;
7
+ //# sourceMappingURL=lint.command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.command.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/lint.command.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiJpC,eAAO,MAAM,WAAW,SAsOrB,CAAC"}
@@ -0,0 +1,342 @@
1
+ /**
2
+ * OSSA Lint Command
3
+ * Lint OSSA agent manifests against best practices
4
+ */
5
+ import chalk from 'chalk';
6
+ import { Command } from 'commander';
7
+ import * as fs from 'fs';
8
+ import * as path from 'path';
9
+ import { container } from '../../di-container.js';
10
+ import { ManifestRepository } from '../../repositories/manifest.repository.js';
11
+ const lintRules = [
12
+ {
13
+ id: 'no-hardcoded-models',
14
+ name: 'No hardcoded model names',
15
+ severity: 'error',
16
+ check: (manifest) => {
17
+ const issues = [];
18
+ if (manifest.spec?.llm?.model && !manifest.spec.llm.model.includes('${')) {
19
+ issues.push({
20
+ rule: 'no-hardcoded-models',
21
+ message: 'Model name should use environment variable (e.g., ${LLM_MODEL:-gpt-4})',
22
+ severity: 'error',
23
+ path: 'spec.llm.model',
24
+ fix: `Replace with: \${LLM_MODEL:-${manifest.spec.llm.model}}`,
25
+ });
26
+ }
27
+ return issues;
28
+ },
29
+ },
30
+ {
31
+ id: 'required-fields',
32
+ name: 'Required fields present',
33
+ severity: 'error',
34
+ check: (manifest) => {
35
+ const issues = [];
36
+ if (!manifest.metadata?.name) {
37
+ issues.push({
38
+ rule: 'required-fields',
39
+ message: 'Missing required field: metadata.name',
40
+ severity: 'error',
41
+ path: 'metadata.name',
42
+ });
43
+ }
44
+ if (!manifest.metadata?.version) {
45
+ issues.push({
46
+ rule: 'required-fields',
47
+ message: 'Missing required field: metadata.version',
48
+ severity: 'error',
49
+ path: 'metadata.version',
50
+ });
51
+ }
52
+ if (!manifest.spec?.role) {
53
+ issues.push({
54
+ rule: 'required-fields',
55
+ message: 'Missing required field: spec.role',
56
+ severity: 'error',
57
+ path: 'spec.role',
58
+ });
59
+ }
60
+ return issues;
61
+ },
62
+ },
63
+ {
64
+ id: 'capability-schemas',
65
+ name: 'Capability input/output schemas defined',
66
+ severity: 'warning',
67
+ check: (manifest) => {
68
+ const issues = [];
69
+ // Check legacy format capabilities
70
+ if (manifest.agent?.capabilities) {
71
+ manifest.agent.capabilities.forEach((cap, idx) => {
72
+ if (!cap.input_schema && !cap.input?.schema) {
73
+ issues.push({
74
+ rule: 'capability-schemas',
75
+ message: `Capability "${cap.name || idx}" missing input schema`,
76
+ severity: 'warning',
77
+ path: `agent.capabilities[${idx}].input_schema`,
78
+ });
79
+ }
80
+ if (!cap.output_schema && !cap.output?.schema) {
81
+ issues.push({
82
+ rule: 'capability-schemas',
83
+ message: `Capability "${cap.name || idx}" missing output schema`,
84
+ severity: 'warning',
85
+ path: `agent.capabilities[${idx}].output_schema`,
86
+ });
87
+ }
88
+ });
89
+ }
90
+ return issues;
91
+ },
92
+ },
93
+ {
94
+ id: 'observability',
95
+ name: 'Observability enabled',
96
+ severity: 'info',
97
+ check: (manifest) => {
98
+ const issues = [];
99
+ const obs = manifest.spec?.observability;
100
+ if (!obs || (!obs.tracing?.enabled && !obs.metrics?.enabled)) {
101
+ issues.push({
102
+ rule: 'observability',
103
+ message: 'Observability (tracing/metrics) not explicitly enabled',
104
+ severity: 'info',
105
+ path: 'spec.observability',
106
+ });
107
+ }
108
+ return issues;
109
+ },
110
+ },
111
+ {
112
+ id: 'cost-constraints',
113
+ name: 'Cost constraints for production agents',
114
+ severity: 'warning',
115
+ check: (manifest) => {
116
+ const issues = [];
117
+ const labels = manifest.metadata?.labels || {};
118
+ const isProduction = Object.values(labels).some((v) => typeof v === 'string' && v.toLowerCase().includes('production'));
119
+ if (isProduction && !manifest.spec?.constraints?.cost) {
120
+ issues.push({
121
+ rule: 'cost-constraints',
122
+ message: 'Production agent should have cost constraints configured',
123
+ severity: 'warning',
124
+ path: 'spec.constraints.cost',
125
+ });
126
+ }
127
+ return issues;
128
+ },
129
+ },
130
+ ];
131
+ export const lintCommand = new Command('lint')
132
+ .argument('[paths...]', 'Paths to OSSA manifests (default: current directory)')
133
+ .option('--fix', 'Auto-fix issues where possible')
134
+ .option('--rule <rule>', 'Run specific rule only')
135
+ .option('--format <format>', 'Output format (default, json, sarif)', 'default')
136
+ .option('-o, --output <file>', 'Output file (for json/sarif formats)')
137
+ .option('--max-warnings <number>', 'Maximum warnings before exit with error', '0')
138
+ .description('Lint OSSA agent manifests against best practices')
139
+ .action(async (paths, options) => {
140
+ try {
141
+ const manifestRepo = container.get(ManifestRepository);
142
+ const maxWarnings = parseInt(options.maxWarnings || '0', 10);
143
+ // Determine files to lint
144
+ const filesToLint = [];
145
+ if (paths.length === 0) {
146
+ // Default: find all .ossa.yaml and .ossa.yml files in current directory
147
+ const cwd = process.cwd();
148
+ const findFiles = (dir) => {
149
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
150
+ for (const entry of entries) {
151
+ const fullPath = path.join(dir, entry.name);
152
+ if (entry.isDirectory() && entry.name !== 'node_modules' && entry.name !== 'dist') {
153
+ findFiles(fullPath);
154
+ }
155
+ else if (entry.isFile() &&
156
+ (entry.name.endsWith('.ossa.yaml') || entry.name.endsWith('.ossa.yml'))) {
157
+ filesToLint.push(fullPath);
158
+ }
159
+ }
160
+ };
161
+ findFiles(cwd);
162
+ }
163
+ else {
164
+ // Use provided paths
165
+ for (const p of paths) {
166
+ if (fs.existsSync(p) && fs.statSync(p).isDirectory()) {
167
+ // Recursively find .ossa.yaml files
168
+ const findFiles = (dir) => {
169
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
170
+ for (const entry of entries) {
171
+ const fullPath = path.join(dir, entry.name);
172
+ if (entry.isDirectory() && entry.name !== 'node_modules' && entry.name !== 'dist') {
173
+ findFiles(fullPath);
174
+ }
175
+ else if (entry.isFile() &&
176
+ (entry.name.endsWith('.ossa.yaml') || entry.name.endsWith('.ossa.yml'))) {
177
+ filesToLint.push(fullPath);
178
+ }
179
+ }
180
+ };
181
+ findFiles(p);
182
+ }
183
+ else {
184
+ filesToLint.push(p);
185
+ }
186
+ }
187
+ }
188
+ if (filesToLint.length === 0) {
189
+ console.log(chalk.yellow('No OSSA manifest files found'));
190
+ process.exit(0);
191
+ }
192
+ // Filter rules if specific rule requested
193
+ const rulesToRun = options.rule
194
+ ? lintRules.filter((r) => r.id === options.rule)
195
+ : lintRules;
196
+ if (rulesToRun.length === 0) {
197
+ console.error(chalk.red(`Unknown rule: ${options.rule}`));
198
+ console.log(chalk.blue('Available rules:'));
199
+ lintRules.forEach((r) => {
200
+ console.log(` - ${r.id}: ${r.name}`);
201
+ });
202
+ process.exit(1);
203
+ }
204
+ // Lint all files
205
+ const allIssues = [];
206
+ for (const file of filesToLint) {
207
+ try {
208
+ const manifest = await manifestRepo.load(file);
209
+ for (const rule of rulesToRun) {
210
+ const issues = rule.check(manifest);
211
+ allIssues.push(...issues.map((issue) => ({
212
+ ...issue,
213
+ file,
214
+ })));
215
+ }
216
+ }
217
+ catch (error) {
218
+ allIssues.push({
219
+ rule: 'parse-error',
220
+ message: `Failed to parse manifest: ${error.message}`,
221
+ severity: 'error',
222
+ file,
223
+ });
224
+ }
225
+ }
226
+ // Count issues by severity
227
+ const errors = allIssues.filter((i) => i.severity === 'error');
228
+ const warnings = allIssues.filter((i) => i.severity === 'warning');
229
+ const infos = allIssues.filter((i) => i.severity === 'info');
230
+ // Output results
231
+ if (options.format === 'json') {
232
+ const output = {
233
+ files: filesToLint.length,
234
+ issues: allIssues.length,
235
+ errors: errors.length,
236
+ warnings: warnings.length,
237
+ infos: infos.length,
238
+ results: allIssues,
239
+ };
240
+ const jsonStr = JSON.stringify(output, null, 2);
241
+ if (options.output) {
242
+ fs.writeFileSync(options.output, jsonStr);
243
+ console.log(chalk.green(`Results written to ${options.output}`));
244
+ }
245
+ else {
246
+ console.log(jsonStr);
247
+ }
248
+ }
249
+ else if (options.format === 'sarif') {
250
+ // SARIF format for CI integration
251
+ const sarif = {
252
+ version: '2.1.0',
253
+ $schema: 'https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json',
254
+ runs: [
255
+ {
256
+ tool: {
257
+ driver: {
258
+ name: 'OSSA Lint',
259
+ version: '0.3.0',
260
+ },
261
+ },
262
+ results: allIssues.map((issue) => ({
263
+ ruleId: issue.rule,
264
+ level: issue.severity === 'error' ? 'error' : issue.severity === 'warning' ? 'warning' : 'note',
265
+ message: {
266
+ text: issue.message,
267
+ },
268
+ locations: [
269
+ {
270
+ physicalLocation: {
271
+ artifactLocation: {
272
+ uri: issue.file,
273
+ },
274
+ },
275
+ },
276
+ ],
277
+ })),
278
+ },
279
+ ],
280
+ };
281
+ const jsonStr = JSON.stringify(sarif, null, 2);
282
+ if (options.output) {
283
+ fs.writeFileSync(options.output, jsonStr);
284
+ console.log(chalk.green(`SARIF results written to ${options.output}`));
285
+ }
286
+ else {
287
+ console.log(jsonStr);
288
+ }
289
+ }
290
+ else {
291
+ // Default format
292
+ console.log(chalk.blue(`\nLinting ${filesToLint.length} file(s)...\n`));
293
+ if (allIssues.length === 0) {
294
+ console.log(chalk.green('No linting issues found!'));
295
+ }
296
+ else {
297
+ // Group by file
298
+ const byFile = new Map();
299
+ for (const issue of allIssues) {
300
+ if (!byFile.has(issue.file)) {
301
+ byFile.set(issue.file, []);
302
+ }
303
+ byFile.get(issue.file).push(issue);
304
+ }
305
+ for (const [file, issues] of byFile) {
306
+ console.log(chalk.cyan(`\n${file}:`));
307
+ for (const issue of issues) {
308
+ const color = issue.severity === 'error'
309
+ ? chalk.red
310
+ : issue.severity === 'warning'
311
+ ? chalk.yellow
312
+ : chalk.blue;
313
+ const icon = issue.severity === 'error' ? '✗' : issue.severity === 'warning' ? '⚠' : 'ℹ';
314
+ console.log(color(` ${icon} [${issue.rule}] ${issue.message}`) +
315
+ (issue.path ? chalk.gray(` (${issue.path})`) : '') +
316
+ (issue.fix ? chalk.gray(`\n Fix: ${issue.fix}`) : ''));
317
+ }
318
+ }
319
+ console.log(chalk.blue(`\nSummary:`));
320
+ console.log(` Errors: ${errors.length}`);
321
+ console.log(` Warnings: ${warnings.length}`);
322
+ console.log(` Info: ${infos.length}`);
323
+ }
324
+ }
325
+ // Exit with appropriate code
326
+ if (errors.length > 0) {
327
+ process.exit(1);
328
+ }
329
+ if (warnings.length > maxWarnings) {
330
+ process.exit(1);
331
+ }
332
+ process.exit(0);
333
+ }
334
+ catch (error) {
335
+ console.error(chalk.red('[ERROR]'), error.message);
336
+ if (error.stack) {
337
+ console.error(chalk.gray(error.stack));
338
+ }
339
+ process.exit(1);
340
+ }
341
+ });
342
+ //# sourceMappingURL=lint.command.js.map