@agentlee5/agent-skills 1.0.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.
Files changed (182) hide show
  1. package/.leeway/config.json +133 -0
  2. package/LICENSE +21 -0
  3. package/LeeWay-Standards/LICENSE +21 -0
  4. package/LeeWay-Standards/README.md +324 -0
  5. package/LeeWay-Standards/examples/NexusButton.tsx +90 -0
  6. package/LeeWay-Standards/examples/example-agent.js +89 -0
  7. package/LeeWay-Standards/package.json +61 -0
  8. package/LeeWay-Standards/schemas/leeway-config.schema.json +81 -0
  9. package/LeeWay-Standards/schemas/leeway-header.schema.json +63 -0
  10. package/LeeWay-Standards/src/agents/discovery/architecture-map-agent.js +134 -0
  11. package/LeeWay-Standards/src/agents/discovery/docs-agent.js +126 -0
  12. package/LeeWay-Standards/src/agents/discovery/explain-agent.js +95 -0
  13. package/LeeWay-Standards/src/agents/discovery/intent-registry-agent.js +119 -0
  14. package/LeeWay-Standards/src/agents/discovery/schema-agent.js +116 -0
  15. package/LeeWay-Standards/src/agents/discovery/sitemap-agent.js +88 -0
  16. package/LeeWay-Standards/src/agents/governance/align-agent.js +155 -0
  17. package/LeeWay-Standards/src/agents/governance/assess-agent.js +161 -0
  18. package/LeeWay-Standards/src/agents/governance/audit-agent.js +185 -0
  19. package/LeeWay-Standards/src/agents/integrity/circular-dependency-agent.js +88 -0
  20. package/LeeWay-Standards/src/agents/integrity/dependency-graph-agent.js +107 -0
  21. package/LeeWay-Standards/src/agents/integrity/duplicate-logic-agent.js +108 -0
  22. package/LeeWay-Standards/src/agents/integrity/import-agent.js +83 -0
  23. package/LeeWay-Standards/src/agents/integrity/module-policy-agent.js +94 -0
  24. package/LeeWay-Standards/src/agents/integrity/refactor-scan-agent.js +113 -0
  25. package/LeeWay-Standards/src/agents/integrity/syntax-agent.js +84 -0
  26. package/LeeWay-Standards/src/agents/mcp/endpoint-agent.js +106 -0
  27. package/LeeWay-Standards/src/agents/mcp/env-agent.js +111 -0
  28. package/LeeWay-Standards/src/agents/mcp/health-agent-lite.js +119 -0
  29. package/LeeWay-Standards/src/agents/mcp/manifest-agent.js +87 -0
  30. package/LeeWay-Standards/src/agents/mcp/port-agent.js +125 -0
  31. package/LeeWay-Standards/src/agents/mcp/process-agent.js +124 -0
  32. package/LeeWay-Standards/src/agents/mcp/runtime-agent.js +108 -0
  33. package/LeeWay-Standards/src/agents/mcp/transport-agent.js +78 -0
  34. package/LeeWay-Standards/src/agents/orchestration/doctor-agent.js +149 -0
  35. package/LeeWay-Standards/src/agents/orchestration/memory-agent-lite.js +125 -0
  36. package/LeeWay-Standards/src/agents/orchestration/router-agent.js +110 -0
  37. package/LeeWay-Standards/src/agents/security/permission-agent.js +98 -0
  38. package/LeeWay-Standards/src/agents/security/policy-agent.js +100 -0
  39. package/LeeWay-Standards/src/agents/security/privacy-agent.js +83 -0
  40. package/LeeWay-Standards/src/agents/security/prompt-security-agent.js +103 -0
  41. package/LeeWay-Standards/src/agents/security/secret-scan-agent.js +108 -0
  42. package/LeeWay-Standards/src/agents/security/tool-access-agent.js +105 -0
  43. package/LeeWay-Standards/src/agents/standards/authority-agent.js +114 -0
  44. package/LeeWay-Standards/src/agents/standards/discovery-pipeline-agent.js +91 -0
  45. package/LeeWay-Standards/src/agents/standards/header-agent.js +120 -0
  46. package/LeeWay-Standards/src/agents/standards/placement-agent.js +96 -0
  47. package/LeeWay-Standards/src/agents/standards/region-agent.js +99 -0
  48. package/LeeWay-Standards/src/agents/standards/registry-agent.js +153 -0
  49. package/LeeWay-Standards/src/agents/standards/tag-agent.js +111 -0
  50. package/LeeWay-Standards/src/cli/leeway.js +225 -0
  51. package/LeeWay-Standards/src/core/compliance-scorer.js +168 -0
  52. package/LeeWay-Standards/src/core/compliance-scorer.test.js +121 -0
  53. package/LeeWay-Standards/src/core/header-parser.js +207 -0
  54. package/LeeWay-Standards/src/core/header-parser.test.js +198 -0
  55. package/LeeWay-Standards/src/core/region-classifier.js +137 -0
  56. package/LeeWay-Standards/src/core/region-classifier.test.js +100 -0
  57. package/LeeWay-Standards/src/core/tag-validator.js +139 -0
  58. package/LeeWay-Standards/src/core/tag-validator.test.js +109 -0
  59. package/LeeWay-Standards/src/index.js +83 -0
  60. package/README.md +217 -0
  61. package/agent-config.yaml +456 -0
  62. package/agentbage.png.png +0 -0
  63. package/bin/leeway-skills-badge.js +52 -0
  64. package/bin/leeway-skills-mcp.js +48 -0
  65. package/bin/leeway-skills.js +160 -0
  66. package/bin/leeway-standards.js +49 -0
  67. package/config/.skillsignore +63 -0
  68. package/config/skills-config.json +70 -0
  69. package/documents/AGENT_LEARNING_REFERENCE.md +329 -0
  70. package/documents/AGENT_LEE_INTEGRATION.md +534 -0
  71. package/documents/COMPLETE_SYSTEM_OVERVIEW.md +502 -0
  72. package/documents/COMPREHENSIVE_SKILL_INTEGRATION_PLAN.md +644 -0
  73. package/documents/DIRECTORY_MAP.md +323 -0
  74. package/documents/EXTENDING.md +514 -0
  75. package/documents/FILE_DIRECTORY_GUIDE.md +427 -0
  76. package/documents/LEEWAY_BADGE_INTEGRATION.md +76 -0
  77. package/documents/LEEWAY_IMPLEMENTATION_SUMMARY.md +384 -0
  78. package/documents/LEEWAY_INTEGRATION_GUIDE.md +414 -0
  79. package/documents/LEEWAY_NPM_SDK.md +66 -0
  80. package/documents/LEEWAY_QUICK_START.md +288 -0
  81. package/documents/LEEWAY_SKILLS_BRANDING.md +375 -0
  82. package/documents/LEEWAY_SKILLS_MCP_SUMMARY.md +593 -0
  83. package/documents/LEEWAY_STANDARDS_COMPLIANCE.md +361 -0
  84. package/documents/LEEWAY_UNIFIED_ARCHITECTURE.md +473 -0
  85. package/documents/LEEWAY_WORKFLOWS_QUICK_REFERENCE.md +307 -0
  86. package/documents/LEEWAY_WORKFLOWS_STRATEGIC_PLAN.md +515 -0
  87. package/documents/LIFELONG_LEARNING_LAYER.md +478 -0
  88. package/documents/MCP_ARCHITECTURE.md +683 -0
  89. package/documents/QUICK_REFERENCE.md +301 -0
  90. package/documents/SETUP.md +325 -0
  91. package/documents/SETUP_SUMMARY.md +413 -0
  92. package/documents/SKILL_ACQUISITION_EXECUTIVE_SUMMARY.md +373 -0
  93. package/documents/SKILL_ACQUISITION_IMPLEMENTATION.md +692 -0
  94. package/documents/SKILL_ACQUISITION_MANIFEST.md +404 -0
  95. package/documents/SKILL_ACQUISITION_QUICK_REFERENCE.md +349 -0
  96. package/documents/SKILL_WORKFLOW_COMPOSITION_MATRIX.md +537 -0
  97. package/documents/STRUCTURE.md +382 -0
  98. package/documents/SYSTEM_TRANSFORMATION_SUMMARY.md +560 -0
  99. package/documents/USAGE.md +390 -0
  100. package/documents/WORKFLOW_ACQUISITION_MANIFEST.md +576 -0
  101. package/documents/aiskills.txt +460 -0
  102. package/mcp-server/README.md +697 -0
  103. package/mcp-server/dist/badge-proof.d.ts +66 -0
  104. package/mcp-server/dist/badge-proof.d.ts.map +1 -0
  105. package/mcp-server/dist/badge-proof.js +324 -0
  106. package/mcp-server/dist/badge-proof.js.map +1 -0
  107. package/mcp-server/dist/index.d.ts +64 -0
  108. package/mcp-server/dist/index.d.ts.map +1 -0
  109. package/mcp-server/dist/index.js +263 -0
  110. package/mcp-server/dist/index.js.map +1 -0
  111. package/mcp-server/dist/install-badge-proof.d.ts +3 -0
  112. package/mcp-server/dist/install-badge-proof.d.ts.map +1 -0
  113. package/mcp-server/dist/install-badge-proof.js +109 -0
  114. package/mcp-server/dist/install-badge-proof.js.map +1 -0
  115. package/mcp-server/package.json +43 -0
  116. package/mcp-server/src/badge-proof.ts +469 -0
  117. package/mcp-server/src/index.ts +355 -0
  118. package/mcp-server/src/install-badge-proof.ts +132 -0
  119. package/mcp-server/tsconfig.json +22 -0
  120. package/package.json +84 -0
  121. package/scripts/init-leeway.js +217 -0
  122. package/scripts/leeway-agents/compliance-monitor.js +374 -0
  123. package/scripts/leeway-agents/header-injector.js +321 -0
  124. package/scripts/skill-integration-toolkit.py +319 -0
  125. package/scripts/skills-registry.json +1117 -0
  126. package/scripts/sync-skills.ps1 +275 -0
  127. package/scripts/verify-leeway-setup.js +249 -0
  128. package/scripts/workflow-integration-toolkit.py +522 -0
  129. package/sdk/application-installer.js +92 -0
  130. package/sdk/index.js +43 -0
  131. package/sdk/paths.js +167 -0
  132. package/skills/agent-autonomy/autonomous-conductor/SKILL.md +206 -0
  133. package/skills/agent-autonomy/full-stack-delivery/SKILL.md +206 -0
  134. package/skills/agent-orchestration/multi-agent-orchestration/SKILL.md +68 -0
  135. package/skills/agent-patterns/agent-design-patterns/SKILL.md +70 -0
  136. package/skills/ai-ml/llm-prompting/SKILL.md +71 -0
  137. package/skills/ai-ml/ml-model-development/SKILL.md +67 -0
  138. package/skills/ai-ml/multimodal-systems/SKILL.md +71 -0
  139. package/skills/ai-ml/retrieval-generation-fine-tuning/SKILL.md +71 -0
  140. package/skills/architecture/system-design/SKILL.md +67 -0
  141. package/skills/code-analysis/refactoring/SKILL.md +64 -0
  142. package/skills/code-analysis/security-vulnerability-scanning/SKILL.md +71 -0
  143. package/skills/code-analysis/static-analysis/SKILL.md +64 -0
  144. package/skills/code-generation/full-stack-application/SKILL.md +70 -0
  145. package/skills/code-generation/microservices-architecture/SKILL.md +71 -0
  146. package/skills/code-generation/python-codegen/SKILL.md +64 -0
  147. package/skills/code-generation/typescript-codegen/SKILL.md +64 -0
  148. package/skills/data-analysis/advanced-analytics/SKILL.md +71 -0
  149. package/skills/data-analysis/pandas-analysis/SKILL.md +66 -0
  150. package/skills/database-design/database-design-optimization/SKILL.md +70 -0
  151. package/skills/debugging/javascript-debugging/SKILL.md +67 -0
  152. package/skills/debugging/python-debugging/SKILL.md +67 -0
  153. package/skills/devops/dockerfile-creation/SKILL.md +64 -0
  154. package/skills/devops/kubernetes-deployment/SKILL.md +65 -0
  155. package/skills/documentation/api-documentation/SKILL.md +67 -0
  156. package/skills/error-handling/resilience-patterns/SKILL.md +70 -0
  157. package/skills/git-workflow/git-collaboration/SKILL.md +67 -0
  158. package/skills/infrastructure/cicd-pipelines/SKILL.md +70 -0
  159. package/skills/infrastructure/infrastructure-as-code/SKILL.md +70 -0
  160. package/skills/observability/monitoring-and-observability/SKILL.md +70 -0
  161. package/skills/performance-optimization/performance-engineering/SKILL.md +70 -0
  162. package/skills/prompt-optimization/prompt-engineering-advanced/SKILL.md +70 -0
  163. package/skills/quality-assurance/deployment-validator/SKILL.md +382 -0
  164. package/skills/quality-assurance/web-security-sweep/SKILL.md +320 -0
  165. package/skills/rag-knowledge/rag-systems/SKILL.md +70 -0
  166. package/skills/research/knowledge-synthesis/SKILL.md +71 -0
  167. package/skills/security/authentication-authorization/SKILL.md +71 -0
  168. package/skills/security/code-security/SKILL.md +66 -0
  169. package/skills/security/secure-architecture/SKILL.md +71 -0
  170. package/skills/self-optimization/dev-loop-optimizer/SKILL.md +344 -0
  171. package/skills/self-optimization/memory-learning/SKILL.md +335 -0
  172. package/skills/self-optimization/runtime-self-profiling/SKILL.md +250 -0
  173. package/skills/testing/advanced-testing-strategies/SKILL.md +71 -0
  174. package/skills/testing/integration-testing/SKILL.md +66 -0
  175. package/skills/testing/load-testing-capacity/SKILL.md +71 -0
  176. package/skills/testing/unit-testing/SKILL.md +66 -0
  177. package/skills/tool-integration/custom-tool-creation/SKILL.md +70 -0
  178. package/skills/web-development/advanced-frontend-patterns/SKILL.md +71 -0
  179. package/skills/web-development/api-design/SKILL.md +71 -0
  180. package/skills/web-development/css-styling/SKILL.md +67 -0
  181. package/skills/web-development/react-development/SKILL.md +79 -0
  182. package/skills/workflow-composition/workflow-orchestration/SKILL.md +70 -0
