@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.
- package/.leeway/config.json +133 -0
- package/LICENSE +21 -0
- package/LeeWay-Standards/LICENSE +21 -0
- package/LeeWay-Standards/README.md +324 -0
- package/LeeWay-Standards/examples/NexusButton.tsx +90 -0
- package/LeeWay-Standards/examples/example-agent.js +89 -0
- package/LeeWay-Standards/package.json +61 -0
- package/LeeWay-Standards/schemas/leeway-config.schema.json +81 -0
- package/LeeWay-Standards/schemas/leeway-header.schema.json +63 -0
- package/LeeWay-Standards/src/agents/discovery/architecture-map-agent.js +134 -0
- package/LeeWay-Standards/src/agents/discovery/docs-agent.js +126 -0
- package/LeeWay-Standards/src/agents/discovery/explain-agent.js +95 -0
- package/LeeWay-Standards/src/agents/discovery/intent-registry-agent.js +119 -0
- package/LeeWay-Standards/src/agents/discovery/schema-agent.js +116 -0
- package/LeeWay-Standards/src/agents/discovery/sitemap-agent.js +88 -0
- package/LeeWay-Standards/src/agents/governance/align-agent.js +155 -0
- package/LeeWay-Standards/src/agents/governance/assess-agent.js +161 -0
- package/LeeWay-Standards/src/agents/governance/audit-agent.js +185 -0
- package/LeeWay-Standards/src/agents/integrity/circular-dependency-agent.js +88 -0
- package/LeeWay-Standards/src/agents/integrity/dependency-graph-agent.js +107 -0
- package/LeeWay-Standards/src/agents/integrity/duplicate-logic-agent.js +108 -0
- package/LeeWay-Standards/src/agents/integrity/import-agent.js +83 -0
- package/LeeWay-Standards/src/agents/integrity/module-policy-agent.js +94 -0
- package/LeeWay-Standards/src/agents/integrity/refactor-scan-agent.js +113 -0
- package/LeeWay-Standards/src/agents/integrity/syntax-agent.js +84 -0
- package/LeeWay-Standards/src/agents/mcp/endpoint-agent.js +106 -0
- package/LeeWay-Standards/src/agents/mcp/env-agent.js +111 -0
- package/LeeWay-Standards/src/agents/mcp/health-agent-lite.js +119 -0
- package/LeeWay-Standards/src/agents/mcp/manifest-agent.js +87 -0
- package/LeeWay-Standards/src/agents/mcp/port-agent.js +125 -0
- package/LeeWay-Standards/src/agents/mcp/process-agent.js +124 -0
- package/LeeWay-Standards/src/agents/mcp/runtime-agent.js +108 -0
- package/LeeWay-Standards/src/agents/mcp/transport-agent.js +78 -0
- package/LeeWay-Standards/src/agents/orchestration/doctor-agent.js +149 -0
- package/LeeWay-Standards/src/agents/orchestration/memory-agent-lite.js +125 -0
- package/LeeWay-Standards/src/agents/orchestration/router-agent.js +110 -0
- package/LeeWay-Standards/src/agents/security/permission-agent.js +98 -0
- package/LeeWay-Standards/src/agents/security/policy-agent.js +100 -0
- package/LeeWay-Standards/src/agents/security/privacy-agent.js +83 -0
- package/LeeWay-Standards/src/agents/security/prompt-security-agent.js +103 -0
- package/LeeWay-Standards/src/agents/security/secret-scan-agent.js +108 -0
- package/LeeWay-Standards/src/agents/security/tool-access-agent.js +105 -0
- package/LeeWay-Standards/src/agents/standards/authority-agent.js +114 -0
- package/LeeWay-Standards/src/agents/standards/discovery-pipeline-agent.js +91 -0
- package/LeeWay-Standards/src/agents/standards/header-agent.js +120 -0
- package/LeeWay-Standards/src/agents/standards/placement-agent.js +96 -0
- package/LeeWay-Standards/src/agents/standards/region-agent.js +99 -0
- package/LeeWay-Standards/src/agents/standards/registry-agent.js +153 -0
- package/LeeWay-Standards/src/agents/standards/tag-agent.js +111 -0
- package/LeeWay-Standards/src/cli/leeway.js +225 -0
- package/LeeWay-Standards/src/core/compliance-scorer.js +168 -0
- package/LeeWay-Standards/src/core/compliance-scorer.test.js +121 -0
- package/LeeWay-Standards/src/core/header-parser.js +207 -0
- package/LeeWay-Standards/src/core/header-parser.test.js +198 -0
- package/LeeWay-Standards/src/core/region-classifier.js +137 -0
- package/LeeWay-Standards/src/core/region-classifier.test.js +100 -0
- package/LeeWay-Standards/src/core/tag-validator.js +139 -0
- package/LeeWay-Standards/src/core/tag-validator.test.js +109 -0
- package/LeeWay-Standards/src/index.js +83 -0
- package/README.md +217 -0
- package/agent-config.yaml +456 -0
- package/agentbage.png.png +0 -0
- package/bin/leeway-skills-badge.js +52 -0
- package/bin/leeway-skills-mcp.js +48 -0
- package/bin/leeway-skills.js +160 -0
- package/bin/leeway-standards.js +49 -0
- package/config/.skillsignore +63 -0
- package/config/skills-config.json +70 -0
- package/documents/AGENT_LEARNING_REFERENCE.md +329 -0
- package/documents/AGENT_LEE_INTEGRATION.md +534 -0
- package/documents/COMPLETE_SYSTEM_OVERVIEW.md +502 -0
- package/documents/COMPREHENSIVE_SKILL_INTEGRATION_PLAN.md +644 -0
- package/documents/DIRECTORY_MAP.md +323 -0
- package/documents/EXTENDING.md +514 -0
- package/documents/FILE_DIRECTORY_GUIDE.md +427 -0
- package/documents/LEEWAY_BADGE_INTEGRATION.md +76 -0
- package/documents/LEEWAY_IMPLEMENTATION_SUMMARY.md +384 -0
- package/documents/LEEWAY_INTEGRATION_GUIDE.md +414 -0
- package/documents/LEEWAY_NPM_SDK.md +66 -0
- package/documents/LEEWAY_QUICK_START.md +288 -0
- package/documents/LEEWAY_SKILLS_BRANDING.md +375 -0
- package/documents/LEEWAY_SKILLS_MCP_SUMMARY.md +593 -0
- package/documents/LEEWAY_STANDARDS_COMPLIANCE.md +361 -0
- package/documents/LEEWAY_UNIFIED_ARCHITECTURE.md +473 -0
- package/documents/LEEWAY_WORKFLOWS_QUICK_REFERENCE.md +307 -0
- package/documents/LEEWAY_WORKFLOWS_STRATEGIC_PLAN.md +515 -0
- package/documents/LIFELONG_LEARNING_LAYER.md +478 -0
- package/documents/MCP_ARCHITECTURE.md +683 -0
- package/documents/QUICK_REFERENCE.md +301 -0
- package/documents/SETUP.md +325 -0
- package/documents/SETUP_SUMMARY.md +413 -0
- package/documents/SKILL_ACQUISITION_EXECUTIVE_SUMMARY.md +373 -0
- package/documents/SKILL_ACQUISITION_IMPLEMENTATION.md +692 -0
- package/documents/SKILL_ACQUISITION_MANIFEST.md +404 -0
- package/documents/SKILL_ACQUISITION_QUICK_REFERENCE.md +349 -0
- package/documents/SKILL_WORKFLOW_COMPOSITION_MATRIX.md +537 -0
- package/documents/STRUCTURE.md +382 -0
- package/documents/SYSTEM_TRANSFORMATION_SUMMARY.md +560 -0
- package/documents/USAGE.md +390 -0
- package/documents/WORKFLOW_ACQUISITION_MANIFEST.md +576 -0
- package/documents/aiskills.txt +460 -0
- package/mcp-server/README.md +697 -0
- package/mcp-server/dist/badge-proof.d.ts +66 -0
- package/mcp-server/dist/badge-proof.d.ts.map +1 -0
- package/mcp-server/dist/badge-proof.js +324 -0
- package/mcp-server/dist/badge-proof.js.map +1 -0
- package/mcp-server/dist/index.d.ts +64 -0
- package/mcp-server/dist/index.d.ts.map +1 -0
- package/mcp-server/dist/index.js +263 -0
- package/mcp-server/dist/index.js.map +1 -0
- package/mcp-server/dist/install-badge-proof.d.ts +3 -0
- package/mcp-server/dist/install-badge-proof.d.ts.map +1 -0
- package/mcp-server/dist/install-badge-proof.js +109 -0
- package/mcp-server/dist/install-badge-proof.js.map +1 -0
- package/mcp-server/package.json +43 -0
- package/mcp-server/src/badge-proof.ts +469 -0
- package/mcp-server/src/index.ts +355 -0
- package/mcp-server/src/install-badge-proof.ts +132 -0
- package/mcp-server/tsconfig.json +22 -0
- package/package.json +84 -0
- package/scripts/init-leeway.js +217 -0
- package/scripts/leeway-agents/compliance-monitor.js +374 -0
- package/scripts/leeway-agents/header-injector.js +321 -0
- package/scripts/skill-integration-toolkit.py +319 -0
- package/scripts/skills-registry.json +1117 -0
- package/scripts/sync-skills.ps1 +275 -0
- package/scripts/verify-leeway-setup.js +249 -0
- package/scripts/workflow-integration-toolkit.py +522 -0
- package/sdk/application-installer.js +92 -0
- package/sdk/index.js +43 -0
- package/sdk/paths.js +167 -0
- package/skills/agent-autonomy/autonomous-conductor/SKILL.md +206 -0
- package/skills/agent-autonomy/full-stack-delivery/SKILL.md +206 -0
- package/skills/agent-orchestration/multi-agent-orchestration/SKILL.md +68 -0
- package/skills/agent-patterns/agent-design-patterns/SKILL.md +70 -0
- package/skills/ai-ml/llm-prompting/SKILL.md +71 -0
- package/skills/ai-ml/ml-model-development/SKILL.md +67 -0
- package/skills/ai-ml/multimodal-systems/SKILL.md +71 -0
- package/skills/ai-ml/retrieval-generation-fine-tuning/SKILL.md +71 -0
- package/skills/architecture/system-design/SKILL.md +67 -0
- package/skills/code-analysis/refactoring/SKILL.md +64 -0
- package/skills/code-analysis/security-vulnerability-scanning/SKILL.md +71 -0
- package/skills/code-analysis/static-analysis/SKILL.md +64 -0
- package/skills/code-generation/full-stack-application/SKILL.md +70 -0
- package/skills/code-generation/microservices-architecture/SKILL.md +71 -0
- package/skills/code-generation/python-codegen/SKILL.md +64 -0
- package/skills/code-generation/typescript-codegen/SKILL.md +64 -0
- package/skills/data-analysis/advanced-analytics/SKILL.md +71 -0
- package/skills/data-analysis/pandas-analysis/SKILL.md +66 -0
- package/skills/database-design/database-design-optimization/SKILL.md +70 -0
- package/skills/debugging/javascript-debugging/SKILL.md +67 -0
- package/skills/debugging/python-debugging/SKILL.md +67 -0
- package/skills/devops/dockerfile-creation/SKILL.md +64 -0
- package/skills/devops/kubernetes-deployment/SKILL.md +65 -0
- package/skills/documentation/api-documentation/SKILL.md +67 -0
- package/skills/error-handling/resilience-patterns/SKILL.md +70 -0
- package/skills/git-workflow/git-collaboration/SKILL.md +67 -0
- package/skills/infrastructure/cicd-pipelines/SKILL.md +70 -0
- package/skills/infrastructure/infrastructure-as-code/SKILL.md +70 -0
- package/skills/observability/monitoring-and-observability/SKILL.md +70 -0
- package/skills/performance-optimization/performance-engineering/SKILL.md +70 -0
- package/skills/prompt-optimization/prompt-engineering-advanced/SKILL.md +70 -0
- package/skills/quality-assurance/deployment-validator/SKILL.md +382 -0
- package/skills/quality-assurance/web-security-sweep/SKILL.md +320 -0
- package/skills/rag-knowledge/rag-systems/SKILL.md +70 -0
- package/skills/research/knowledge-synthesis/SKILL.md +71 -0
- package/skills/security/authentication-authorization/SKILL.md +71 -0
- package/skills/security/code-security/SKILL.md +66 -0
- package/skills/security/secure-architecture/SKILL.md +71 -0
- package/skills/self-optimization/dev-loop-optimizer/SKILL.md +344 -0
- package/skills/self-optimization/memory-learning/SKILL.md +335 -0
- package/skills/self-optimization/runtime-self-profiling/SKILL.md +250 -0
- package/skills/testing/advanced-testing-strategies/SKILL.md +71 -0
- package/skills/testing/integration-testing/SKILL.md +66 -0
- package/skills/testing/load-testing-capacity/SKILL.md +71 -0
- package/skills/testing/unit-testing/SKILL.md +66 -0
- package/skills/tool-integration/custom-tool-creation/SKILL.md +70 -0
- package/skills/web-development/advanced-frontend-patterns/SKILL.md +71 -0
- package/skills/web-development/api-design/SKILL.md +71 -0
- package/skills/web-development/css-styling/SKILL.md +67 -0
- package/skills/web-development/react-development/SKILL.md +79 -0
- package/skills/workflow-composition/workflow-orchestration/SKILL.md +70 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/*
|
|
2
|
+
LEEWAY HEADER — DO NOT REMOVE
|
|
3
|
+
|
|
4
|
+
REGION: AI.AGENT.STANDARDS
|
|
5
|
+
TAG: AI.AGENT.HEADER.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-plus
|
|
15
|
+
|
|
16
|
+
5WH:
|
|
17
|
+
WHAT = Header agent — inserts and repairs LEEWAY headers in source files
|
|
18
|
+
WHY = All LEEWAY files must have a valid identity header; this agent enforces that rule
|
|
19
|
+
WHO = Rapid Web Development
|
|
20
|
+
WHERE = src/agents/standards/header-agent.js
|
|
21
|
+
WHEN = 2026
|
|
22
|
+
HOW = Reads files, detects missing or malformed headers, inserts or repairs as needed
|
|
23
|
+
|
|
24
|
+
AGENTS:
|
|
25
|
+
HEADER
|
|
26
|
+
ASSESS
|
|
27
|
+
ALIGN
|
|
28
|
+
|
|
29
|
+
LICENSE:
|
|
30
|
+
MIT
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
34
|
+
import { join } from 'node:path';
|
|
35
|
+
import { parseHeader, validateHeader, buildHeader } from '../../core/header-parser.js';
|
|
36
|
+
import { inferTag } from '../../core/tag-validator.js';
|
|
37
|
+
import { classifyRegion } from '../../core/region-classifier.js';
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* HeaderAgent inserts and repairs LEEWAY headers in source files.
|
|
41
|
+
*/
|
|
42
|
+
export class HeaderAgent {
|
|
43
|
+
constructor(options = {}) {
|
|
44
|
+
this.rootDir = options.rootDir || process.cwd();
|
|
45
|
+
this.dryRun = options.dryRun !== false;
|
|
46
|
+
this.author = options.author || 'LEEWAY Header Agent';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Process a single file — insert header if missing, repair if invalid.
|
|
51
|
+
*
|
|
52
|
+
* @param {string} filePath - Absolute or relative file path
|
|
53
|
+
* @returns {Promise<{ file: string, action: string, dryRun: boolean }>}
|
|
54
|
+
*/
|
|
55
|
+
async processFile(filePath) {
|
|
56
|
+
const fullPath = filePath.startsWith('/') ? filePath : join(this.rootDir, filePath);
|
|
57
|
+
const relPath = filePath.startsWith('/') ? filePath.replace(this.rootDir + '/', '') : filePath;
|
|
58
|
+
|
|
59
|
+
let content;
|
|
60
|
+
try {
|
|
61
|
+
content = await readFile(fullPath, 'utf8');
|
|
62
|
+
} catch (err) {
|
|
63
|
+
return { file: relPath, action: 'error', reason: err.message };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const header = parseHeader(content);
|
|
67
|
+
|
|
68
|
+
if (!header) {
|
|
69
|
+
return this._insertHeader(fullPath, relPath, content);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const { valid, errors } = validateHeader(header);
|
|
73
|
+
if (!valid) {
|
|
74
|
+
return { file: relPath, action: 'needs_repair', errors, dryRun: this.dryRun };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return { file: relPath, action: 'valid', dryRun: this.dryRun };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async _insertHeader(fullPath, relPath, content) {
|
|
81
|
+
const regionResult = classifyRegion(relPath);
|
|
82
|
+
const tag = inferTag(relPath);
|
|
83
|
+
const fileName = relPath.split('/').pop().replace(/\.[^.]+$/, '');
|
|
84
|
+
|
|
85
|
+
const headerBlock = buildHeader({
|
|
86
|
+
region: regionResult.region,
|
|
87
|
+
tag,
|
|
88
|
+
fiveWH: {
|
|
89
|
+
WHAT: `${fileName} module`,
|
|
90
|
+
WHY: `${regionResult.metadata.description}`,
|
|
91
|
+
WHO: this.author,
|
|
92
|
+
WHERE: relPath,
|
|
93
|
+
WHEN: new Date().getFullYear().toString(),
|
|
94
|
+
HOW: 'Auto-inserted by LEEWAY header-agent',
|
|
95
|
+
},
|
|
96
|
+
agents: ['ASSESS', 'ALIGN', 'AUDIT'],
|
|
97
|
+
license: 'MIT',
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
if (!this.dryRun) {
|
|
101
|
+
await writeFile(fullPath, headerBlock + '\n' + content, 'utf8');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return { file: relPath, action: 'header_inserted', dryRun: this.dryRun };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Process multiple files.
|
|
109
|
+
*
|
|
110
|
+
* @param {string[]} filePaths
|
|
111
|
+
* @returns {Promise<object[]>}
|
|
112
|
+
*/
|
|
113
|
+
async processFiles(filePaths) {
|
|
114
|
+
const results = [];
|
|
115
|
+
for (const fp of filePaths) {
|
|
116
|
+
results.push(await this.processFile(fp));
|
|
117
|
+
}
|
|
118
|
+
return results;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/*
|
|
2
|
+
LEEWAY HEADER — DO NOT REMOVE
|
|
3
|
+
|
|
4
|
+
REGION: AI.AGENT.STANDARDS
|
|
5
|
+
TAG: AI.AGENT.PLACEMENT.MAIN
|
|
6
|
+
|
|
7
|
+
COLOR_ONION_HEX:
|
|
8
|
+
NEON=#39FF14
|
|
9
|
+
FLUO=#0DFF94
|
|
10
|
+
PASTEL=#C7FFD8
|
|
11
|
+
|
|
12
|
+
ICON_ASCII:
|
|
13
|
+
family=lucide
|
|
14
|
+
glyph=folder-check
|
|
15
|
+
|
|
16
|
+
5WH:
|
|
17
|
+
WHAT = Placement agent — checks file placement against LEEWAY directory structure rules
|
|
18
|
+
WHY = Files in wrong directories break discoverability and architecture legibility
|
|
19
|
+
WHO = Rapid Web Development
|
|
20
|
+
WHERE = src/agents/standards/placement-agent.js
|
|
21
|
+
WHEN = 2026
|
|
22
|
+
HOW = Compares declared REGION against expected directory paths, reports misplacements
|
|
23
|
+
|
|
24
|
+
AGENTS:
|
|
25
|
+
PLACEMENT
|
|
26
|
+
ASSESS
|
|
27
|
+
AUDIT
|
|
28
|
+
|
|
29
|
+
LICENSE:
|
|
30
|
+
MIT
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import { readFile } from 'node:fs/promises';
|
|
34
|
+
import { join, dirname } from 'node:path';
|
|
35
|
+
import { parseHeader } from '../../core/header-parser.js';
|
|
36
|
+
import { classifyRegion } from '../../core/region-classifier.js';
|
|
37
|
+
|
|
38
|
+
const REGION_EXPECTED_DIRS = {
|
|
39
|
+
UI: ['src/components', 'src/pages', 'src/layouts', 'src/ui', 'src/views', 'src/screens'],
|
|
40
|
+
CORE: ['src/core', 'src/sdk', 'src/lib', 'src/runtime', 'src/engine'],
|
|
41
|
+
DATA: ['src/data', 'src/store', 'src/stores', 'src/db', 'src/models'],
|
|
42
|
+
AI: ['src/ai', 'src/agents', 'src/llm', 'src/ml', 'src/prompts'],
|
|
43
|
+
SEO: ['src/seo', 'src/discovery', 'src/schema', 'src/sitemap'],
|
|
44
|
+
UTIL: ['src/utils', 'src/util', 'src/helpers', 'src/shared'],
|
|
45
|
+
MCP: ['src/mcp', 'src/transport', 'src/endpoints'],
|
|
46
|
+
SECURITY: ['src/security', 'src/auth', 'src/authorization'],
|
|
47
|
+
TEST: ['src/tests', 'src/__tests__', 'test', 'tests', '__tests__'],
|
|
48
|
+
DOCS: ['docs', 'documentation', 'guides'],
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* PlacementAgent validates that files are in the correct LEEWAY directories.
|
|
53
|
+
*/
|
|
54
|
+
export class PlacementAgent {
|
|
55
|
+
constructor(options = {}) {
|
|
56
|
+
this.rootDir = options.rootDir || process.cwd();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Check placement of a file.
|
|
61
|
+
*
|
|
62
|
+
* @param {string} filePath
|
|
63
|
+
* @returns {Promise<PlacementResult>}
|
|
64
|
+
*/
|
|
65
|
+
async checkFile(filePath) {
|
|
66
|
+
const fullPath = filePath.startsWith('/') ? filePath : join(this.rootDir, filePath);
|
|
67
|
+
const relPath = filePath.startsWith('/') ? filePath.replace(this.rootDir + '/', '') : filePath;
|
|
68
|
+
const normalizedPath = relPath.replace(/\\/g, '/');
|
|
69
|
+
|
|
70
|
+
let content = '';
|
|
71
|
+
try {
|
|
72
|
+
content = await readFile(fullPath, 'utf8');
|
|
73
|
+
} catch {
|
|
74
|
+
return { file: relPath, status: 'error' };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const header = parseHeader(content);
|
|
78
|
+
const declaredRegion = header?.region?.split('.')?.[0];
|
|
79
|
+
const { region: inferredRegion, confidence } = classifyRegion(relPath);
|
|
80
|
+
|
|
81
|
+
const regionToCheck = declaredRegion || inferredRegion;
|
|
82
|
+
const expectedDirs = REGION_EXPECTED_DIRS[regionToCheck] || [];
|
|
83
|
+
const isCorrectlyPlaced = expectedDirs.length === 0
|
|
84
|
+
|| expectedDirs.some(dir => normalizedPath.startsWith(dir.replace(/^\//, '')));
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
file: relPath,
|
|
88
|
+
declaredRegion,
|
|
89
|
+
inferredRegion,
|
|
90
|
+
confidence,
|
|
91
|
+
expectedDirectories: expectedDirs,
|
|
92
|
+
status: isCorrectlyPlaced ? 'correct' : 'misplaced',
|
|
93
|
+
suggestion: isCorrectlyPlaced ? null : `Move to one of: ${expectedDirs.slice(0, 3).join(', ')}`,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/*
|
|
2
|
+
LEEWAY HEADER — DO NOT REMOVE
|
|
3
|
+
|
|
4
|
+
REGION: AI.AGENT.STANDARDS
|
|
5
|
+
TAG: AI.AGENT.REGION.MAIN
|
|
6
|
+
|
|
7
|
+
COLOR_ONION_HEX:
|
|
8
|
+
NEON=#39FF14
|
|
9
|
+
FLUO=#0DFF94
|
|
10
|
+
PASTEL=#C7FFD8
|
|
11
|
+
|
|
12
|
+
ICON_ASCII:
|
|
13
|
+
family=lucide
|
|
14
|
+
glyph=map
|
|
15
|
+
|
|
16
|
+
5WH:
|
|
17
|
+
WHAT = Region agent — assigns REGION correctly to files based on path and content
|
|
18
|
+
WHY = Files must belong to the correct system region for governance and discoverability
|
|
19
|
+
WHO = Rapid Web Development
|
|
20
|
+
WHERE = src/agents/standards/region-agent.js
|
|
21
|
+
WHEN = 2026
|
|
22
|
+
HOW = Path analysis and content scanning to determine the most appropriate region
|
|
23
|
+
|
|
24
|
+
AGENTS:
|
|
25
|
+
REGION
|
|
26
|
+
ASSESS
|
|
27
|
+
|
|
28
|
+
LICENSE:
|
|
29
|
+
MIT
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import { readFile } from 'node:fs/promises';
|
|
33
|
+
import { join } from 'node:path';
|
|
34
|
+
import { classifyRegion, REGIONS } from '../../core/region-classifier.js';
|
|
35
|
+
import { parseHeader } from '../../core/header-parser.js';
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* RegionAgent assigns and validates LEEWAY REGION values.
|
|
39
|
+
*/
|
|
40
|
+
export class RegionAgent {
|
|
41
|
+
constructor(options = {}) {
|
|
42
|
+
this.rootDir = options.rootDir || process.cwd();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Analyze a file and determine its correct REGION.
|
|
47
|
+
*
|
|
48
|
+
* @param {string} filePath
|
|
49
|
+
* @returns {Promise<RegionAnalysis>}
|
|
50
|
+
*/
|
|
51
|
+
async analyzeFile(filePath) {
|
|
52
|
+
const fullPath = filePath.startsWith('/') ? filePath : join(this.rootDir, filePath);
|
|
53
|
+
const relPath = filePath.startsWith('/') ? filePath.replace(this.rootDir + '/', '') : filePath;
|
|
54
|
+
|
|
55
|
+
let content = '';
|
|
56
|
+
try {
|
|
57
|
+
content = await readFile(fullPath, 'utf8');
|
|
58
|
+
} catch {
|
|
59
|
+
return { file: relPath, status: 'error' };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const header = parseHeader(content);
|
|
63
|
+
const { region: inferredRegion, confidence, metadata } = classifyRegion(relPath);
|
|
64
|
+
|
|
65
|
+
if (!header) {
|
|
66
|
+
return {
|
|
67
|
+
file: relPath,
|
|
68
|
+
status: 'no_header',
|
|
69
|
+
inferredRegion,
|
|
70
|
+
confidence,
|
|
71
|
+
description: metadata.description,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const declaredRegion = header.region ? header.region.split('.')[0] : null;
|
|
76
|
+
const mismatch = declaredRegion && declaredRegion !== inferredRegion && confidence === 'high';
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
file: relPath,
|
|
80
|
+
status: mismatch ? 'region_mismatch' : 'valid',
|
|
81
|
+
declaredRegion: header.region,
|
|
82
|
+
inferredRegion,
|
|
83
|
+
confidence,
|
|
84
|
+
description: metadata.description,
|
|
85
|
+
mismatch,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Get a summary of all available regions.
|
|
91
|
+
* @returns {object}
|
|
92
|
+
*/
|
|
93
|
+
getRegionMap() {
|
|
94
|
+
return Object.entries(REGIONS).reduce((acc, [key, val]) => {
|
|
95
|
+
acc[key] = { label: val.label, description: val.description, color: val.color };
|
|
96
|
+
return acc;
|
|
97
|
+
}, {});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/*
|
|
2
|
+
LEEWAY HEADER — DO NOT REMOVE
|
|
3
|
+
|
|
4
|
+
REGION: AI.AGENT.STANDARDS
|
|
5
|
+
TAG: AI.AGENT.REGISTRY.MAIN
|
|
6
|
+
|
|
7
|
+
COLOR_ONION_HEX:
|
|
8
|
+
NEON=#39FF14
|
|
9
|
+
FLUO=#0DFF94
|
|
10
|
+
PASTEL=#C7FFD8
|
|
11
|
+
|
|
12
|
+
ICON_ASCII:
|
|
13
|
+
family=lucide
|
|
14
|
+
glyph=database
|
|
15
|
+
|
|
16
|
+
5WH:
|
|
17
|
+
WHAT = Registry agent — updates tag registry, file registry, and system map
|
|
18
|
+
WHY = A LEEWAY system needs a queryable registry of all files and their identities
|
|
19
|
+
WHO = Rapid Web Development
|
|
20
|
+
WHERE = src/agents/standards/registry-agent.js
|
|
21
|
+
WHEN = 2026
|
|
22
|
+
HOW = Walks codebase, reads LEEWAY headers, writes to .leeway/registry.json
|
|
23
|
+
|
|
24
|
+
AGENTS:
|
|
25
|
+
REGISTRY
|
|
26
|
+
ASSESS
|
|
27
|
+
AUDIT
|
|
28
|
+
|
|
29
|
+
LICENSE:
|
|
30
|
+
MIT
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import { readdir, readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
34
|
+
import { join, relative, extname } from 'node:path';
|
|
35
|
+
import { parseHeader } from '../../core/header-parser.js';
|
|
36
|
+
|
|
37
|
+
const SKIP_DIRS = new Set(['.git', 'node_modules', 'dist', 'build', '.next', '.cache', 'coverage']);
|
|
38
|
+
const CODE_EXTENSIONS = new Set(['.js', '.ts', '.jsx', '.tsx', '.mjs', '.cjs']);
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* RegistryAgent builds and updates the LEEWAY file and tag registries.
|
|
42
|
+
*/
|
|
43
|
+
export class RegistryAgent {
|
|
44
|
+
constructor(options = {}) {
|
|
45
|
+
this.rootDir = options.rootDir || process.cwd();
|
|
46
|
+
this.registryDir = join(this.rootDir, '.leeway');
|
|
47
|
+
this.registryPath = join(this.registryDir, 'registry.json');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Build the registry from the current codebase.
|
|
52
|
+
* @returns {Promise<Registry>}
|
|
53
|
+
*/
|
|
54
|
+
async build() {
|
|
55
|
+
const registry = {
|
|
56
|
+
version: '1.0.1',
|
|
57
|
+
built: new Date().toISOString(),
|
|
58
|
+
rootDir: this.rootDir,
|
|
59
|
+
files: {},
|
|
60
|
+
tags: {},
|
|
61
|
+
regions: {},
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
await this._walk(this.rootDir, registry);
|
|
65
|
+
return registry;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Build and persist the registry to .leeway/registry.json
|
|
70
|
+
* @returns {Promise<Registry>}
|
|
71
|
+
*/
|
|
72
|
+
async buildAndSave() {
|
|
73
|
+
const registry = await this.build();
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
await mkdir(this.registryDir, { recursive: true });
|
|
77
|
+
await writeFile(this.registryPath, JSON.stringify(registry, null, 2), 'utf8');
|
|
78
|
+
registry.savedTo = this.registryPath;
|
|
79
|
+
} catch (err) {
|
|
80
|
+
registry.saveError = err.message;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return registry;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Load the existing registry from disk.
|
|
88
|
+
* @returns {Promise<Registry | null>}
|
|
89
|
+
*/
|
|
90
|
+
async load() {
|
|
91
|
+
try {
|
|
92
|
+
const raw = await readFile(this.registryPath, 'utf8');
|
|
93
|
+
return JSON.parse(raw);
|
|
94
|
+
} catch {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async _walk(dir, registry, depth = 0) {
|
|
100
|
+
if (depth > 10) return;
|
|
101
|
+
|
|
102
|
+
let entries;
|
|
103
|
+
try {
|
|
104
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
105
|
+
} catch {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
for (const entry of entries) {
|
|
110
|
+
if (SKIP_DIRS.has(entry.name)) continue;
|
|
111
|
+
const fullPath = join(dir, entry.name);
|
|
112
|
+
const relPath = relative(this.rootDir, fullPath);
|
|
113
|
+
|
|
114
|
+
if (entry.isDirectory()) {
|
|
115
|
+
await this._walk(fullPath, registry, depth + 1);
|
|
116
|
+
} else if (entry.isFile() && CODE_EXTENSIONS.has(extname(entry.name))) {
|
|
117
|
+
await this._indexFile(fullPath, relPath, registry);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async _indexFile(fullPath, relPath, registry) {
|
|
123
|
+
let content;
|
|
124
|
+
try {
|
|
125
|
+
content = await readFile(fullPath, 'utf8');
|
|
126
|
+
} catch {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const header = parseHeader(content);
|
|
131
|
+
const entry = {
|
|
132
|
+
path: relPath,
|
|
133
|
+
hasHeader: !!header,
|
|
134
|
+
region: header?.region || null,
|
|
135
|
+
tag: header?.tag || null,
|
|
136
|
+
agents: header?.agents || [],
|
|
137
|
+
license: header?.license || null,
|
|
138
|
+
fiveWH: header?.fiveWH || {},
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
registry.files[relPath] = entry;
|
|
142
|
+
|
|
143
|
+
if (header?.tag) {
|
|
144
|
+
if (!registry.tags[header.tag]) registry.tags[header.tag] = [];
|
|
145
|
+
registry.tags[header.tag].push(relPath);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (header?.region) {
|
|
149
|
+
const regionKey = header.region.split('.')[0];
|
|
150
|
+
registry.regions[regionKey] = (registry.regions[regionKey] || 0) + 1;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/*
|
|
2
|
+
LEEWAY HEADER — DO NOT REMOVE
|
|
3
|
+
|
|
4
|
+
REGION: AI.AGENT.STANDARDS
|
|
5
|
+
TAG: AI.AGENT.TAG.MAIN
|
|
6
|
+
|
|
7
|
+
COLOR_ONION_HEX:
|
|
8
|
+
NEON=#39FF14
|
|
9
|
+
FLUO=#0DFF94
|
|
10
|
+
PASTEL=#C7FFD8
|
|
11
|
+
|
|
12
|
+
ICON_ASCII:
|
|
13
|
+
family=lucide
|
|
14
|
+
glyph=tag
|
|
15
|
+
|
|
16
|
+
5WH:
|
|
17
|
+
WHAT = Tag agent — infers TAG values from file path, purpose, and role
|
|
18
|
+
WHY = Every file needs an accurate TAG for the system to be machine-searchable
|
|
19
|
+
WHO = Rapid Web Development
|
|
20
|
+
WHERE = src/agents/standards/tag-agent.js
|
|
21
|
+
WHEN = 2026
|
|
22
|
+
HOW = Uses path heuristics and file content analysis to suggest optimal TAGs
|
|
23
|
+
|
|
24
|
+
AGENTS:
|
|
25
|
+
TAG
|
|
26
|
+
ASSESS
|
|
27
|
+
|
|
28
|
+
LICENSE:
|
|
29
|
+
MIT
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import { readFile } from 'node:fs/promises';
|
|
33
|
+
import { join, extname } from 'node:path';
|
|
34
|
+
import { validateTag, inferTag } from '../../core/tag-validator.js';
|
|
35
|
+
import { parseHeader } from '../../core/header-parser.js';
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* TagAgent infers and validates LEEWAY TAG values for files.
|
|
39
|
+
*/
|
|
40
|
+
export class TagAgent {
|
|
41
|
+
constructor(options = {}) {
|
|
42
|
+
this.rootDir = options.rootDir || process.cwd();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Analyze a file and suggest or validate its TAG.
|
|
47
|
+
*
|
|
48
|
+
* @param {string} filePath
|
|
49
|
+
* @returns {Promise<TagAnalysis>}
|
|
50
|
+
*/
|
|
51
|
+
async analyzeFile(filePath) {
|
|
52
|
+
const fullPath = filePath.startsWith('/') ? filePath : join(this.rootDir, filePath);
|
|
53
|
+
const relPath = filePath.startsWith('/') ? filePath.replace(this.rootDir + '/', '') : filePath;
|
|
54
|
+
|
|
55
|
+
let content = '';
|
|
56
|
+
try {
|
|
57
|
+
content = await readFile(fullPath, 'utf8');
|
|
58
|
+
} catch {
|
|
59
|
+
return { file: relPath, status: 'error', reason: 'Cannot read file' };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const header = parseHeader(content);
|
|
63
|
+
const suggestedTag = inferTag(relPath, this._extractContext(content));
|
|
64
|
+
|
|
65
|
+
if (!header) {
|
|
66
|
+
return {
|
|
67
|
+
file: relPath,
|
|
68
|
+
status: 'no_header',
|
|
69
|
+
suggestedTag,
|
|
70
|
+
currentTag: null,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (!header.tag) {
|
|
75
|
+
return {
|
|
76
|
+
file: relPath,
|
|
77
|
+
status: 'missing_tag',
|
|
78
|
+
suggestedTag,
|
|
79
|
+
currentTag: null,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const { valid, errors } = validateTag(header.tag);
|
|
84
|
+
return {
|
|
85
|
+
file: relPath,
|
|
86
|
+
status: valid ? 'valid' : 'invalid_tag',
|
|
87
|
+
currentTag: header.tag,
|
|
88
|
+
suggestedTag: valid ? header.tag : suggestedTag,
|
|
89
|
+
errors: valid ? [] : errors,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
_extractContext(content) {
|
|
94
|
+
const lines = content.split('\n').slice(0, 30).join(' ');
|
|
95
|
+
const purposeMatch = lines.match(/(?:export|function|class|const)\s+([A-Za-z][A-Za-z0-9]+)/);
|
|
96
|
+
return { purpose: purposeMatch ? purposeMatch[1] : 'MAIN' };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Analyze multiple files.
|
|
101
|
+
* @param {string[]} filePaths
|
|
102
|
+
* @returns {Promise<TagAnalysis[]>}
|
|
103
|
+
*/
|
|
104
|
+
async analyzeFiles(filePaths) {
|
|
105
|
+
const results = [];
|
|
106
|
+
for (const fp of filePaths) {
|
|
107
|
+
results.push(await this.analyzeFile(fp));
|
|
108
|
+
}
|
|
109
|
+
return results;
|
|
110
|
+
}
|
|
111
|
+
}
|