liteagents 2.4.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/CHANGELOG.md +441 -0
- package/LICENSE +21 -0
- package/README.md +179 -0
- package/cli.js +230 -0
- package/docs/.gitkeep +1 -0
- package/docs/CONTRIBUTING.md +739 -0
- package/docs/DUAL_PUBLISH_SUMMARY.md +177 -0
- package/docs/ERROR_HANDLING_IMPLEMENTATION.md +327 -0
- package/docs/GITHUB_PACKAGES.md +181 -0
- package/docs/GITHUB_SETUP.md +158 -0
- package/docs/INSTALLATION_DEMO.md +691 -0
- package/docs/INSTALLATION_LOCATIONS.md +299 -0
- package/docs/INSTALLER_GUIDE.md +1586 -0
- package/docs/INTEGRATION_ISSUES_9.1.md +341 -0
- package/docs/KNOWLEDGE_BASE.md +727 -0
- package/docs/MIGRATION.md +384 -0
- package/docs/PACKAGE_BASELINE.md +557 -0
- package/docs/PACKAGE_VALIDATION_REPORT.md +427 -0
- package/docs/PASS_INTEGRATION.md +307 -0
- package/docs/PASS_QUICK_START.md +150 -0
- package/docs/PRIVACY.md +203 -0
- package/docs/PUBLISHING.md +494 -0
- package/docs/QUICK-START.md +318 -0
- package/docs/RELEASE_NOTES_1.2.0.md +323 -0
- package/docs/SECURITY.md +317 -0
- package/docs/SILENT_MODE_GUIDE.md +526 -0
- package/docs/SKILLS_CONVERSION.md +154 -0
- package/docs/TESTING.md +582 -0
- package/docs/TEST_COVERAGE.md +347 -0
- package/docs/TROUBLESHOOTING.md +788 -0
- package/docs/UPDATED_VARIANT_CONFIGURATION.md +274 -0
- package/docs/VARIANT_CONFIGURATION.md +440 -0
- package/installer/cli.js +761 -0
- package/installer/installation-engine.js +1536 -0
- package/installer/package-manager.js +640 -0
- package/installer/path-manager.js +427 -0
- package/installer/report-template.js +298 -0
- package/installer/verification-system.js +274 -0
- package/package.json +83 -0
- package/packages/ampcode/AGENT.md +58 -0
- package/packages/ampcode/README.md +17 -0
- package/packages/ampcode/agents/1-create-prd.md +175 -0
- package/packages/ampcode/agents/2-generate-tasks.md +190 -0
- package/packages/ampcode/agents/3-process-task-list.md +225 -0
- package/packages/ampcode/agents/code-developer.md +198 -0
- package/packages/ampcode/agents/context-builder.md +142 -0
- package/packages/ampcode/agents/feature-planner.md +199 -0
- package/packages/ampcode/agents/market-researcher.md +89 -0
- package/packages/ampcode/agents/orchestrator.md +116 -0
- package/packages/ampcode/agents/quality-assurance.md +115 -0
- package/packages/ampcode/agents/system-architect.md +135 -0
- package/packages/ampcode/agents/ui-designer.md +184 -0
- package/packages/ampcode/commands/brainstorming.md +56 -0
- package/packages/ampcode/commands/code-review.md +107 -0
- package/packages/ampcode/commands/condition-based-waiting/example.ts +158 -0
- package/packages/ampcode/commands/condition-based-waiting.md +122 -0
- package/packages/ampcode/commands/debug.md +20 -0
- package/packages/ampcode/commands/docs-builder/templates.md +572 -0
- package/packages/ampcode/commands/docs-builder.md +106 -0
- package/packages/ampcode/commands/explain.md +18 -0
- package/packages/ampcode/commands/git-commit.md +14 -0
- package/packages/ampcode/commands/optimize.md +20 -0
- package/packages/ampcode/commands/refactor.md +21 -0
- package/packages/ampcode/commands/review.md +18 -0
- package/packages/ampcode/commands/root-cause-tracing/find-polluter.sh +63 -0
- package/packages/ampcode/commands/root-cause-tracing.md +176 -0
- package/packages/ampcode/commands/security.md +21 -0
- package/packages/ampcode/commands/ship.md +18 -0
- package/packages/ampcode/commands/skill-creator/scripts/init_skill.py +303 -0
- package/packages/ampcode/commands/skill-creator/scripts/package_skill.py +110 -0
- package/packages/ampcode/commands/skill-creator/scripts/quick_validate.py +65 -0
- package/packages/ampcode/commands/skill-creator.md +211 -0
- package/packages/ampcode/commands/stash.md +45 -0
- package/packages/ampcode/commands/systematic-debugging.md +297 -0
- package/packages/ampcode/commands/test-driven-development.md +390 -0
- package/packages/ampcode/commands/test-generate.md +18 -0
- package/packages/ampcode/commands/testing-anti-patterns.md +304 -0
- package/packages/ampcode/commands/verification-before-completion.md +152 -0
- package/packages/ampcode/settings.json +13 -0
- package/packages/ampcode/variants.json +8 -0
- package/packages/claude/CLAUDE.md +58 -0
- package/packages/claude/README.md +23 -0
- package/packages/claude/agents/1-create-prd.md +175 -0
- package/packages/claude/agents/2-generate-tasks.md +190 -0
- package/packages/claude/agents/3-process-task-list.md +225 -0
- package/packages/claude/agents/code-developer.md +198 -0
- package/packages/claude/agents/context-builder.md +142 -0
- package/packages/claude/agents/feature-planner.md +199 -0
- package/packages/claude/agents/market-researcher.md +89 -0
- package/packages/claude/agents/orchestrator.md +117 -0
- package/packages/claude/agents/quality-assurance.md +115 -0
- package/packages/claude/agents/system-architect.md +135 -0
- package/packages/claude/agents/ui-designer.md +184 -0
- package/packages/claude/commands/debug.md +20 -0
- package/packages/claude/commands/explain.md +18 -0
- package/packages/claude/commands/git-commit.md +14 -0
- package/packages/claude/commands/optimize.md +20 -0
- package/packages/claude/commands/refactor.md +21 -0
- package/packages/claude/commands/review.md +18 -0
- package/packages/claude/commands/security.md +21 -0
- package/packages/claude/commands/ship.md +18 -0
- package/packages/claude/commands/stash.md +45 -0
- package/packages/claude/commands/test-generate.md +18 -0
- package/packages/claude/skills/brainstorming/SKILL.md +56 -0
- package/packages/claude/skills/code-review/SKILL.md +107 -0
- package/packages/claude/skills/code-review/code-reviewer.md +146 -0
- package/packages/claude/skills/condition-based-waiting/SKILL.md +122 -0
- package/packages/claude/skills/condition-based-waiting/example.ts +158 -0
- package/packages/claude/skills/docs-builder/SKILL.md +106 -0
- package/packages/claude/skills/docs-builder/references/templates.md +572 -0
- package/packages/claude/skills/root-cause-tracing/SKILL.md +176 -0
- package/packages/claude/skills/root-cause-tracing/find-polluter.sh +63 -0
- package/packages/claude/skills/skill-creator/LICENSE.txt +202 -0
- package/packages/claude/skills/skill-creator/SKILL.md +211 -0
- package/packages/claude/skills/skill-creator/scripts/init_skill.py +303 -0
- package/packages/claude/skills/skill-creator/scripts/package_skill.py +110 -0
- package/packages/claude/skills/skill-creator/scripts/quick_validate.py +65 -0
- package/packages/claude/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/packages/claude/skills/systematic-debugging/SKILL.md +296 -0
- package/packages/claude/skills/systematic-debugging/test-academic.md +14 -0
- package/packages/claude/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/packages/claude/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/packages/claude/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/packages/claude/skills/test-driven-development/SKILL.md +392 -0
- package/packages/claude/skills/testing-anti-patterns/SKILL.md +304 -0
- package/packages/claude/skills/verification-before-completion/SKILL.md +152 -0
- package/packages/claude/variants.json +9 -0
- package/packages/droid/AGENTS.md +52 -0
- package/packages/droid/README.md +17 -0
- package/packages/droid/change_settings.json +61 -0
- package/packages/droid/commands/brainstorming.md +56 -0
- package/packages/droid/commands/code-review.md +107 -0
- package/packages/droid/commands/condition-based-waiting/example.ts +158 -0
- package/packages/droid/commands/condition-based-waiting.md +122 -0
- package/packages/droid/commands/debug.md +20 -0
- package/packages/droid/commands/docs-builder/templates.md +572 -0
- package/packages/droid/commands/docs-builder.md +106 -0
- package/packages/droid/commands/explain.md +18 -0
- package/packages/droid/commands/git-commit.md +14 -0
- package/packages/droid/commands/optimize.md +20 -0
- package/packages/droid/commands/refactor.md +21 -0
- package/packages/droid/commands/review.md +18 -0
- package/packages/droid/commands/root-cause-tracing/find-polluter.sh +63 -0
- package/packages/droid/commands/root-cause-tracing.md +176 -0
- package/packages/droid/commands/security.md +21 -0
- package/packages/droid/commands/ship.md +18 -0
- package/packages/droid/commands/skill-creator/scripts/init_skill.py +303 -0
- package/packages/droid/commands/skill-creator/scripts/package_skill.py +110 -0
- package/packages/droid/commands/skill-creator/scripts/quick_validate.py +65 -0
- package/packages/droid/commands/skill-creator.md +211 -0
- package/packages/droid/commands/stash.md +45 -0
- package/packages/droid/commands/systematic-debugging.md +297 -0
- package/packages/droid/commands/test-driven-development.md +390 -0
- package/packages/droid/commands/test-generate.md +18 -0
- package/packages/droid/commands/testing-anti-patterns.md +304 -0
- package/packages/droid/commands/verification-before-completion.md +152 -0
- package/packages/droid/droids/1-create-prd.md +170 -0
- package/packages/droid/droids/2-generate-tasks.md +190 -0
- package/packages/droid/droids/3-process-task-list.md +225 -0
- package/packages/droid/droids/code-developer.md +198 -0
- package/packages/droid/droids/context-builder.md +142 -0
- package/packages/droid/droids/feature-planner.md +199 -0
- package/packages/droid/droids/market-researcher.md +89 -0
- package/packages/droid/droids/orchestrator.md +116 -0
- package/packages/droid/droids/quality-assurance.md +115 -0
- package/packages/droid/droids/system-architect.md +135 -0
- package/packages/droid/droids/ui-designer.md +184 -0
- package/packages/droid/variants.json +8 -0
- package/packages/opencode/AGENTS.md +52 -0
- package/packages/opencode/README.md +17 -0
- package/packages/opencode/agent/1-create-prd.md +179 -0
- package/packages/opencode/agent/2-generate-tasks.md +194 -0
- package/packages/opencode/agent/3-process-task-list.md +229 -0
- package/packages/opencode/agent/code-developer.md +202 -0
- package/packages/opencode/agent/context-builder.md +146 -0
- package/packages/opencode/agent/feature-planner.md +203 -0
- package/packages/opencode/agent/market-researcher.md +93 -0
- package/packages/opencode/agent/orchestrator.md +120 -0
- package/packages/opencode/agent/quality-assurance.md +119 -0
- package/packages/opencode/agent/system-architect.md +139 -0
- package/packages/opencode/agent/ui-designer.md +188 -0
- package/packages/opencode/command/brainstorming.md +56 -0
- package/packages/opencode/command/code-review.md +107 -0
- package/packages/opencode/command/condition-based-waiting/example.ts +158 -0
- package/packages/opencode/command/condition-based-waiting.md +122 -0
- package/packages/opencode/command/debug.md +20 -0
- package/packages/opencode/command/docs-builder/templates.md +572 -0
- package/packages/opencode/command/docs-builder.md +106 -0
- package/packages/opencode/command/explain.md +18 -0
- package/packages/opencode/command/git-commit.md +14 -0
- package/packages/opencode/command/optimize.md +20 -0
- package/packages/opencode/command/refactor.md +21 -0
- package/packages/opencode/command/review.md +18 -0
- package/packages/opencode/command/root-cause-tracing/find-polluter.sh +63 -0
- package/packages/opencode/command/root-cause-tracing.md +176 -0
- package/packages/opencode/command/security.md +21 -0
- package/packages/opencode/command/ship.md +18 -0
- package/packages/opencode/command/skill-creator/scripts/init_skill.py +303 -0
- package/packages/opencode/command/skill-creator/scripts/package_skill.py +110 -0
- package/packages/opencode/command/skill-creator/scripts/quick_validate.py +65 -0
- package/packages/opencode/command/skill-creator.md +211 -0
- package/packages/opencode/command/stash.md +45 -0
- package/packages/opencode/command/systematic-debugging.md +297 -0
- package/packages/opencode/command/test-driven-development.md +390 -0
- package/packages/opencode/command/test-generate.md +18 -0
- package/packages/opencode/command/testing-anti-patterns.md +304 -0
- package/packages/opencode/command/verification-before-completion.md +152 -0
- package/packages/opencode/opencode.jsonc +201 -0
- package/packages/opencode/variants.json +8 -0
- package/packages/subagentic-manual.md +349 -0
- package/postinstall.js +21 -0
- package/tools/ampcode/manifest-template.json +14 -0
- package/tools/claude/manifest-template.json +14 -0
- package/tools/droid/manifest-template.json +14 -0
- package/tools/opencode/manifest-template.json +14 -0
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path Manager for Agentic Kit Installer
|
|
3
|
+
*
|
|
4
|
+
* Handles path validation, permissions, and tool-specific path management
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const os = require('os');
|
|
10
|
+
|
|
11
|
+
class PathManager {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.homeDir = os.homedir();
|
|
14
|
+
this.defaultPaths = {
|
|
15
|
+
claude: path.join(this.homeDir, '.claude'),
|
|
16
|
+
opencode: path.join(this.homeDir, '.config', 'opencode'),
|
|
17
|
+
ampcode: path.join(this.homeDir, '.amp'),
|
|
18
|
+
droid: path.join(this.homeDir, '.factory')
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Expand user home path (~) to full path
|
|
24
|
+
* Includes security checks for path traversal
|
|
25
|
+
*/
|
|
26
|
+
expandPath(pathStr) {
|
|
27
|
+
if (pathStr.startsWith('~')) {
|
|
28
|
+
return path.join(this.homeDir, pathStr.slice(1));
|
|
29
|
+
}
|
|
30
|
+
return pathStr;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Sanitize and validate path for security
|
|
35
|
+
* Prevents path traversal attacks and validates path safety
|
|
36
|
+
*
|
|
37
|
+
* @param {string} pathStr - Path to sanitize
|
|
38
|
+
* @returns {Object} Result with sanitized path or error
|
|
39
|
+
*/
|
|
40
|
+
sanitizePath(pathStr) {
|
|
41
|
+
try {
|
|
42
|
+
// Expand tilde first
|
|
43
|
+
let sanitized = this.expandPath(pathStr);
|
|
44
|
+
|
|
45
|
+
// Resolve to absolute path (normalizes .. and .)
|
|
46
|
+
sanitized = path.resolve(sanitized);
|
|
47
|
+
|
|
48
|
+
// Check for null bytes (security risk)
|
|
49
|
+
if (sanitized.includes('\0')) {
|
|
50
|
+
return {
|
|
51
|
+
valid: false,
|
|
52
|
+
error: 'Path contains null bytes (security risk)'
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Ensure path is within user's home directory or /tmp for safety
|
|
57
|
+
// This prevents writing to system directories
|
|
58
|
+
const homeDir = this.homeDir;
|
|
59
|
+
const tmpDir = os.tmpdir();
|
|
60
|
+
|
|
61
|
+
const isInHome = sanitized.startsWith(homeDir);
|
|
62
|
+
const isInTmp = sanitized.startsWith(tmpDir);
|
|
63
|
+
|
|
64
|
+
if (!isInHome && !isInTmp) {
|
|
65
|
+
return {
|
|
66
|
+
valid: false,
|
|
67
|
+
error: `Path must be within home directory (${homeDir}) for security`
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Check for suspicious patterns
|
|
72
|
+
const suspiciousPatterns = [
|
|
73
|
+
'/etc/', '/var/', '/usr/', '/bin/', '/sbin/',
|
|
74
|
+
'/root/', '/boot/', '/dev/', '/proc/', '/sys/'
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
for (const pattern of suspiciousPatterns) {
|
|
78
|
+
if (sanitized.includes(pattern)) {
|
|
79
|
+
return {
|
|
80
|
+
valid: false,
|
|
81
|
+
error: `Path contains suspicious directory: ${pattern}`
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
valid: true,
|
|
88
|
+
path: sanitized
|
|
89
|
+
};
|
|
90
|
+
} catch (error) {
|
|
91
|
+
return {
|
|
92
|
+
valid: false,
|
|
93
|
+
error: `Path sanitization failed: ${error.message}`
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Validate if a path is writable
|
|
100
|
+
* Includes security checks via sanitizePath
|
|
101
|
+
*/
|
|
102
|
+
async validatePath(pathStr) {
|
|
103
|
+
// First, sanitize the path for security
|
|
104
|
+
const sanitizeResult = this.sanitizePath(pathStr);
|
|
105
|
+
if (!sanitizeResult.valid) {
|
|
106
|
+
return {
|
|
107
|
+
valid: false,
|
|
108
|
+
path: pathStr,
|
|
109
|
+
error: sanitizeResult.error
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const fullPath = sanitizeResult.path;
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
// Resolve symlinks to real path
|
|
117
|
+
let realPath;
|
|
118
|
+
try {
|
|
119
|
+
realPath = await fs.promises.realpath(fullPath);
|
|
120
|
+
} catch (error) {
|
|
121
|
+
// Path doesn't exist yet, use parent directory
|
|
122
|
+
const parentDir = path.dirname(fullPath);
|
|
123
|
+
try {
|
|
124
|
+
const parentReal = await fs.promises.realpath(parentDir);
|
|
125
|
+
realPath = path.join(parentReal, path.basename(fullPath));
|
|
126
|
+
} catch (parentError) {
|
|
127
|
+
// Parent doesn't exist either, will be created
|
|
128
|
+
realPath = fullPath;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Verify real path is still safe after symlink resolution
|
|
133
|
+
const realPathCheck = this.sanitizePath(realPath);
|
|
134
|
+
if (!realPathCheck.valid) {
|
|
135
|
+
return {
|
|
136
|
+
valid: false,
|
|
137
|
+
path: fullPath,
|
|
138
|
+
error: `Resolved path is unsafe: ${realPathCheck.error}`
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Check if parent directory exists and is writable
|
|
143
|
+
const parentDir = path.dirname(fullPath);
|
|
144
|
+
await fs.promises.access(parentDir, fs.constants.W_OK);
|
|
145
|
+
|
|
146
|
+
// Try to create the directory if it doesn't exist
|
|
147
|
+
await fs.promises.mkdir(fullPath, { recursive: true });
|
|
148
|
+
|
|
149
|
+
// Test write access
|
|
150
|
+
const testFile = path.join(fullPath, '.install-test');
|
|
151
|
+
await fs.promises.writeFile(testFile, 'test', { mode: 0o600 });
|
|
152
|
+
await fs.promises.unlink(testFile);
|
|
153
|
+
|
|
154
|
+
return { valid: true, path: fullPath };
|
|
155
|
+
} catch (error) {
|
|
156
|
+
return {
|
|
157
|
+
valid: false,
|
|
158
|
+
path: fullPath,
|
|
159
|
+
error: error.message
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Get disk space information for a path
|
|
166
|
+
*/
|
|
167
|
+
async getDiskSpace(pathStr) {
|
|
168
|
+
const fullPath = this.expandPath(pathStr);
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
const stats = await fs.promises.statfs(fullPath);
|
|
172
|
+
return {
|
|
173
|
+
total: stats.bavail * stats.bsize,
|
|
174
|
+
available: stats.bavail * stats.bsize,
|
|
175
|
+
path: fullPath
|
|
176
|
+
};
|
|
177
|
+
} catch (error) {
|
|
178
|
+
return { error: error.message };
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Check if path exists and has existing installation
|
|
184
|
+
*/
|
|
185
|
+
async checkExistingInstallation(pathStr) {
|
|
186
|
+
const fullPath = this.expandPath(pathStr);
|
|
187
|
+
|
|
188
|
+
try {
|
|
189
|
+
const manifestPath = path.join(fullPath, 'manifest.json');
|
|
190
|
+
await fs.promises.access(manifestPath);
|
|
191
|
+
|
|
192
|
+
const manifest = JSON.parse(
|
|
193
|
+
await fs.promises.readFile(manifestPath, 'utf8')
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
exists: true,
|
|
198
|
+
manifest,
|
|
199
|
+
path: fullPath
|
|
200
|
+
};
|
|
201
|
+
} catch (error) {
|
|
202
|
+
return { exists: false, path: fullPath };
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Get default path for a tool
|
|
208
|
+
*/
|
|
209
|
+
getDefaultPath(toolId) {
|
|
210
|
+
return this.defaultPaths[toolId] || null;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Normalize path for display
|
|
215
|
+
*/
|
|
216
|
+
normalizePathForDisplay(pathStr) {
|
|
217
|
+
const fullPath = this.expandPath(pathStr);
|
|
218
|
+
|
|
219
|
+
if (fullPath.startsWith(this.homeDir)) {
|
|
220
|
+
return '~' + fullPath.slice(this.homeDir.length);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return fullPath;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Detect legacy installation (from version < 1.2.0)
|
|
228
|
+
* Legacy installations don't have manifest.json
|
|
229
|
+
*
|
|
230
|
+
* @param {string} toolId - Tool identifier (claude, opencode, ampcode, droid)
|
|
231
|
+
* @returns {Promise<Object>} Detection result with installation details
|
|
232
|
+
*/
|
|
233
|
+
async detectLegacyInstallation(toolId) {
|
|
234
|
+
const installPath = this.getDefaultPath(toolId);
|
|
235
|
+
if (!installPath) {
|
|
236
|
+
return { isLegacy: false, exists: false };
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const fullPath = this.expandPath(installPath);
|
|
240
|
+
|
|
241
|
+
try {
|
|
242
|
+
// Check if directory exists
|
|
243
|
+
const dirStats = await fs.promises.stat(fullPath);
|
|
244
|
+
if (!dirStats.isDirectory()) {
|
|
245
|
+
return { isLegacy: false, exists: false };
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Check for manifest.json
|
|
249
|
+
const manifestPath = path.join(fullPath, 'manifest.json');
|
|
250
|
+
const hasManifest = fs.existsSync(manifestPath);
|
|
251
|
+
|
|
252
|
+
if (hasManifest) {
|
|
253
|
+
// Has manifest, not a legacy installation
|
|
254
|
+
return {
|
|
255
|
+
isLegacy: false,
|
|
256
|
+
exists: true,
|
|
257
|
+
path: fullPath,
|
|
258
|
+
reason: 'Installation has manifest.json (v1.2.0+)'
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// No manifest - this is a legacy installation
|
|
263
|
+
// Count components to classify variant
|
|
264
|
+
const components = await this.countLegacyComponents(fullPath);
|
|
265
|
+
|
|
266
|
+
// Classify variant based on component counts
|
|
267
|
+
const variant = this.classifyVariantFromComponents(components);
|
|
268
|
+
|
|
269
|
+
return {
|
|
270
|
+
isLegacy: true,
|
|
271
|
+
exists: true,
|
|
272
|
+
path: fullPath,
|
|
273
|
+
components: components,
|
|
274
|
+
suggestedVariant: variant,
|
|
275
|
+
reason: 'No manifest.json found (pre-1.2.0 installation)'
|
|
276
|
+
};
|
|
277
|
+
} catch (error) {
|
|
278
|
+
return {
|
|
279
|
+
isLegacy: false,
|
|
280
|
+
exists: false,
|
|
281
|
+
error: error.message
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Count components in legacy installation
|
|
288
|
+
*
|
|
289
|
+
* @private
|
|
290
|
+
* @param {string} installPath - Installation directory path
|
|
291
|
+
* @returns {Promise<Object>} Component counts
|
|
292
|
+
*/
|
|
293
|
+
async countLegacyComponents(installPath) {
|
|
294
|
+
const components = {
|
|
295
|
+
agents: 0,
|
|
296
|
+
skills: 0,
|
|
297
|
+
resources: 0,
|
|
298
|
+
hooks: 0
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
// Count agents
|
|
302
|
+
try {
|
|
303
|
+
const agentsDir = path.join(installPath, 'agents');
|
|
304
|
+
const agentFiles = await fs.promises.readdir(agentsDir);
|
|
305
|
+
components.agents = agentFiles.filter(f => f.endsWith('.md')).length;
|
|
306
|
+
} catch (error) {
|
|
307
|
+
// Directory doesn't exist or can't read
|
|
308
|
+
components.agents = 0;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Count skills
|
|
312
|
+
try {
|
|
313
|
+
const skillsDir = path.join(installPath, 'skills');
|
|
314
|
+
const skillFiles = await fs.promises.readdir(skillsDir);
|
|
315
|
+
components.skills = skillFiles.filter(f => f.endsWith('.md')).length;
|
|
316
|
+
} catch (error) {
|
|
317
|
+
components.skills = 0;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Count resources
|
|
321
|
+
try {
|
|
322
|
+
const resourcesDir = path.join(installPath, 'resources');
|
|
323
|
+
const resourceFiles = await fs.promises.readdir(resourcesDir);
|
|
324
|
+
components.resources = resourceFiles.length;
|
|
325
|
+
} catch (error) {
|
|
326
|
+
components.resources = 0;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Count hooks
|
|
330
|
+
try {
|
|
331
|
+
const hooksDir = path.join(installPath, 'hooks');
|
|
332
|
+
const hookFiles = await fs.promises.readdir(hooksDir);
|
|
333
|
+
components.hooks = hookFiles.filter(f => f.endsWith('.js')).length;
|
|
334
|
+
} catch (error) {
|
|
335
|
+
components.hooks = 0;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
return components;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Classify variant based on component counts
|
|
343
|
+
*
|
|
344
|
+
* @private
|
|
345
|
+
* @param {Object} components - Component counts
|
|
346
|
+
* @returns {string} Suggested variant (lite, standard, pro, or custom)
|
|
347
|
+
*/
|
|
348
|
+
classifyVariantFromComponents(components) {
|
|
349
|
+
const { agents, skills } = components;
|
|
350
|
+
|
|
351
|
+
// Lite: 3 agents, 0 skills
|
|
352
|
+
if (agents === 3 && skills === 0) {
|
|
353
|
+
return 'lite';
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Pro: 13 agents, 9+ skills
|
|
357
|
+
if (agents >= 13 && skills >= 9) {
|
|
358
|
+
return 'pro';
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Standard: 13 agents, 1-8 skills (or close to it)
|
|
362
|
+
if (agents >= 10 && skills >= 1 && skills <= 8) {
|
|
363
|
+
return 'standard';
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// If 3 agents or fewer, likely lite
|
|
367
|
+
if (agents <= 3) {
|
|
368
|
+
return 'lite';
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// If many agents (10+), likely standard or pro
|
|
372
|
+
if (agents >= 10) {
|
|
373
|
+
return skills >= 9 ? 'pro' : 'standard';
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Default to standard for anything in between
|
|
377
|
+
return 'standard';
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Create manifest for legacy installation
|
|
382
|
+
*
|
|
383
|
+
* @param {string} toolId - Tool identifier
|
|
384
|
+
* @param {Object} components - Component counts
|
|
385
|
+
* @param {string} variant - Classified variant
|
|
386
|
+
* @returns {Promise<Object>} Created manifest
|
|
387
|
+
*/
|
|
388
|
+
async createManifestForLegacy(toolId, components, variant) {
|
|
389
|
+
const installPath = this.expandPath(this.getDefaultPath(toolId));
|
|
390
|
+
const manifestPath = path.join(installPath, 'manifest.json');
|
|
391
|
+
|
|
392
|
+
const manifest = {
|
|
393
|
+
tool: toolId,
|
|
394
|
+
variant: variant,
|
|
395
|
+
version: '1.2.0',
|
|
396
|
+
installed_at: new Date().toISOString(),
|
|
397
|
+
migrated_from: 'legacy',
|
|
398
|
+
components: components,
|
|
399
|
+
paths: {
|
|
400
|
+
agents: path.join(installPath, 'agents'),
|
|
401
|
+
skills: path.join(installPath, 'skills'),
|
|
402
|
+
resources: path.join(installPath, 'resources'),
|
|
403
|
+
hooks: path.join(installPath, 'hooks')
|
|
404
|
+
},
|
|
405
|
+
files: {
|
|
406
|
+
total: components.agents + components.skills + components.resources + components.hooks,
|
|
407
|
+
size: 'unknown'
|
|
408
|
+
},
|
|
409
|
+
migration: {
|
|
410
|
+
from_version: 'unknown',
|
|
411
|
+
migrated_at: new Date().toISOString(),
|
|
412
|
+
migration_type: 'automatic'
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
// Write manifest with secure permissions
|
|
417
|
+
await fs.promises.writeFile(
|
|
418
|
+
manifestPath,
|
|
419
|
+
JSON.stringify(manifest, null, 2),
|
|
420
|
+
{ mode: 0o600 }
|
|
421
|
+
);
|
|
422
|
+
|
|
423
|
+
return manifest;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
module.exports = PathManager;
|