@@ -0,0 +1,106 @@
1
+ /*
2
+ LEEWAY HEADER — DO NOT REMOVE
3
+
4
+ REGION: MCP.AGENT.ENDPOINT
5
+ TAG: MCP.ENDPOINT.AGENT.MAIN
6
+
7
+ COLOR_ONION_HEX:
8
+ NEON=#39FF14
9
+ FLUO=#0DFF94
10
+ PASTEL=#C7FFD8
11
+
12
+ ICON_ASCII:
13
+ family=lucide
14
+ glyph=globe
15
+
16
+ 5WH:
17
+ WHAT = Endpoint agent — detects existing health and HTTP endpoints safely
18
+ WHY = Prevents duplicate endpoint registration and detects port conflicts before startup
19
+ WHO = Rapid Web Development
20
+ WHERE = src/agents/mcp/endpoint-agent.js
21
+ WHEN = 2026
22
+ HOW = Reads manifest files and scans source for endpoint declarations
23
+
24
+ AGENTS:
25
+ ENDPOINT
26
+ TRANSPORT
27
+ PORT
28
+
29
+ LICENSE:
30
+ MIT
31
+ */
32
+
33
+ import { readFile } from 'node:fs/promises';
34
+ import { join } from 'node:path';
35
+
36
+ const ENDPOINT_PATTERNS = [
37
+ { type: 'express', pattern: /app\.(get|post|put|delete|patch|use)\s*\(\s*['"`]([^'"`]+)['"`]/g },
38
+ { type: 'fastify', pattern: /fastify\.(get|post|put|delete|patch)\s*\(\s*['"`]([^'"`]+)['"`]/g },
39
+ { type: 'http', pattern: /createServer|http\.listen\s*\(\s*(\d+)/g },
40
+ ];
41
+
42
+ /**
43
+ * EndpointAgent detects existing HTTP endpoints and health checks in source files.
44
+ */
45
+ export class EndpointAgent {
46
+ constructor(options = {}) {
47
+ this.rootDir = options.rootDir || process.cwd();
48
+ this.knownEndpoints = new Map();
49
+ }
50
+
51
+ /**
52
+ * Scan a file for endpoint declarations.
53
+ *
54
+ * @param {string} filePath
55
+ * @returns {Promise<EndpointScanResult>}
56
+ */
57
+ async scanFile(filePath) {
58
+ const fullPath = filePath.startsWith('/') ? filePath : join(this.rootDir, filePath);
59
+ let content = '';
60
+ try {
61
+ content = await readFile(fullPath, 'utf8');
62
+ } catch {
63
+ return { file: filePath, endpoints: [], status: 'error' };
64
+ }
65
+
66
+ const endpoints = [];
67
+ for (const { type, pattern } of ENDPOINT_PATTERNS) {
68
+ const regex = new RegExp(pattern.source, pattern.flags);
69
+ let match;
70
+ while ((match = regex.exec(content)) !== null) {
71
+ endpoints.push({
72
+ type,
73
+ method: match[1]?.toUpperCase() || 'UNKNOWN',
74
+ path: match[2] || '/',
75
+ line: content.slice(0, match.index).split('\n').length,
76
+ });
77
+ }
78
+ }
79
+
80
+ return { file: filePath, endpoints, status: 'scanned' };
81
+ }
82
+
83
+ /**
84
+ * Check for duplicate endpoints across multiple scan results.
85
+ *
86
+ * @param {EndpointScanResult[]} scanResults
87
+ * @returns {{ duplicates: object[], unique: object[] }}
88
+ */
89
+ detectDuplicates(scanResults) {
90
+ const seen = new Map();
91
+ const duplicates = [];
92
+
93
+ for (const result of scanResults) {
94
+ for (const ep of result.endpoints) {
95
+ const key = `${ep.method}:${ep.path}`;
96
+ if (seen.has(key)) {
97
+ duplicates.push({ key, files: [seen.get(key).file, result.file], endpoint: ep });
98
+ } else {
99
+ seen.set(key, { ...ep, file: result.file });
100
+ }
101
+ }
102
+ }
103
+
104
+ return { duplicates, unique: Array.from(seen.values()) };
105
+ }
106
+ }
@@ -0,0 +1,111 @@
1
+ /*
2
+ LEEWAY HEADER — DO NOT REMOVE
3
+
4
+ REGION: MCP.AGENT.ENV
5
+ TAG: MCP.ENV.AGENT.MAIN
6
+
7
+ COLOR_ONION_HEX:
8
+ NEON=#39FF14
9
+ FLUO=#0DFF94
10
+ PASTEL=#C7FFD8
11
+
12
+ ICON_ASCII:
13
+ family=lucide
14
+ glyph=settings
15
+
16
+ 5WH:
17
+ WHAT = Env agent — validates required vs optional environment variables
18
+ WHY = Missing or misconfigured env vars cause runtime failures that are hard to debug
19
+ WHO = Rapid Web Development
20
+ WHERE = src/agents/mcp/env-agent.js
21
+ WHEN = 2026
22
+ HOW = Reads .leeway/env-schema.json and validates against process.env
23
+
24
+ AGENTS:
25
+ ENV
26
+ RUNTIME
27
+ ALIGN
28
+
29
+ LICENSE:
30
+ MIT
31
+ */
32
+
33
+ import { readFile } from 'node:fs/promises';
34
+ import { join } from 'node:path';
35
+
36
+ /**
37
+ * EnvAgent validates environment variable presence and format.
38
+ */
39
+ export class EnvAgent {
40
+ constructor(options = {}) {
41
+ this.rootDir = options.rootDir || process.cwd();
42
+ this.schema = null;
43
+ }
44
+
45
+ /**
46
+ * Load the env schema from .leeway/env-schema.json or .env.schema.json
47
+ */
48
+ async loadSchema() {
49
+ const paths = [
50
+ join(this.rootDir, '.leeway', 'env-schema.json'),
51
+ join(this.rootDir, '.env.schema.json'),
52
+ ];
53
+
54
+ for (const p of paths) {
55
+ try {
56
+ const raw = await readFile(p, 'utf8');
57
+ this.schema = JSON.parse(raw);
58
+ return this.schema;
59
+ } catch {
60
+ continue;
61
+ }
62
+ }
63
+
64
+ this.schema = { required: [], optional: [] };
65
+ return this.schema;
66
+ }
67
+
68
+ /**
69
+ * Validate current environment against the schema.
70
+ *
71
+ * @param {object} [env] - Environment to validate (defaults to process.env)
72
+ * @returns {Promise<EnvValidationResult>}
73
+ */
74
+ async validate(env = process.env) {
75
+ if (!this.schema) await this.loadSchema();
76
+
77
+ const missing = [];
78
+ const present = [];
79
+ const warnings = [];
80
+
81
+ for (const varDef of this.schema.required || []) {
82
+ const name = typeof varDef === 'string' ? varDef : varDef.name;
83
+ const pattern = typeof varDef === 'object' ? varDef.pattern : null;
84
+
85
+ if (!env[name]) {
86
+ missing.push(name);
87
+ } else {
88
+ if (pattern && !new RegExp(pattern).test(env[name])) {
89
+ warnings.push(`${name} does not match expected pattern`);
90
+ }
91
+ present.push(name);
92
+ }
93
+ }
94
+
95
+ for (const varDef of this.schema.optional || []) {
96
+ const name = typeof varDef === 'string' ? varDef : varDef.name;
97
+ if (!env[name]) {
98
+ warnings.push(`Optional env var ${name} is not set`);
99
+ } else {
100
+ present.push(name);
101
+ }
102
+ }
103
+
104
+ return {
105
+ valid: missing.length === 0,
106
+ missing,
107
+ present,
108
+ warnings,
109
+ };
110
+ }
111
+ }
@@ -0,0 +1,119 @@
1
+ /*
2
+ LEEWAY HEADER — DO NOT REMOVE
3
+
4
+ REGION: MCP.AGENT.HEALTH
5
+ TAG: MCP.HEALTH.AGENT.LITE
6
+
7
+ COLOR_ONION_HEX:
8
+ NEON=#39FF14
9
+ FLUO=#0DFF94
10
+ PASTEL=#C7FFD8
11
+
12
+ ICON_ASCII:
13
+ family=lucide
14
+ glyph=heart-pulse
15
+
16
+ 5WH:
17
+ WHAT = Health agent lite — runs lightweight startup and readiness checks
18
+ WHY = Services must pass readiness gates before routing traffic or accepting requests
19
+ WHO = Rapid Web Development
20
+ WHERE = src/agents/mcp/health-agent-lite.js
21
+ WHEN = 2026
22
+ HOW = Runs a series of configurable health checks, returns pass/fail with details
23
+
24
+ AGENTS:
25
+ HEALTH
26
+ RUNTIME
27
+ ENV
28
+
29
+ LICENSE:
30
+ MIT
31
+ */
32
+
33
+ /**
34
+ * HealthAgentLite performs lightweight startup and readiness checks.
35
+ */
36
+ export class HealthAgentLite {
37
+ constructor(options = {}) {
38
+ this.checks = options.checks || [];
39
+ this.timeout = options.timeout || 5000;
40
+ }
41
+
42
+ /**
43
+ * Register a health check function.
44
+ *
45
+ * @param {string} name
46
+ * @param {() => Promise<{ healthy: boolean, details?: string }>} fn
47
+ */
48
+ register(name, fn) {
49
+ this.checks.push({ name, fn });
50
+ }
51
+
52
+ /**
53
+ * Run all registered health checks.
54
+ * @returns {Promise<HealthReport>}
55
+ */
56
+ async run() {
57
+ const results = [];
58
+ let allHealthy = true;
59
+
60
+ for (const check of this.checks) {
61
+ const startTime = Date.now();
62
+ try {
63
+ const result = await Promise.race([
64
+ check.fn(),
65
+ new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), this.timeout)),
66
+ ]);
67
+
68
+ const duration = Date.now() - startTime;
69
+ results.push({
70
+ name: check.name,
71
+ healthy: result.healthy,
72
+ details: result.details || null,
73
+ durationMs: duration,
74
+ });
75
+
76
+ if (!result.healthy) allHealthy = false;
77
+ } catch (err) {
78
+ results.push({
79
+ name: check.name,
80
+ healthy: false,
81
+ details: err.message,
82
+ durationMs: Date.now() - startTime,
83
+ });
84
+ allHealthy = false;
85
+ }
86
+ }
87
+
88
+ return {
89
+ healthy: allHealthy,
90
+ timestamp: new Date().toISOString(),
91
+ checks: results,
92
+ summary: `${results.filter(r => r.healthy).length}/${results.length} checks passed`,
93
+ };
94
+ }
95
+
96
+ /**
97
+ * Get built-in system health checks.
98
+ * @returns {HealthAgentLite}
99
+ */
100
+ static withSystemChecks(options = {}) {
101
+ const agent = new HealthAgentLite(options);
102
+
103
+ agent.register('memory', async () => {
104
+ const { heapUsed, heapTotal } = process.memoryUsage();
105
+ const usagePercent = Math.round((heapUsed / heapTotal) * 100);
106
+ return {
107
+ healthy: usagePercent < 90,
108
+ details: `Heap usage: ${usagePercent}% (${Math.round(heapUsed / 1024 / 1024)}MB / ${Math.round(heapTotal / 1024 / 1024)}MB)`,
109
+ };
110
+ });
111
+
112
+ agent.register('uptime', async () => ({
113
+ healthy: true,
114
+ details: `Process uptime: ${Math.round(process.uptime())}s`,
115
+ }));
116
+
117
+ return agent;
118
+ }
119
+ }
@@ -0,0 +1,87 @@
1
+ /*
2
+ LEEWAY HEADER — DO NOT REMOVE
3
+
4
+ REGION: MCP.AGENT.MANIFEST
5
+ TAG: MCP.MANIFEST.AGENT.MAIN
6
+
7
+ COLOR_ONION_HEX:
8
+ NEON=#39FF14
9
+ FLUO=#0DFF94
10
+ PASTEL=#C7FFD8
11
+
12
+ ICON_ASCII:
13
+ family=lucide
14
+ glyph=file-check
15
+
16
+ 5WH:
17
+ WHAT = Manifest agent — validates MCP manifest completeness and tool definitions
18
+ WHY = Incomplete or malformed manifests prevent MCP servers from being discovered and used
19
+ WHO = Rapid Web Development
20
+ WHERE = src/agents/mcp/manifest-agent.js
21
+ WHEN = 2026
22
+ HOW = Reads manifest JSON, validates required fields and tool schemas
23
+
24
+ AGENTS:
25
+ MANIFEST
26
+ TRANSPORT
27
+ ENDPOINT
28
+
29
+ LICENSE:
30
+ MIT
31
+ */
32
+
33
+ import { readFile } from 'node:fs/promises';
34
+ import { join } from 'node:path';
35
+
36
+ const REQUIRED_MANIFEST_FIELDS = ['name', 'version', 'description'];
37
+ const REQUIRED_TOOL_FIELDS = ['name', 'description', 'inputSchema'];
38
+
39
+ /**
40
+ * ManifestAgent validates MCP manifest files for completeness.
41
+ */
42
+ export class ManifestAgent {
43
+ constructor(options = {}) {
44
+ this.rootDir = options.rootDir || process.cwd();
45
+ }
46
+
47
+ /**
48
+ * Validate a manifest object or load from file.
49
+ *
50
+ * @param {string | object} manifestOrPath - Manifest object or path to manifest file
51
+ * @returns {Promise<ManifestValidationResult>}
52
+ */
53
+ async validate(manifestOrPath) {
54
+ let manifest = manifestOrPath;
55
+
56
+ if (typeof manifestOrPath === 'string') {
57
+ const fullPath = manifestOrPath.startsWith('/') ? manifestOrPath : join(this.rootDir, manifestOrPath);
58
+ try {
59
+ const raw = await readFile(fullPath, 'utf8');
60
+ manifest = JSON.parse(raw);
61
+ } catch (err) {
62
+ return { valid: false, issues: [`Cannot load manifest: ${err.message}`] };
63
+ }
64
+ }
65
+
66
+ const issues = [];
67
+
68
+ for (const field of REQUIRED_MANIFEST_FIELDS) {
69
+ if (!manifest[field]) issues.push(`Missing required field: ${field}`);
70
+ }
71
+
72
+ if (manifest.tools && Array.isArray(manifest.tools)) {
73
+ for (const tool of manifest.tools) {
74
+ for (const field of REQUIRED_TOOL_FIELDS) {
75
+ if (!tool[field]) issues.push(`Tool "${tool.name || 'unknown'}" missing field: ${field}`);
76
+ }
77
+ if (tool.inputSchema && typeof tool.inputSchema !== 'object') {
78
+ issues.push(`Tool "${tool.name}" inputSchema must be an object`);
79
+ }
80
+ }
81
+ } else if (manifest.tools !== undefined) {
82
+ issues.push('manifest.tools must be an array');
83
+ }
84
+
85
+ return { valid: issues.length === 0, issues, manifest };
86
+ }
87
+ }
@@ -0,0 +1,125 @@
1
+ /*
2
+ LEEWAY HEADER — DO NOT REMOVE
3
+
4
+ REGION: MCP.AGENT.PORT
5
+ TAG: MCP.PORT.AGENT.MAIN
6
+
7
+ COLOR_ONION_HEX:
8
+ NEON=#39FF14
9
+ FLUO=#0DFF94
10
+ PASTEL=#C7FFD8
11
+
12
+ ICON_ASCII:
13
+ family=lucide
14
+ glyph=radio
15
+
16
+ 5WH:
17
+ WHAT = Port agent — assigns and validates ports from a registry to prevent collisions
18
+ WHY = Port collisions cause service startup failures; governance requires a centralized port registry
19
+ WHO = Rapid Web Development
20
+ WHERE = src/agents/mcp/port-agent.js
21
+ WHEN = 2026
22
+ HOW = Maintains a port registry in .leeway/ports.json, validates before assignment
23
+
24
+ AGENTS:
25
+ PORT
26
+ ENDPOINT
27
+ TRANSPORT
28
+
29
+ LICENSE:
30
+ MIT
31
+ */
32
+
33
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
34
+ import { join } from 'node:path';
35
+
36
+ const DEFAULT_PORT_RANGES = {
37
+ UI: [3000, 3099],
38
+ API: [4000, 4099],
39
+ AI: [5000, 5099],
40
+ MCP: [6000, 6099],
41
+ DATA: [7000, 7099],
42
+ UTIL: [8000, 8099],
43
+ };
44
+
45
+ /**
46
+ * PortAgent manages port assignments to prevent collisions.
47
+ */
48
+ export class PortAgent {
49
+ constructor(options = {}) {
50
+ this.rootDir = options.rootDir || process.cwd();
51
+ this.registryPath = join(this.rootDir, '.leeway', 'ports.json');
52
+ this.registry = null;
53
+ }
54
+
55
+ async _loadRegistry() {
56
+ if (this.registry) return this.registry;
57
+ try {
58
+ const raw = await readFile(this.registryPath, 'utf8');
59
+ this.registry = JSON.parse(raw);
60
+ } catch {
61
+ this.registry = { assignments: {}, reserved: [22, 80, 443, 8080, 8443] };
62
+ }
63
+ return this.registry;
64
+ }
65
+
66
+ async _saveRegistry() {
67
+ await mkdir(join(this.rootDir, '.leeway'), { recursive: true });
68
+ await writeFile(this.registryPath, JSON.stringify(this.registry, null, 2), 'utf8');
69
+ }
70
+
71
+ /**
72
+ * Check if a port is available (not assigned).
73
+ *
74
+ * @param {number} port
75
+ * @returns {Promise<{ available: boolean, assignedTo?: string }>}
76
+ */
77
+ async checkPort(port) {
78
+ const reg = await this._loadRegistry();
79
+ const assignedTo = Object.entries(reg.assignments).find(([, p]) => p === port)?.[0];
80
+ const isReserved = reg.reserved.includes(port);
81
+
82
+ return {
83
+ available: !assignedTo && !isReserved,
84
+ assignedTo: assignedTo || (isReserved ? 'SYSTEM_RESERVED' : null),
85
+ };
86
+ }
87
+
88
+ /**
89
+ * Assign a port to a service.
90
+ *
91
+ * @param {string} serviceName
92
+ * @param {number} [preferredPort]
93
+ * @param {string} [region]
94
+ * @returns {Promise<{ port: number, assigned: boolean, conflict?: string }>}
95
+ */
96
+ async assignPort(serviceName, preferredPort, region = 'UTIL') {
97
+ const reg = await this._loadRegistry();
98
+
99
+ if (reg.assignments[serviceName]) {
100
+ return { port: reg.assignments[serviceName], assigned: false, reason: 'Already assigned' };
101
+ }
102
+
103
+ let port = preferredPort;
104
+ if (port) {
105
+ const check = await this.checkPort(port);
106
+ if (!check.available) {
107
+ return { port: null, assigned: false, conflict: `Port ${port} already assigned to ${check.assignedTo}` };
108
+ }
109
+ } else {
110
+ const [rangeStart, rangeEnd] = DEFAULT_PORT_RANGES[region] || DEFAULT_PORT_RANGES.UTIL;
111
+ for (let p = rangeStart; p <= rangeEnd; p++) {
112
+ const check = await this.checkPort(p);
113
+ if (check.available) { port = p; break; }
114
+ }
115
+ }
116
+
117
+ if (!port) {
118
+ return { port: null, assigned: false, reason: 'No available port in range' };
119
+ }
120
+
121
+ reg.assignments[serviceName] = port;
122
+ await this._saveRegistry();
123
+ return { port, assigned: true };
124
+ }
125
+ }
@@ -0,0 +1,124 @@
1
+ /*
2
+ LEEWAY HEADER — DO NOT REMOVE
3
+
4
+ REGION: MCP.AGENT.PROCESS
5
+ TAG: MCP.PROCESS.AGENT.MAIN
6
+
7
+ COLOR_ONION_HEX:
8
+ NEON=#39FF14
9
+ FLUO=#0DFF94
10
+ PASTEL=#C7FFD8
11
+
12
+ ICON_ASCII:
13
+ family=lucide
14
+ glyph=cpu
15
+
16
+ 5WH:
17
+ WHAT = Process agent — handles process ownership, shutdown sequencing, and zombie cleanup
18
+ WHY = Unmanaged processes cause resource leaks, port conflicts, and failed restarts
19
+ WHO = Rapid Web Development
20
+ WHERE = src/agents/mcp/process-agent.js
21
+ WHEN = 2026
22
+ HOW = Tracks PID registry in .leeway/processes.json, validates liveness, signals shutdown
23
+
24
+ AGENTS:
25
+ PROCESS
26
+ PORT
27
+ HEALTH
28
+
29
+ LICENSE:
30
+ MIT
31
+ */
32
+
33
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
34
+ import { join } from 'node:path';
35
+
36
+ /**
37
+ * ProcessAgent tracks and manages process ownership and lifecycle.
38
+ */
39
+ export class ProcessAgent {
40
+ constructor(options = {}) {
41
+ this.rootDir = options.rootDir || process.cwd();
42
+ this.registryPath = join(this.rootDir, '.leeway', 'processes.json');
43
+ this.registry = null;
44
+ }
45
+
46
+ async _load() {
47
+ if (this.registry) return this.registry;
48
+ try {
49
+ const raw = await readFile(this.registryPath, 'utf8');
50
+ this.registry = JSON.parse(raw);
51
+ } catch {
52
+ this.registry = { processes: {} };
53
+ }
54
+ return this.registry;
55
+ }
56
+
57
+ async _save() {
58
+ await mkdir(join(this.rootDir, '.leeway'), { recursive: true });
59
+ await writeFile(this.registryPath, JSON.stringify(this.registry, null, 2), 'utf8');
60
+ }
61
+
62
+ /**
63
+ * Register a process.
64
+ *
65
+ * @param {string} name - Process identifier
66
+ * @param {number} pid - OS process ID
67
+ * @param {object} [meta] - Additional metadata
68
+ */
69
+ async register(name, pid, meta = {}) {
70
+ const reg = await this._load();
71
+ reg.processes[name] = { pid, registered: new Date().toISOString(), ...meta };
72
+ await this._save();
73
+ }
74
+
75
+ /**
76
+ * Check if a process is alive.
77
+ *
78
+ * @param {string} name
79
+ * @returns {Promise<{ alive: boolean, pid: number | null }>}
80
+ */
81
+ async isAlive(name) {
82
+ const reg = await this._load();
83
+ const entry = reg.processes[name];
84
+ if (!entry) return { alive: false, pid: null };
85
+
86
+ try {
87
+ process.kill(entry.pid, 0);
88
+ return { alive: true, pid: entry.pid };
89
+ } catch {
90
+ return { alive: false, pid: entry.pid };
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Clean up zombie entries (processes that are no longer alive).
96
+ * @returns {Promise<string[]>} - Names of cleaned processes
97
+ */
98
+ async cleanZombies() {
99
+ const reg = await this._load();
100
+ const cleaned = [];
101
+
102
+ for (const [name, entry] of Object.entries(reg.processes)) {
103
+ try {
104
+ process.kill(entry.pid, 0);
105
+ } catch {
106
+ delete reg.processes[name];
107
+ cleaned.push(name);
108
+ }
109
+ }
110
+
111
+ if (cleaned.length > 0) await this._save();
112
+ return cleaned;
113
+ }
114
+
115
+ /**
116
+ * Deregister a process entry.
117
+ * @param {string} name
118
+ */
119
+ async deregister(name) {
120
+ const reg = await this._load();
121
+ delete reg.processes[name];
122
+ await this._save();
123
+ }
124
+ }