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.
Files changed (215) hide show
  1. package/CHANGELOG.md +441 -0
  2. package/LICENSE +21 -0
  3. package/README.md +179 -0
  4. package/cli.js +230 -0
  5. package/docs/.gitkeep +1 -0
  6. package/docs/CONTRIBUTING.md +739 -0
  7. package/docs/DUAL_PUBLISH_SUMMARY.md +177 -0
  8. package/docs/ERROR_HANDLING_IMPLEMENTATION.md +327 -0
  9. package/docs/GITHUB_PACKAGES.md +181 -0
  10. package/docs/GITHUB_SETUP.md +158 -0
  11. package/docs/INSTALLATION_DEMO.md +691 -0
  12. package/docs/INSTALLATION_LOCATIONS.md +299 -0
  13. package/docs/INSTALLER_GUIDE.md +1586 -0
  14. package/docs/INTEGRATION_ISSUES_9.1.md +341 -0
  15. package/docs/KNOWLEDGE_BASE.md +727 -0
  16. package/docs/MIGRATION.md +384 -0
  17. package/docs/PACKAGE_BASELINE.md +557 -0
  18. package/docs/PACKAGE_VALIDATION_REPORT.md +427 -0
  19. package/docs/PASS_INTEGRATION.md +307 -0
  20. package/docs/PASS_QUICK_START.md +150 -0
  21. package/docs/PRIVACY.md +203 -0
  22. package/docs/PUBLISHING.md +494 -0
  23. package/docs/QUICK-START.md +318 -0
  24. package/docs/RELEASE_NOTES_1.2.0.md +323 -0
  25. package/docs/SECURITY.md +317 -0
  26. package/docs/SILENT_MODE_GUIDE.md +526 -0
  27. package/docs/SKILLS_CONVERSION.md +154 -0
  28. package/docs/TESTING.md +582 -0
  29. package/docs/TEST_COVERAGE.md +347 -0
  30. package/docs/TROUBLESHOOTING.md +788 -0
  31. package/docs/UPDATED_VARIANT_CONFIGURATION.md +274 -0
  32. package/docs/VARIANT_CONFIGURATION.md +440 -0
  33. package/installer/cli.js +761 -0
  34. package/installer/installation-engine.js +1536 -0
  35. package/installer/package-manager.js +640 -0
  36. package/installer/path-manager.js +427 -0
  37. package/installer/report-template.js +298 -0
  38. package/installer/verification-system.js +274 -0
  39. package/package.json +83 -0
  40. package/packages/ampcode/AGENT.md +58 -0
  41. package/packages/ampcode/README.md +17 -0
  42. package/packages/ampcode/agents/1-create-prd.md +175 -0
  43. package/packages/ampcode/agents/2-generate-tasks.md +190 -0
  44. package/packages/ampcode/agents/3-process-task-list.md +225 -0
  45. package/packages/ampcode/agents/code-developer.md +198 -0
  46. package/packages/ampcode/agents/context-builder.md +142 -0
  47. package/packages/ampcode/agents/feature-planner.md +199 -0
  48. package/packages/ampcode/agents/market-researcher.md +89 -0
  49. package/packages/ampcode/agents/orchestrator.md +116 -0
  50. package/packages/ampcode/agents/quality-assurance.md +115 -0
  51. package/packages/ampcode/agents/system-architect.md +135 -0
  52. package/packages/ampcode/agents/ui-designer.md +184 -0
  53. package/packages/ampcode/commands/brainstorming.md +56 -0
  54. package/packages/ampcode/commands/code-review.md +107 -0
  55. package/packages/ampcode/commands/condition-based-waiting/example.ts +158 -0
  56. package/packages/ampcode/commands/condition-based-waiting.md +122 -0
  57. package/packages/ampcode/commands/debug.md +20 -0
  58. package/packages/ampcode/commands/docs-builder/templates.md +572 -0
  59. package/packages/ampcode/commands/docs-builder.md +106 -0
  60. package/packages/ampcode/commands/explain.md +18 -0
  61. package/packages/ampcode/commands/git-commit.md +14 -0
  62. package/packages/ampcode/commands/optimize.md +20 -0
  63. package/packages/ampcode/commands/refactor.md +21 -0
  64. package/packages/ampcode/commands/review.md +18 -0
  65. package/packages/ampcode/commands/root-cause-tracing/find-polluter.sh +63 -0
  66. package/packages/ampcode/commands/root-cause-tracing.md +176 -0
  67. package/packages/ampcode/commands/security.md +21 -0
  68. package/packages/ampcode/commands/ship.md +18 -0
  69. package/packages/ampcode/commands/skill-creator/scripts/init_skill.py +303 -0
  70. package/packages/ampcode/commands/skill-creator/scripts/package_skill.py +110 -0
  71. package/packages/ampcode/commands/skill-creator/scripts/quick_validate.py +65 -0
  72. package/packages/ampcode/commands/skill-creator.md +211 -0
  73. package/packages/ampcode/commands/stash.md +45 -0
  74. package/packages/ampcode/commands/systematic-debugging.md +297 -0
  75. package/packages/ampcode/commands/test-driven-development.md +390 -0
  76. package/packages/ampcode/commands/test-generate.md +18 -0
  77. package/packages/ampcode/commands/testing-anti-patterns.md +304 -0
  78. package/packages/ampcode/commands/verification-before-completion.md +152 -0
  79. package/packages/ampcode/settings.json +13 -0
  80. package/packages/ampcode/variants.json +8 -0
  81. package/packages/claude/CLAUDE.md +58 -0
  82. package/packages/claude/README.md +23 -0
  83. package/packages/claude/agents/1-create-prd.md +175 -0
  84. package/packages/claude/agents/2-generate-tasks.md +190 -0
  85. package/packages/claude/agents/3-process-task-list.md +225 -0
  86. package/packages/claude/agents/code-developer.md +198 -0
  87. package/packages/claude/agents/context-builder.md +142 -0
  88. package/packages/claude/agents/feature-planner.md +199 -0
  89. package/packages/claude/agents/market-researcher.md +89 -0
  90. package/packages/claude/agents/orchestrator.md +117 -0
  91. package/packages/claude/agents/quality-assurance.md +115 -0
  92. package/packages/claude/agents/system-architect.md +135 -0
  93. package/packages/claude/agents/ui-designer.md +184 -0
  94. package/packages/claude/commands/debug.md +20 -0
  95. package/packages/claude/commands/explain.md +18 -0
  96. package/packages/claude/commands/git-commit.md +14 -0
  97. package/packages/claude/commands/optimize.md +20 -0
  98. package/packages/claude/commands/refactor.md +21 -0
  99. package/packages/claude/commands/review.md +18 -0
  100. package/packages/claude/commands/security.md +21 -0
  101. package/packages/claude/commands/ship.md +18 -0
  102. package/packages/claude/commands/stash.md +45 -0
  103. package/packages/claude/commands/test-generate.md +18 -0
  104. package/packages/claude/skills/brainstorming/SKILL.md +56 -0
  105. package/packages/claude/skills/code-review/SKILL.md +107 -0
  106. package/packages/claude/skills/code-review/code-reviewer.md +146 -0
  107. package/packages/claude/skills/condition-based-waiting/SKILL.md +122 -0
  108. package/packages/claude/skills/condition-based-waiting/example.ts +158 -0
  109. package/packages/claude/skills/docs-builder/SKILL.md +106 -0
  110. package/packages/claude/skills/docs-builder/references/templates.md +572 -0
  111. package/packages/claude/skills/root-cause-tracing/SKILL.md +176 -0
  112. package/packages/claude/skills/root-cause-tracing/find-polluter.sh +63 -0
  113. package/packages/claude/skills/skill-creator/LICENSE.txt +202 -0
  114. package/packages/claude/skills/skill-creator/SKILL.md +211 -0
  115. package/packages/claude/skills/skill-creator/scripts/init_skill.py +303 -0
  116. package/packages/claude/skills/skill-creator/scripts/package_skill.py +110 -0
  117. package/packages/claude/skills/skill-creator/scripts/quick_validate.py +65 -0
  118. package/packages/claude/skills/systematic-debugging/CREATION-LOG.md +119 -0
  119. package/packages/claude/skills/systematic-debugging/SKILL.md +296 -0
  120. package/packages/claude/skills/systematic-debugging/test-academic.md +14 -0
  121. package/packages/claude/skills/systematic-debugging/test-pressure-1.md +58 -0
  122. package/packages/claude/skills/systematic-debugging/test-pressure-2.md +68 -0
  123. package/packages/claude/skills/systematic-debugging/test-pressure-3.md +69 -0
  124. package/packages/claude/skills/test-driven-development/SKILL.md +392 -0
  125. package/packages/claude/skills/testing-anti-patterns/SKILL.md +304 -0
  126. package/packages/claude/skills/verification-before-completion/SKILL.md +152 -0
  127. package/packages/claude/variants.json +9 -0
  128. package/packages/droid/AGENTS.md +52 -0
  129. package/packages/droid/README.md +17 -0
  130. package/packages/droid/change_settings.json +61 -0
  131. package/packages/droid/commands/brainstorming.md +56 -0
  132. package/packages/droid/commands/code-review.md +107 -0
  133. package/packages/droid/commands/condition-based-waiting/example.ts +158 -0
  134. package/packages/droid/commands/condition-based-waiting.md +122 -0
  135. package/packages/droid/commands/debug.md +20 -0
  136. package/packages/droid/commands/docs-builder/templates.md +572 -0
  137. package/packages/droid/commands/docs-builder.md +106 -0
  138. package/packages/droid/commands/explain.md +18 -0
  139. package/packages/droid/commands/git-commit.md +14 -0
  140. package/packages/droid/commands/optimize.md +20 -0
  141. package/packages/droid/commands/refactor.md +21 -0
  142. package/packages/droid/commands/review.md +18 -0
  143. package/packages/droid/commands/root-cause-tracing/find-polluter.sh +63 -0
  144. package/packages/droid/commands/root-cause-tracing.md +176 -0
  145. package/packages/droid/commands/security.md +21 -0
  146. package/packages/droid/commands/ship.md +18 -0
  147. package/packages/droid/commands/skill-creator/scripts/init_skill.py +303 -0
  148. package/packages/droid/commands/skill-creator/scripts/package_skill.py +110 -0
  149. package/packages/droid/commands/skill-creator/scripts/quick_validate.py +65 -0
  150. package/packages/droid/commands/skill-creator.md +211 -0
  151. package/packages/droid/commands/stash.md +45 -0
  152. package/packages/droid/commands/systematic-debugging.md +297 -0
  153. package/packages/droid/commands/test-driven-development.md +390 -0
  154. package/packages/droid/commands/test-generate.md +18 -0
  155. package/packages/droid/commands/testing-anti-patterns.md +304 -0
  156. package/packages/droid/commands/verification-before-completion.md +152 -0
  157. package/packages/droid/droids/1-create-prd.md +170 -0
  158. package/packages/droid/droids/2-generate-tasks.md +190 -0
  159. package/packages/droid/droids/3-process-task-list.md +225 -0
  160. package/packages/droid/droids/code-developer.md +198 -0
  161. package/packages/droid/droids/context-builder.md +142 -0
  162. package/packages/droid/droids/feature-planner.md +199 -0
  163. package/packages/droid/droids/market-researcher.md +89 -0
  164. package/packages/droid/droids/orchestrator.md +116 -0
  165. package/packages/droid/droids/quality-assurance.md +115 -0
  166. package/packages/droid/droids/system-architect.md +135 -0
  167. package/packages/droid/droids/ui-designer.md +184 -0
  168. package/packages/droid/variants.json +8 -0
  169. package/packages/opencode/AGENTS.md +52 -0
  170. package/packages/opencode/README.md +17 -0
  171. package/packages/opencode/agent/1-create-prd.md +179 -0
  172. package/packages/opencode/agent/2-generate-tasks.md +194 -0
  173. package/packages/opencode/agent/3-process-task-list.md +229 -0
  174. package/packages/opencode/agent/code-developer.md +202 -0
  175. package/packages/opencode/agent/context-builder.md +146 -0
  176. package/packages/opencode/agent/feature-planner.md +203 -0
  177. package/packages/opencode/agent/market-researcher.md +93 -0
  178. package/packages/opencode/agent/orchestrator.md +120 -0
  179. package/packages/opencode/agent/quality-assurance.md +119 -0
  180. package/packages/opencode/agent/system-architect.md +139 -0
  181. package/packages/opencode/agent/ui-designer.md +188 -0
  182. package/packages/opencode/command/brainstorming.md +56 -0
  183. package/packages/opencode/command/code-review.md +107 -0
  184. package/packages/opencode/command/condition-based-waiting/example.ts +158 -0
  185. package/packages/opencode/command/condition-based-waiting.md +122 -0
  186. package/packages/opencode/command/debug.md +20 -0
  187. package/packages/opencode/command/docs-builder/templates.md +572 -0
  188. package/packages/opencode/command/docs-builder.md +106 -0
  189. package/packages/opencode/command/explain.md +18 -0
  190. package/packages/opencode/command/git-commit.md +14 -0
  191. package/packages/opencode/command/optimize.md +20 -0
  192. package/packages/opencode/command/refactor.md +21 -0
  193. package/packages/opencode/command/review.md +18 -0
  194. package/packages/opencode/command/root-cause-tracing/find-polluter.sh +63 -0
  195. package/packages/opencode/command/root-cause-tracing.md +176 -0
  196. package/packages/opencode/command/security.md +21 -0
  197. package/packages/opencode/command/ship.md +18 -0
  198. package/packages/opencode/command/skill-creator/scripts/init_skill.py +303 -0
  199. package/packages/opencode/command/skill-creator/scripts/package_skill.py +110 -0
  200. package/packages/opencode/command/skill-creator/scripts/quick_validate.py +65 -0
  201. package/packages/opencode/command/skill-creator.md +211 -0
  202. package/packages/opencode/command/stash.md +45 -0
  203. package/packages/opencode/command/systematic-debugging.md +297 -0
  204. package/packages/opencode/command/test-driven-development.md +390 -0
  205. package/packages/opencode/command/test-generate.md +18 -0
  206. package/packages/opencode/command/testing-anti-patterns.md +304 -0
  207. package/packages/opencode/command/verification-before-completion.md +152 -0
  208. package/packages/opencode/opencode.jsonc +201 -0
  209. package/packages/opencode/variants.json +8 -0
  210. package/packages/subagentic-manual.md +349 -0
  211. package/postinstall.js +21 -0
  212. package/tools/ampcode/manifest-template.json +14 -0
  213. package/tools/claude/manifest-template.json +14 -0
  214. package/tools/droid/manifest-template.json +14 -0
  215. 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;