aios-core 2.2.2 → 2.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.
- package/.aios-core/.session/current-session.json +14 -14
- package/.aios-core/cli/commands/migrate/validate.js +1 -1
- package/.aios-core/core/docs/session-update-pattern.md +17 -10
- package/.aios-core/core/elicitation/elicitation-engine.js +11 -6
- package/.aios-core/core/elicitation/session-manager.js +2 -1
- package/.aios-core/core/registry/registry-schema.json +166 -166
- package/.aios-core/core/registry/service-registry.json +6585 -6585
- package/.aios-core/core-config.yaml +12 -1
- package/.aios-core/data/agent-config-requirements.yaml +5 -5
- package/.aios-core/development/agents/devops.md +12 -0
- package/.aios-core/development/scripts/squad/README.md +112 -0
- package/.aios-core/development/scripts/squad/index.js +41 -0
- package/.aios-core/development/scripts/squad/squad-loader.js +359 -0
- package/.aios-core/development/scripts/squad/squad-validator.js +685 -0
- package/.aios-core/development/tasks/add-mcp.md +11 -5
- package/.aios-core/development/tasks/search-mcp.md +309 -0
- package/.aios-core/development/tasks/setup-mcp-docker.md +11 -8
- package/.aios-core/development/tasks/squad-creator-validate.md +151 -0
- package/.aios-core/docs/standards/AGENT-PERSONALIZATION-STANDARD-V1.md +3 -3
- package/.aios-core/index.d.ts +7 -7
- package/.aios-core/index.js +1 -1
- package/.aios-core/infrastructure/scripts/batch-creator.js +1 -1
- package/.aios-core/infrastructure/scripts/component-generator.js +1 -1
- package/.aios-core/infrastructure/templates/coderabbit.yaml.template +279 -279
- package/.aios-core/infrastructure/templates/github-workflows/ci.yml.template +169 -169
- package/.aios-core/infrastructure/templates/github-workflows/pr-automation.yml.template +330 -330
- package/.aios-core/infrastructure/templates/github-workflows/release.yml.template +196 -196
- package/.aios-core/infrastructure/templates/gitignore/gitignore-aios-base.tmpl +63 -63
- package/.aios-core/infrastructure/templates/gitignore/gitignore-brownfield-merge.tmpl +18 -18
- package/.aios-core/infrastructure/templates/gitignore/gitignore-node.tmpl +85 -85
- package/.aios-core/infrastructure/templates/gitignore/gitignore-python.tmpl +145 -145
- package/.aios-core/infrastructure/tests/utilities-audit-results.json +500 -500
- package/.aios-core/infrastructure/tools/README.md +1 -1
- package/.aios-core/install-manifest.yaml +4 -1
- package/.aios-core/manifests/schema/manifest-schema.json +190 -190
- package/.aios-core/manifests/workers.csv +203 -203
- package/.aios-core/package.json +102 -102
- package/.aios-core/product/templates/activation-instructions-template.md +7 -7
- package/.aios-core/product/templates/adr.hbs +125 -125
- package/.aios-core/product/templates/component-react-tmpl.tsx +98 -98
- package/.aios-core/product/templates/dbdr.hbs +241 -241
- package/.aios-core/product/templates/engine/schemas/adr.schema.json +102 -102
- package/.aios-core/product/templates/engine/schemas/dbdr.schema.json +205 -205
- package/.aios-core/product/templates/engine/schemas/epic.schema.json +175 -175
- package/.aios-core/product/templates/engine/schemas/pmdr.schema.json +175 -175
- package/.aios-core/product/templates/engine/schemas/prd-v2.schema.json +300 -300
- package/.aios-core/product/templates/engine/schemas/prd.schema.json +152 -152
- package/.aios-core/product/templates/engine/schemas/story.schema.json +222 -222
- package/.aios-core/product/templates/engine/schemas/task.schema.json +154 -154
- package/.aios-core/product/templates/epic.hbs +212 -212
- package/.aios-core/product/templates/eslintrc-security.json +32 -32
- package/.aios-core/product/templates/github-actions-cd.yml +212 -212
- package/.aios-core/product/templates/github-actions-ci.yml +172 -172
- package/.aios-core/product/templates/pmdr.hbs +186 -186
- package/.aios-core/product/templates/prd-v2.0.hbs +216 -216
- package/.aios-core/product/templates/prd.hbs +201 -201
- package/.aios-core/product/templates/shock-report-tmpl.html +502 -502
- package/.aios-core/product/templates/story.hbs +263 -263
- package/.aios-core/product/templates/task.hbs +170 -170
- package/.aios-core/product/templates/tmpl-comment-on-examples.sql +158 -158
- package/.aios-core/product/templates/tmpl-migration-script.sql +91 -91
- package/.aios-core/product/templates/tmpl-rls-granular-policies.sql +104 -104
- package/.aios-core/product/templates/tmpl-rls-kiss-policy.sql +10 -10
- package/.aios-core/product/templates/tmpl-rls-roles.sql +135 -135
- package/.aios-core/product/templates/tmpl-rls-simple.sql +77 -77
- package/.aios-core/product/templates/tmpl-rls-tenant.sql +152 -152
- package/.aios-core/product/templates/tmpl-rollback-script.sql +77 -77
- package/.aios-core/product/templates/tmpl-seed-data.sql +140 -140
- package/.aios-core/product/templates/tmpl-smoke-test.sql +16 -16
- package/.aios-core/product/templates/tmpl-staging-copy-merge.sql +139 -139
- package/.aios-core/product/templates/tmpl-stored-proc.sql +140 -140
- package/.aios-core/product/templates/tmpl-trigger.sql +152 -152
- package/.aios-core/product/templates/tmpl-view-materialized.sql +133 -133
- package/.aios-core/product/templates/tmpl-view.sql +177 -177
- package/.aios-core/product/templates/token-exports-css-tmpl.css +240 -240
- package/.aios-core/quality/schemas/quality-metrics.schema.json +233 -233
- package/.aios-core/schemas/squad-schema.json +185 -0
- package/.aios-core/scripts/README.md +90 -322
- package/.aios-core/scripts/migrate-framework-docs.sh +300 -300
- package/.claude/rules/mcp-usage.md +116 -100
- package/LICENSE +48 -48
- package/README.md +3 -4
- package/bin/aios.js +2 -1
- package/package.json +1 -3
- package/packages/installer/package.json +39 -39
- package/templates/squad/LICENSE +21 -21
- package/templates/squad/README.md +37 -37
- package/templates/squad/agents/example-agent.yaml +36 -36
- package/templates/squad/package.json +19 -19
- package/templates/squad/squad.yaml +25 -25
- package/templates/squad/tasks/example-task.yaml +46 -46
- package/templates/squad/templates/example-template.md +24 -24
- package/templates/squad/tests/example-agent.test.js +53 -53
- package/templates/squad/workflows/example-workflow.yaml +54 -54
- package/tools/diagnose-npx-issue.ps1 +96 -96
- package/tools/quick-diagnose.cmd +85 -85
- package/tools/quick-diagnose.ps1 +117 -117
- package/.aios-core/core/data/agent-config-requirements.yaml +0 -368
- package/.aios-core/core/data/aios-kb.md +0 -924
- package/.aios-core/core/data/workflow-patterns.yaml +0 -267
- package/.aios-core/product/templates/1mcp-config.yaml +0 -225
- package/.aios-core/scripts/context-detector.js +0 -226
- package/.aios-core/scripts/elicitation-engine.js +0 -385
- package/.aios-core/scripts/elicitation-session-manager.js +0 -300
- package/.claude/CLAUDE.md +0 -221
|
@@ -69,7 +69,18 @@ slashPrefix: AIOS
|
|
|
69
69
|
# SECTION 3: Resource Locations
|
|
70
70
|
# ============================================
|
|
71
71
|
toolsLocation: .aios-core/tools
|
|
72
|
-
|
|
72
|
+
|
|
73
|
+
# Scripts are organized into modules by domain (Story 6.16)
|
|
74
|
+
# - core: Core framework modules (elicitation, session)
|
|
75
|
+
# - development: Development scripts (greeting, workflow, exit hooks)
|
|
76
|
+
# - infrastructure: Infrastructure scripts (git config, project status, validators)
|
|
77
|
+
# - legacy: Migration utilities only (deprecated scripts have been removed)
|
|
78
|
+
scriptsLocation:
|
|
79
|
+
core: .aios-core/core
|
|
80
|
+
development: .aios-core/development/scripts
|
|
81
|
+
infrastructure: .aios-core/infrastructure/scripts
|
|
82
|
+
legacy: .aios-core/scripts
|
|
83
|
+
|
|
73
84
|
dataLocation: .aios-core/data
|
|
74
85
|
elicitationLocation: .aios-core/elicitation
|
|
75
86
|
# Squads replaced Squads in OSR-8 - see docs/guides/squads-guide.md
|
|
@@ -64,10 +64,10 @@ agents:
|
|
|
64
64
|
- path: .aios-core/data/technical-preferences.md
|
|
65
65
|
lazy: false
|
|
66
66
|
size: 15KB
|
|
67
|
-
- path: .aios-core/data/test-levels-framework.md
|
|
67
|
+
- path: .aios-core/product/data/test-levels-framework.md
|
|
68
68
|
lazy: false
|
|
69
69
|
size: 8KB
|
|
70
|
-
- path: .aios-core/data/test-priorities-matrix.md
|
|
70
|
+
- path: .aios-core/product/data/test-priorities-matrix.md
|
|
71
71
|
lazy: false
|
|
72
72
|
size: 6KB
|
|
73
73
|
lazy_loading:
|
|
@@ -120,7 +120,7 @@ agents:
|
|
|
120
120
|
- storyBacklog
|
|
121
121
|
- templatesLocation
|
|
122
122
|
files_loaded:
|
|
123
|
-
- path: .aios-core/data/elicitation-methods.md
|
|
123
|
+
- path: .aios-core/product/data/elicitation-methods.md
|
|
124
124
|
lazy: false
|
|
125
125
|
size: 5KB
|
|
126
126
|
lazy_loading:
|
|
@@ -134,7 +134,7 @@ agents:
|
|
|
134
134
|
- storyBacklog
|
|
135
135
|
- dataLocation
|
|
136
136
|
files_loaded:
|
|
137
|
-
- path: .aios-core/data/mode-selection-best-practices.md
|
|
137
|
+
- path: .aios-core/product/data/mode-selection-best-practices.md
|
|
138
138
|
lazy: false
|
|
139
139
|
size: 10KB
|
|
140
140
|
- path: .aios-core/data/workflow-patterns.yaml
|
|
@@ -182,7 +182,7 @@ agents:
|
|
|
182
182
|
- dataLocation
|
|
183
183
|
- analyticsLocation
|
|
184
184
|
files_loaded:
|
|
185
|
-
- path: .aios-core/data/brainstorming-techniques.md
|
|
185
|
+
- path: .aios-core/product/data/brainstorming-techniques.md
|
|
186
186
|
lazy: false
|
|
187
187
|
size: 2KB
|
|
188
188
|
lazy_loading: {}
|
|
@@ -158,6 +158,13 @@ commands:
|
|
|
158
158
|
- environment-bootstrap: Complete environment setup for new projects (CLIs, auth, Git/GitHub)
|
|
159
159
|
- setup-github: Configure DevOps infrastructure for user projects (workflows, CodeRabbit, branch protection, secrets) [Story 5.10]
|
|
160
160
|
|
|
161
|
+
# MCP Management (via Docker Gateway) [Story 6.14]
|
|
162
|
+
- search-mcp: Search available MCPs in Docker MCP Toolkit catalog
|
|
163
|
+
- add-mcp: Add MCP server to Docker MCP Toolkit
|
|
164
|
+
- list-mcps: List currently enabled MCPs and their tools
|
|
165
|
+
- remove-mcp: Remove MCP server from Docker MCP Toolkit
|
|
166
|
+
- setup-mcp-docker: Initial Docker MCP Toolkit configuration [Story 5.11]
|
|
167
|
+
|
|
161
168
|
# Utilities
|
|
162
169
|
- session-info: Show current session details (agent history, commands)
|
|
163
170
|
- guide: Show comprehensive usage guide for this agent
|
|
@@ -173,6 +180,10 @@ dependencies:
|
|
|
173
180
|
- ci-cd-configuration.md
|
|
174
181
|
- github-devops-repository-cleanup.md
|
|
175
182
|
- release-management.md
|
|
183
|
+
# MCP Management Tasks [Story 6.14]
|
|
184
|
+
- search-mcp.md
|
|
185
|
+
- add-mcp.md
|
|
186
|
+
- setup-mcp-docker.md
|
|
176
187
|
templates:
|
|
177
188
|
- github-pr-template.md
|
|
178
189
|
- github-actions-ci.yml
|
|
@@ -191,6 +202,7 @@ dependencies:
|
|
|
191
202
|
- coderabbit # Automated code review, pre-PR quality gate
|
|
192
203
|
- github-cli # PRIMARY TOOL - All GitHub operations
|
|
193
204
|
- git # ALL operations including push (EXCLUSIVE to this agent)
|
|
205
|
+
- docker-gateway # Docker MCP Toolkit gateway for MCP management [Story 6.14]
|
|
194
206
|
|
|
195
207
|
coderabbit_integration:
|
|
196
208
|
enabled: true
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Squad Scripts Module
|
|
2
|
+
|
|
3
|
+
Utilities for the squad-creator agent to manage squads in AIOS projects.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This module provides utilities for:
|
|
8
|
+
- **Loading** squad manifests from local directories
|
|
9
|
+
- **Validating** squad structure and configuration (SQS-3)
|
|
10
|
+
- **Generating** new squads from templates (SQS-4)
|
|
11
|
+
|
|
12
|
+
## Components
|
|
13
|
+
|
|
14
|
+
| File | Story | Description |
|
|
15
|
+
|------|-------|-------------|
|
|
16
|
+
| `squad-loader.js` | SQS-2 | Load and resolve squad manifests |
|
|
17
|
+
| `squad-validator.js` | SQS-3 | Validate squad structure |
|
|
18
|
+
| `squad-generator.js` | SQS-4 | Generate new squads |
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
### Squad Loader
|
|
23
|
+
|
|
24
|
+
```javascript
|
|
25
|
+
const { SquadLoader } = require('./.aios-core/development/scripts/squad');
|
|
26
|
+
|
|
27
|
+
// Create loader instance
|
|
28
|
+
const loader = new SquadLoader({
|
|
29
|
+
squadsPath: './squads', // Default: './squads'
|
|
30
|
+
verbose: false // Enable debug logging
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Resolve squad by name
|
|
34
|
+
const { path, manifestPath } = await loader.resolve('my-squad');
|
|
35
|
+
|
|
36
|
+
// Load and parse manifest
|
|
37
|
+
const manifest = await loader.loadManifest('./squads/my-squad');
|
|
38
|
+
|
|
39
|
+
// List all local squads
|
|
40
|
+
const squads = await loader.listLocal();
|
|
41
|
+
// Returns: [{ name, path, manifestPath }, ...]
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Error Handling
|
|
45
|
+
|
|
46
|
+
```javascript
|
|
47
|
+
const { SquadLoader, SquadLoaderError } = require('./.aios-core/development/scripts/squad');
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
const loader = new SquadLoader();
|
|
51
|
+
await loader.resolve('non-existent-squad');
|
|
52
|
+
} catch (error) {
|
|
53
|
+
if (error instanceof SquadLoaderError) {
|
|
54
|
+
console.error(`Error [${error.code}]: ${error.message}`);
|
|
55
|
+
console.log(`Suggestion: ${error.suggestion}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Error Codes
|
|
61
|
+
|
|
62
|
+
| Code | Description | Suggestion |
|
|
63
|
+
|------|-------------|------------|
|
|
64
|
+
| `SQUAD_NOT_FOUND` | Squad directory not found | Create squad with: @squad-creator *create-squad {name} |
|
|
65
|
+
| `MANIFEST_NOT_FOUND` | No manifest file in squad | Create squad.yaml in squad directory |
|
|
66
|
+
| `YAML_PARSE_ERROR` | Invalid YAML syntax | Check YAML syntax - use a YAML linter |
|
|
67
|
+
| `PERMISSION_DENIED` | File permission error | Check file permissions: chmod 644 {path} |
|
|
68
|
+
|
|
69
|
+
## Manifest Files
|
|
70
|
+
|
|
71
|
+
The loader supports two manifest formats:
|
|
72
|
+
|
|
73
|
+
1. **`squad.yaml`** (preferred) - New standard format
|
|
74
|
+
2. **`config.yaml`** (deprecated) - Legacy format with console warning
|
|
75
|
+
|
|
76
|
+
## Integration with squad-creator Agent
|
|
77
|
+
|
|
78
|
+
This module is used by squad-creator agent tasks:
|
|
79
|
+
|
|
80
|
+
- `*create-squad` - Uses loader to check for conflicts
|
|
81
|
+
- `*validate-squad` - Uses loader to load and validate manifest
|
|
82
|
+
- `*list-squads` - Uses loader to enumerate local squads
|
|
83
|
+
|
|
84
|
+
## Related Stories
|
|
85
|
+
|
|
86
|
+
- **SQS-2**: Squad Loader Utility (this module)
|
|
87
|
+
- **SQS-3**: Squad Validator + Schema
|
|
88
|
+
- **SQS-4**: Squad Creator Agent + Tasks
|
|
89
|
+
|
|
90
|
+
## Dependencies
|
|
91
|
+
|
|
92
|
+
- `js-yaml` - YAML parsing (project dependency)
|
|
93
|
+
- `fs/promises` - File system operations (Node.js built-in)
|
|
94
|
+
- `path` - Path manipulation (Node.js built-in)
|
|
95
|
+
|
|
96
|
+
## Testing
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# Run squad-loader tests
|
|
100
|
+
npm test -- tests/unit/squad/squad-loader.test.js
|
|
101
|
+
|
|
102
|
+
# Run with coverage
|
|
103
|
+
npm test -- tests/unit/squad/squad-loader.test.js --coverage --collectCoverageFrom=".aios-core/development/scripts/squad/*.js"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Coverage:** 94.5% statements (target: 80%+)
|
|
107
|
+
|
|
108
|
+
## Version History
|
|
109
|
+
|
|
110
|
+
| Version | Date | Description |
|
|
111
|
+
|---------|------|-------------|
|
|
112
|
+
| 1.0.0 | 2025-12-18 | Initial implementation (Story SQS-2) |
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Squad Scripts Module
|
|
3
|
+
*
|
|
4
|
+
* Central exports for squad-related utilities used by the squad-creator agent.
|
|
5
|
+
*
|
|
6
|
+
* @module squad
|
|
7
|
+
* @see {@link ./squad-loader.js} - Load and resolve squad manifests
|
|
8
|
+
* @see {@link ./squad-validator.js} - Validate squad structure (SQS-3)
|
|
9
|
+
* @see {@link ./squad-generator.js} - Generate new squads (SQS-4)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const {
|
|
13
|
+
SquadLoader,
|
|
14
|
+
SquadLoaderError,
|
|
15
|
+
MANIFEST_FILES,
|
|
16
|
+
DEFAULT_SQUADS_PATH,
|
|
17
|
+
ErrorCodes,
|
|
18
|
+
} = require('./squad-loader');
|
|
19
|
+
|
|
20
|
+
const {
|
|
21
|
+
SquadValidator,
|
|
22
|
+
ValidationErrorCodes,
|
|
23
|
+
TASK_REQUIRED_FIELDS,
|
|
24
|
+
} = require('./squad-validator');
|
|
25
|
+
|
|
26
|
+
module.exports = {
|
|
27
|
+
// Squad Loader (SQS-2)
|
|
28
|
+
SquadLoader,
|
|
29
|
+
SquadLoaderError,
|
|
30
|
+
MANIFEST_FILES,
|
|
31
|
+
DEFAULT_SQUADS_PATH,
|
|
32
|
+
ErrorCodes,
|
|
33
|
+
|
|
34
|
+
// Squad Validator (SQS-3)
|
|
35
|
+
SquadValidator,
|
|
36
|
+
ValidationErrorCodes,
|
|
37
|
+
TASK_REQUIRED_FIELDS,
|
|
38
|
+
|
|
39
|
+
// Squad Generator (SQS-4) - TODO: Implement in Story SQS-4
|
|
40
|
+
// SquadGenerator,
|
|
41
|
+
};
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Squad Loader Utility
|
|
3
|
+
*
|
|
4
|
+
* Utilities for loading and resolving squad manifests from local directories.
|
|
5
|
+
* Used by squad-creator agent tasks.
|
|
6
|
+
*
|
|
7
|
+
* @module squad-loader
|
|
8
|
+
* @version 1.0.0
|
|
9
|
+
* @see Story SQS-2: Squad Loader Utility
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const fs = require('fs').promises;
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const yaml = require('js-yaml');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Supported manifest file names in order of preference
|
|
18
|
+
* @constant {string[]}
|
|
19
|
+
*/
|
|
20
|
+
const MANIFEST_FILES = ['squad.yaml', 'config.yaml'];
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Default path for squads directory
|
|
24
|
+
* @constant {string}
|
|
25
|
+
*/
|
|
26
|
+
const DEFAULT_SQUADS_PATH = './squads';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Error codes for SquadLoaderError
|
|
30
|
+
* @enum {string}
|
|
31
|
+
*/
|
|
32
|
+
const ErrorCodes = {
|
|
33
|
+
SQUAD_NOT_FOUND: 'SQUAD_NOT_FOUND',
|
|
34
|
+
MANIFEST_NOT_FOUND: 'MANIFEST_NOT_FOUND',
|
|
35
|
+
YAML_PARSE_ERROR: 'YAML_PARSE_ERROR',
|
|
36
|
+
PERMISSION_DENIED: 'PERMISSION_DENIED',
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Suggestions for each error code
|
|
41
|
+
* @constant {Object.<string, string|Function>}
|
|
42
|
+
*/
|
|
43
|
+
const ErrorSuggestions = {
|
|
44
|
+
[ErrorCodes.SQUAD_NOT_FOUND]: (squadName) =>
|
|
45
|
+
`Create squad with: @squad-creator *create-squad ${squadName}`,
|
|
46
|
+
[ErrorCodes.MANIFEST_NOT_FOUND]: () =>
|
|
47
|
+
'Create squad.yaml in squad directory',
|
|
48
|
+
[ErrorCodes.YAML_PARSE_ERROR]: () =>
|
|
49
|
+
'Check YAML syntax - use a YAML linter',
|
|
50
|
+
[ErrorCodes.PERMISSION_DENIED]: (filePath) =>
|
|
51
|
+
`Check file permissions: chmod 644 ${filePath}`,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Custom error class for Squad Loader operations
|
|
56
|
+
* @extends Error
|
|
57
|
+
*/
|
|
58
|
+
class SquadLoaderError extends Error {
|
|
59
|
+
/**
|
|
60
|
+
* Create a SquadLoaderError
|
|
61
|
+
* @param {string} code - Error code from ErrorCodes enum
|
|
62
|
+
* @param {string} message - Human-readable error message
|
|
63
|
+
* @param {string} [suggestion] - Suggested fix for the error
|
|
64
|
+
* @param {string} [filePath] - Path to the problematic file/directory
|
|
65
|
+
*/
|
|
66
|
+
constructor(code, message, suggestion, filePath) {
|
|
67
|
+
super(message);
|
|
68
|
+
this.name = 'SquadLoaderError';
|
|
69
|
+
this.code = code;
|
|
70
|
+
this.suggestion = suggestion || '';
|
|
71
|
+
this.filePath = filePath || '';
|
|
72
|
+
|
|
73
|
+
// Maintains proper stack trace for where error was thrown (V8 engines)
|
|
74
|
+
if (Error.captureStackTrace) {
|
|
75
|
+
Error.captureStackTrace(this, SquadLoaderError);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Create error for squad not found
|
|
81
|
+
* @param {string} squadName - Name of the squad
|
|
82
|
+
* @param {string} squadsPath - Path searched
|
|
83
|
+
* @returns {SquadLoaderError}
|
|
84
|
+
*/
|
|
85
|
+
static squadNotFound(squadName, squadsPath) {
|
|
86
|
+
const filePath = path.join(squadsPath, squadName);
|
|
87
|
+
return new SquadLoaderError(
|
|
88
|
+
ErrorCodes.SQUAD_NOT_FOUND,
|
|
89
|
+
`Squad "${squadName}" not found in ${squadsPath}/`,
|
|
90
|
+
ErrorSuggestions[ErrorCodes.SQUAD_NOT_FOUND](squadName),
|
|
91
|
+
filePath,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Create error for manifest not found
|
|
97
|
+
* @param {string} squadPath - Path to squad directory
|
|
98
|
+
* @returns {SquadLoaderError}
|
|
99
|
+
*/
|
|
100
|
+
static manifestNotFound(squadPath) {
|
|
101
|
+
return new SquadLoaderError(
|
|
102
|
+
ErrorCodes.MANIFEST_NOT_FOUND,
|
|
103
|
+
`No manifest found in ${squadPath}/ (expected squad.yaml or config.yaml)`,
|
|
104
|
+
ErrorSuggestions[ErrorCodes.MANIFEST_NOT_FOUND](),
|
|
105
|
+
squadPath,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Create error for YAML parse failure
|
|
111
|
+
* @param {string} filePath - Path to the YAML file
|
|
112
|
+
* @param {Error} parseError - Original YAML parse error
|
|
113
|
+
* @returns {SquadLoaderError}
|
|
114
|
+
*/
|
|
115
|
+
static yamlParseError(filePath, parseError) {
|
|
116
|
+
return new SquadLoaderError(
|
|
117
|
+
ErrorCodes.YAML_PARSE_ERROR,
|
|
118
|
+
`Failed to parse YAML in ${filePath}: ${parseError.message}`,
|
|
119
|
+
ErrorSuggestions[ErrorCodes.YAML_PARSE_ERROR](),
|
|
120
|
+
filePath,
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Create error for permission denied
|
|
126
|
+
* @param {string} filePath - Path to the file/directory
|
|
127
|
+
* @param {Error} originalError - Original file system error
|
|
128
|
+
* @returns {SquadLoaderError}
|
|
129
|
+
*/
|
|
130
|
+
static permissionDenied(filePath, originalError) {
|
|
131
|
+
return new SquadLoaderError(
|
|
132
|
+
ErrorCodes.PERMISSION_DENIED,
|
|
133
|
+
`Permission denied accessing ${filePath}: ${originalError.message}`,
|
|
134
|
+
ErrorSuggestions[ErrorCodes.PERMISSION_DENIED](filePath),
|
|
135
|
+
filePath,
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Returns formatted error string
|
|
141
|
+
* @returns {string}
|
|
142
|
+
*/
|
|
143
|
+
toString() {
|
|
144
|
+
let str = `[${this.code}] ${this.message}`;
|
|
145
|
+
if (this.suggestion) {
|
|
146
|
+
str += `\n Suggestion: ${this.suggestion}`;
|
|
147
|
+
}
|
|
148
|
+
return str;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Squad Loader class for loading and resolving squad manifests
|
|
154
|
+
*/
|
|
155
|
+
class SquadLoader {
|
|
156
|
+
/**
|
|
157
|
+
* Create a SquadLoader instance
|
|
158
|
+
* @param {Object} [options={}] - Configuration options
|
|
159
|
+
* @param {string} [options.squadsPath='./squads'] - Path to squads directory
|
|
160
|
+
* @param {boolean} [options.verbose=false] - Enable verbose logging
|
|
161
|
+
*/
|
|
162
|
+
constructor(options = {}) {
|
|
163
|
+
this.squadsPath = options.squadsPath || DEFAULT_SQUADS_PATH;
|
|
164
|
+
this.verbose = options.verbose || false;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Log message if verbose mode is enabled
|
|
169
|
+
* @private
|
|
170
|
+
* @param {string} message - Message to log
|
|
171
|
+
*/
|
|
172
|
+
_log(message) {
|
|
173
|
+
if (this.verbose) {
|
|
174
|
+
console.log(`[SquadLoader] ${message}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Resolve squad path by name
|
|
180
|
+
*
|
|
181
|
+
* Finds a squad directory and its manifest file.
|
|
182
|
+
*
|
|
183
|
+
* @param {string} squadName - Name of the squad (kebab-case)
|
|
184
|
+
* @returns {Promise<{path: string, manifestPath: string}>} Resolved paths
|
|
185
|
+
* @throws {SquadLoaderError} SQUAD_NOT_FOUND if squad directory doesn't exist
|
|
186
|
+
* @throws {SquadLoaderError} MANIFEST_NOT_FOUND if no manifest file found
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* const loader = new SquadLoader();
|
|
190
|
+
* const { path, manifestPath } = await loader.resolve('etl-squad');
|
|
191
|
+
* // { path: './squads/etl-squad', manifestPath: './squads/etl-squad/squad.yaml' }
|
|
192
|
+
*/
|
|
193
|
+
async resolve(squadName) {
|
|
194
|
+
this._log(`Resolving squad: ${squadName}`);
|
|
195
|
+
const squadPath = path.join(this.squadsPath, squadName);
|
|
196
|
+
|
|
197
|
+
// Check if squad directory exists
|
|
198
|
+
const exists = await this._pathExists(squadPath);
|
|
199
|
+
if (!exists) {
|
|
200
|
+
throw SquadLoaderError.squadNotFound(squadName, this.squadsPath);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Find manifest file
|
|
204
|
+
const manifestPath = await this._findManifest(squadPath);
|
|
205
|
+
if (!manifestPath) {
|
|
206
|
+
throw SquadLoaderError.manifestNotFound(squadPath);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
this._log(`Resolved: ${squadPath} -> ${manifestPath}`);
|
|
210
|
+
return { path: squadPath, manifestPath };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Load and parse squad manifest
|
|
215
|
+
*
|
|
216
|
+
* Loads the manifest file from a squad directory and parses it.
|
|
217
|
+
* Shows deprecation warning for config.yaml files.
|
|
218
|
+
*
|
|
219
|
+
* @param {string} squadPath - Path to squad directory
|
|
220
|
+
* @returns {Promise<Object>} Parsed manifest data
|
|
221
|
+
* @throws {SquadLoaderError} MANIFEST_NOT_FOUND if no manifest file found
|
|
222
|
+
* @throws {SquadLoaderError} YAML_PARSE_ERROR if YAML parsing fails
|
|
223
|
+
* @throws {SquadLoaderError} PERMISSION_DENIED if file cannot be read
|
|
224
|
+
*
|
|
225
|
+
* @example
|
|
226
|
+
* const loader = new SquadLoader();
|
|
227
|
+
* const manifest = await loader.loadManifest('./squads/etl-squad');
|
|
228
|
+
* console.log(manifest.name); // 'etl-squad'
|
|
229
|
+
*/
|
|
230
|
+
async loadManifest(squadPath) {
|
|
231
|
+
this._log(`Loading manifest from: ${squadPath}`);
|
|
232
|
+
|
|
233
|
+
const manifestPath = await this._findManifest(squadPath);
|
|
234
|
+
if (!manifestPath) {
|
|
235
|
+
throw SquadLoaderError.manifestNotFound(squadPath);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Deprecation warning for config.yaml
|
|
239
|
+
const manifestFilename = path.basename(manifestPath);
|
|
240
|
+
if (manifestFilename === 'config.yaml') {
|
|
241
|
+
console.warn(
|
|
242
|
+
`\u26a0\ufe0f DEPRECATED: ${manifestPath} uses legacy format. Rename to squad.yaml`,
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
try {
|
|
247
|
+
const content = await fs.readFile(manifestPath, 'utf-8');
|
|
248
|
+
const parsed = yaml.load(content);
|
|
249
|
+
this._log(`Manifest loaded successfully: ${manifestPath}`);
|
|
250
|
+
return parsed;
|
|
251
|
+
} catch (error) {
|
|
252
|
+
if (error.code === 'EACCES' || error.code === 'EPERM') {
|
|
253
|
+
throw SquadLoaderError.permissionDenied(manifestPath, error);
|
|
254
|
+
}
|
|
255
|
+
if (error.name === 'YAMLException') {
|
|
256
|
+
throw SquadLoaderError.yamlParseError(manifestPath, error);
|
|
257
|
+
}
|
|
258
|
+
throw error;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* List all local squads in project
|
|
264
|
+
*
|
|
265
|
+
* Scans the squads directory for valid squad directories
|
|
266
|
+
* (directories containing a manifest file).
|
|
267
|
+
*
|
|
268
|
+
* @returns {Promise<Array<{name: string, path: string, manifestPath: string}>>}
|
|
269
|
+
* Array of squad info objects
|
|
270
|
+
*
|
|
271
|
+
* @example
|
|
272
|
+
* const loader = new SquadLoader();
|
|
273
|
+
* const squads = await loader.listLocal();
|
|
274
|
+
* // [
|
|
275
|
+
* // { name: 'etl-squad', path: './squads/etl-squad', manifestPath: '...' },
|
|
276
|
+
* // { name: 'creator-squad', path: './squads/creator-squad', manifestPath: '...' }
|
|
277
|
+
* // ]
|
|
278
|
+
*/
|
|
279
|
+
async listLocal() {
|
|
280
|
+
this._log(`Listing squads in: ${this.squadsPath}`);
|
|
281
|
+
|
|
282
|
+
const exists = await this._pathExists(this.squadsPath);
|
|
283
|
+
if (!exists) {
|
|
284
|
+
this._log('Squads directory does not exist, returning empty array');
|
|
285
|
+
return [];
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
let entries;
|
|
289
|
+
try {
|
|
290
|
+
entries = await fs.readdir(this.squadsPath, { withFileTypes: true });
|
|
291
|
+
} catch (error) {
|
|
292
|
+
if (error.code === 'EACCES' || error.code === 'EPERM') {
|
|
293
|
+
throw SquadLoaderError.permissionDenied(this.squadsPath, error);
|
|
294
|
+
}
|
|
295
|
+
throw error;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const squads = [];
|
|
299
|
+
|
|
300
|
+
for (const entry of entries) {
|
|
301
|
+
if (entry.isDirectory()) {
|
|
302
|
+
const squadPath = path.join(this.squadsPath, entry.name);
|
|
303
|
+
const manifestPath = await this._findManifest(squadPath);
|
|
304
|
+
if (manifestPath) {
|
|
305
|
+
squads.push({
|
|
306
|
+
name: entry.name,
|
|
307
|
+
path: squadPath,
|
|
308
|
+
manifestPath,
|
|
309
|
+
});
|
|
310
|
+
this._log(`Found squad: ${entry.name}`);
|
|
311
|
+
} else {
|
|
312
|
+
this._log(`Skipped directory (no manifest): ${entry.name}`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
this._log(`Found ${squads.length} squad(s)`);
|
|
318
|
+
return squads;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Find manifest file in squad directory
|
|
323
|
+
* @private
|
|
324
|
+
* @param {string} squadPath - Path to squad directory
|
|
325
|
+
* @returns {Promise<string|null>} Path to manifest or null if not found
|
|
326
|
+
*/
|
|
327
|
+
async _findManifest(squadPath) {
|
|
328
|
+
for (const filename of MANIFEST_FILES) {
|
|
329
|
+
const manifestPath = path.join(squadPath, filename);
|
|
330
|
+
if (await this._pathExists(manifestPath)) {
|
|
331
|
+
return manifestPath;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Check if path exists
|
|
339
|
+
* @private
|
|
340
|
+
* @param {string} filePath - Path to check
|
|
341
|
+
* @returns {Promise<boolean>} True if path exists
|
|
342
|
+
*/
|
|
343
|
+
async _pathExists(filePath) {
|
|
344
|
+
try {
|
|
345
|
+
await fs.access(filePath);
|
|
346
|
+
return true;
|
|
347
|
+
} catch {
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
module.exports = {
|
|
354
|
+
SquadLoader,
|
|
355
|
+
SquadLoaderError,
|
|
356
|
+
MANIFEST_FILES,
|
|
357
|
+
DEFAULT_SQUADS_PATH,
|
|
358
|
+
ErrorCodes,
|
|
359
|
+
};
|