opkg 0.7.2 → 0.7.4

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 (277) hide show
  1. package/dist/commands/add.js +52 -26
  2. package/dist/commands/add.js.map +1 -1
  3. package/dist/commands/apply.js +43 -4
  4. package/dist/commands/apply.js.map +1 -1
  5. package/dist/commands/install.js +132 -187
  6. package/dist/commands/install.js.map +1 -1
  7. package/dist/commands/remove.js +18 -6
  8. package/dist/commands/remove.js.map +1 -1
  9. package/dist/commands/status.js +76 -22
  10. package/dist/commands/status.js.map +1 -1
  11. package/dist/commands/uninstall.js +16 -4
  12. package/dist/commands/uninstall.js.map +1 -1
  13. package/dist/core/add/add-conflict-handler.js +1 -3
  14. package/dist/core/add/add-conflict-handler.js.map +1 -1
  15. package/dist/core/add/add-context.js +9 -0
  16. package/dist/core/add/add-context.js.map +1 -0
  17. package/dist/core/add/add-to-source-pipeline.js +127 -65
  18. package/dist/core/add/add-to-source-pipeline.js.map +1 -1
  19. package/dist/core/add/platform-path-transformer.js +3 -2
  20. package/dist/core/add/platform-path-transformer.js.map +1 -1
  21. package/dist/core/add/source-collector.js +32 -13
  22. package/dist/core/add/source-collector.js.map +1 -1
  23. package/dist/core/apply/apply-pipeline.js +2 -2
  24. package/dist/core/apply/apply-pipeline.js.map +1 -1
  25. package/dist/core/conversion-context/creation.js +153 -0
  26. package/dist/core/conversion-context/creation.js.map +1 -0
  27. package/dist/core/conversion-context/index.js +13 -0
  28. package/dist/core/conversion-context/index.js.map +1 -0
  29. package/dist/core/conversion-context/serialization.js +129 -0
  30. package/dist/core/conversion-context/serialization.js.map +1 -0
  31. package/dist/core/conversion-context/validation.js +200 -0
  32. package/dist/core/conversion-context/validation.js.map +1 -0
  33. package/dist/core/dependency-resolver.js +1 -1
  34. package/dist/core/dependency-resolver.js.map +1 -1
  35. package/dist/core/discovery/file-discovery.js +18 -19
  36. package/dist/core/discovery/file-discovery.js.map +1 -1
  37. package/dist/core/discovery/platform-files-discovery.js +3 -2
  38. package/dist/core/discovery/platform-files-discovery.js.map +1 -1
  39. package/dist/core/flows/flow-execution-coordinator.js +268 -0
  40. package/dist/core/flows/flow-execution-coordinator.js.map +1 -0
  41. package/dist/core/flows/flow-executor.js +47 -34
  42. package/dist/core/flows/flow-executor.js.map +1 -1
  43. package/dist/core/flows/flow-source-discovery.js +287 -0
  44. package/dist/core/flows/flow-source-discovery.js.map +1 -0
  45. package/dist/core/flows/flow-transforms.js +2 -0
  46. package/dist/core/flows/flow-transforms.js.map +1 -1
  47. package/dist/core/flows/map-pipeline/operations/transform.js +45 -17
  48. package/dist/core/flows/map-pipeline/operations/transform.js.map +1 -1
  49. package/dist/core/flows/platform-converter.js +81 -46
  50. package/dist/core/flows/platform-converter.js.map +1 -1
  51. package/dist/core/flows/platform-suffix-handler.js +212 -0
  52. package/dist/core/flows/platform-suffix-handler.js.map +1 -0
  53. package/dist/core/install/dry-run.js +2 -11
  54. package/dist/core/install/dry-run.js.map +1 -1
  55. package/dist/core/install/flow-based/index.js +39 -0
  56. package/dist/core/install/flow-based/index.js.map +1 -0
  57. package/dist/core/install/flow-based/installer.js +207 -0
  58. package/dist/core/install/flow-based/installer.js.map +1 -0
  59. package/dist/core/install/flow-based/orchestration/conflict-tracker.js +103 -0
  60. package/dist/core/install/flow-based/orchestration/conflict-tracker.js.map +1 -0
  61. package/dist/core/install/flow-based/orchestration/index.js +9 -0
  62. package/dist/core/install/flow-based/orchestration/index.js.map +1 -0
  63. package/dist/core/install/flow-based/orchestration/multi-package.js +110 -0
  64. package/dist/core/install/flow-based/orchestration/multi-package.js.map +1 -0
  65. package/dist/core/install/flow-based/orchestration/result-aggregator.js +120 -0
  66. package/dist/core/install/flow-based/orchestration/result-aggregator.js.map +1 -0
  67. package/dist/core/install/flow-based/shared/filtering.js +86 -0
  68. package/dist/core/install/flow-based/shared/filtering.js.map +1 -0
  69. package/dist/core/install/flow-based/shared/flow-helpers.js +92 -0
  70. package/dist/core/install/flow-based/shared/flow-helpers.js.map +1 -0
  71. package/dist/core/install/flow-based/shared/index.js +9 -0
  72. package/dist/core/install/flow-based/shared/index.js.map +1 -0
  73. package/dist/core/install/flow-based/shared/result-converter.js +97 -0
  74. package/dist/core/install/flow-based/shared/result-converter.js.map +1 -0
  75. package/dist/core/install/flow-based/strategies/base.js +98 -0
  76. package/dist/core/install/flow-based/strategies/base.js.map +1 -0
  77. package/dist/core/install/flow-based/strategies/conversion.js +172 -0
  78. package/dist/core/install/flow-based/strategies/conversion.js.map +1 -0
  79. package/dist/core/install/flow-based/strategies/direct.js +82 -0
  80. package/dist/core/install/flow-based/strategies/direct.js.map +1 -0
  81. package/dist/core/install/flow-based/strategies/factory.js +158 -0
  82. package/dist/core/install/flow-based/strategies/factory.js.map +1 -0
  83. package/dist/core/install/flow-based/strategies/flow-based.js +75 -0
  84. package/dist/core/install/flow-based/strategies/flow-based.js.map +1 -0
  85. package/dist/core/install/flow-based/strategies/index.js +14 -0
  86. package/dist/core/install/flow-based/strategies/index.js.map +1 -0
  87. package/dist/core/install/flow-based/strategies/path-mapping.js +84 -0
  88. package/dist/core/install/flow-based/strategies/path-mapping.js.map +1 -0
  89. package/dist/core/install/flow-based-installer.js +65 -1132
  90. package/dist/core/install/flow-based-installer.js.map +1 -1
  91. package/dist/core/install/flow-installation-strategies.js +11 -0
  92. package/dist/core/install/flow-installation-strategies.js.map +1 -0
  93. package/dist/core/install/format-detector.js +29 -20
  94. package/dist/core/install/format-detector.js.map +1 -1
  95. package/dist/core/install/helpers/conflict-detection.js +71 -0
  96. package/dist/core/install/helpers/conflict-detection.js.map +1 -0
  97. package/dist/core/install/helpers/file-discovery.js +39 -0
  98. package/dist/core/install/helpers/file-discovery.js.map +1 -0
  99. package/dist/core/install/helpers/format-detection.js +66 -0
  100. package/dist/core/install/helpers/format-detection.js.map +1 -0
  101. package/dist/core/install/helpers/index.js +14 -0
  102. package/dist/core/install/helpers/index.js.map +1 -0
  103. package/dist/core/install/helpers/result-aggregation.js +107 -0
  104. package/dist/core/install/helpers/result-aggregation.js.map +1 -0
  105. package/dist/core/install/helpers/result-logging.js +85 -0
  106. package/dist/core/install/helpers/result-logging.js.map +1 -0
  107. package/dist/core/install/install-flow.js +5 -5
  108. package/dist/core/install/install-flow.js.map +1 -1
  109. package/dist/core/install/local-source-resolution.js.map +1 -1
  110. package/dist/core/install/marketplace-handler.js +186 -107
  111. package/dist/core/install/marketplace-handler.js.map +1 -1
  112. package/dist/core/install/operations/conflict-handler.js +103 -0
  113. package/dist/core/install/operations/conflict-handler.js.map +1 -0
  114. package/dist/core/install/operations/index.js +7 -0
  115. package/dist/core/install/operations/index.js.map +1 -0
  116. package/dist/core/install/operations/root-files.js +182 -0
  117. package/dist/core/install/operations/root-files.js.map +1 -0
  118. package/dist/core/install/path-package-loader.js +2 -1
  119. package/dist/core/install/path-package-loader.js.map +1 -1
  120. package/dist/core/install/plugin-import.js +212 -0
  121. package/dist/core/install/plugin-import.js.map +1 -0
  122. package/dist/core/install/plugin-sources.js +135 -0
  123. package/dist/core/install/plugin-sources.js.map +1 -0
  124. package/dist/core/install/plugin-transformer.js +20 -25
  125. package/dist/core/install/plugin-transformer.js.map +1 -1
  126. package/dist/core/install/sources/base.js +12 -0
  127. package/dist/core/install/sources/base.js.map +1 -0
  128. package/dist/core/install/sources/git-source.js +86 -0
  129. package/dist/core/install/sources/git-source.js.map +1 -0
  130. package/dist/core/install/sources/index.js +16 -0
  131. package/dist/core/install/sources/index.js.map +1 -0
  132. package/dist/core/install/sources/loader-factory.js +30 -0
  133. package/dist/core/install/sources/loader-factory.js.map +1 -0
  134. package/dist/core/install/sources/path-source.js +52 -0
  135. package/dist/core/install/sources/path-source.js.map +1 -0
  136. package/dist/core/install/sources/registry-source.js +47 -0
  137. package/dist/core/install/sources/registry-source.js.map +1 -0
  138. package/dist/core/install/sources/workspace-source.js +83 -0
  139. package/dist/core/install/sources/workspace-source.js.map +1 -0
  140. package/dist/core/install/strategies/base-strategy.js +101 -0
  141. package/dist/core/install/strategies/base-strategy.js.map +1 -0
  142. package/dist/core/install/strategies/conversion-strategy.js +148 -0
  143. package/dist/core/install/strategies/conversion-strategy.js.map +1 -0
  144. package/dist/core/install/strategies/direct-install-strategy.js +63 -0
  145. package/dist/core/install/strategies/direct-install-strategy.js.map +1 -0
  146. package/dist/core/install/strategies/flow-based-strategy.js +58 -0
  147. package/dist/core/install/strategies/flow-based-strategy.js.map +1 -0
  148. package/dist/core/install/strategies/helpers/flow-helpers.js +22 -0
  149. package/dist/core/install/strategies/helpers/flow-helpers.js.map +1 -0
  150. package/dist/core/install/strategies/helpers/platform-filtering.js +53 -0
  151. package/dist/core/install/strategies/helpers/platform-filtering.js.map +1 -0
  152. package/dist/core/install/strategies/helpers/result-converter.js +75 -0
  153. package/dist/core/install/strategies/helpers/result-converter.js.map +1 -0
  154. package/dist/core/install/strategies/helpers/temp-directory.js +101 -0
  155. package/dist/core/install/strategies/helpers/temp-directory.js.map +1 -0
  156. package/dist/core/install/strategies/index.js +18 -0
  157. package/dist/core/install/strategies/index.js.map +1 -0
  158. package/dist/core/install/strategies/path-mapping-strategy.js +64 -0
  159. package/dist/core/install/strategies/path-mapping-strategy.js.map +1 -0
  160. package/dist/core/install/strategies/strategy-selector.js +51 -0
  161. package/dist/core/install/strategies/strategy-selector.js.map +1 -0
  162. package/dist/core/install/strategies/types.js +7 -0
  163. package/dist/core/install/strategies/types.js.map +1 -0
  164. package/dist/core/install/unified/context-builders.js +296 -0
  165. package/dist/core/install/unified/context-builders.js.map +1 -0
  166. package/dist/core/install/unified/context-helpers.js +80 -0
  167. package/dist/core/install/unified/context-helpers.js.map +1 -0
  168. package/dist/core/install/unified/context.js +2 -0
  169. package/dist/core/install/unified/context.js.map +1 -0
  170. package/dist/core/install/unified/index.js +20 -0
  171. package/dist/core/install/unified/index.js.map +1 -0
  172. package/dist/core/install/unified/phases/conflicts.js +19 -0
  173. package/dist/core/install/unified/phases/conflicts.js.map +1 -0
  174. package/dist/core/install/unified/phases/execute.js +42 -0
  175. package/dist/core/install/unified/phases/execute.js.map +1 -0
  176. package/dist/core/install/unified/phases/load-package.js +64 -0
  177. package/dist/core/install/unified/phases/load-package.js.map +1 -0
  178. package/dist/core/install/unified/phases/manifest.js +57 -0
  179. package/dist/core/install/unified/phases/manifest.js.map +1 -0
  180. package/dist/core/install/unified/phases/report.js +29 -0
  181. package/dist/core/install/unified/phases/report.js.map +1 -0
  182. package/dist/core/install/unified/phases/resolve-dependencies.js +50 -0
  183. package/dist/core/install/unified/phases/resolve-dependencies.js.map +1 -0
  184. package/dist/core/install/unified/pipeline.js +89 -0
  185. package/dist/core/install/unified/pipeline.js.map +1 -0
  186. package/dist/core/package.js +9 -14
  187. package/dist/core/package.js.map +1 -1
  188. package/dist/core/platforms.js +111 -29
  189. package/dist/core/platforms.js.map +1 -1
  190. package/dist/core/remove/remove-from-source-pipeline.js +124 -43
  191. package/dist/core/remove/remove-from-source-pipeline.js.map +1 -1
  192. package/dist/core/save/flow-based-saver.js +6 -3
  193. package/dist/core/save/flow-based-saver.js.map +1 -1
  194. package/dist/core/status/status-comparison.js +177 -0
  195. package/dist/core/status/status-comparison.js.map +1 -0
  196. package/dist/core/status/status-file-discovery.js +2 -2
  197. package/dist/core/status/status-file-discovery.js.map +1 -1
  198. package/dist/core/status/status-hints.js +64 -0
  199. package/dist/core/status/status-hints.js.map +1 -0
  200. package/dist/core/status/status-operation-detector.js +23 -0
  201. package/dist/core/status/status-operation-detector.js.map +1 -0
  202. package/dist/core/status/status-output.js +147 -0
  203. package/dist/core/status/status-output.js.map +1 -0
  204. package/dist/core/status/status-pipeline.js +87 -78
  205. package/dist/core/status/status-pipeline.js.map +1 -1
  206. package/dist/core/status/status-source-analyzer.js +102 -0
  207. package/dist/core/status/status-source-analyzer.js.map +1 -0
  208. package/dist/core/status/status-state-classifier.js +77 -0
  209. package/dist/core/status/status-state-classifier.js.map +1 -0
  210. package/dist/core/status/status-types.js +5 -0
  211. package/dist/core/status/status-types.js.map +1 -0
  212. package/dist/core/sync/platform-sync.js +2 -2
  213. package/dist/core/sync/platform-sync.js.map +1 -1
  214. package/dist/core/uninstall/flow-aware-uninstaller.js +1 -1
  215. package/dist/core/uninstall/flow-aware-uninstaller.js.map +1 -1
  216. package/dist/core/uninstall/uninstall-pipeline.js +43 -14
  217. package/dist/core/uninstall/uninstall-pipeline.js.map +1 -1
  218. package/dist/index.js +13 -0
  219. package/dist/index.js.map +1 -1
  220. package/dist/types/conversion-context.js +11 -0
  221. package/dist/types/conversion-context.js.map +1 -0
  222. package/dist/types/index.js +1 -0
  223. package/dist/types/index.js.map +1 -1
  224. package/dist/utils/directory-preservation.js +99 -0
  225. package/dist/utils/directory-preservation.js.map +1 -0
  226. package/dist/utils/file-walker.js +144 -0
  227. package/dist/utils/file-walker.js.map +1 -0
  228. package/dist/utils/flow-index-installer.js +47 -44
  229. package/dist/utils/flow-index-installer.js.map +1 -1
  230. package/dist/utils/glob-target-mapping.js +83 -0
  231. package/dist/utils/glob-target-mapping.js.map +1 -0
  232. package/dist/utils/index-based-installer.js +6 -45
  233. package/dist/utils/index-based-installer.js.map +1 -1
  234. package/dist/utils/install-helpers.js +0 -19
  235. package/dist/utils/install-helpers.js.map +1 -1
  236. package/dist/utils/logger.js +8 -1
  237. package/dist/utils/logger.js.map +1 -1
  238. package/dist/utils/markdown-frontmatter.js +4 -2
  239. package/dist/utils/markdown-frontmatter.js.map +1 -1
  240. package/dist/utils/package-management.js +7 -0
  241. package/dist/utils/package-management.js.map +1 -1
  242. package/dist/utils/package-versioning.js +1 -1
  243. package/dist/utils/package-versioning.js.map +1 -1
  244. package/dist/utils/package-yml.js +1 -0
  245. package/dist/utils/package-yml.js.map +1 -1
  246. package/dist/utils/path-comparison.js +110 -0
  247. package/dist/utils/path-comparison.js.map +1 -0
  248. package/dist/utils/path-resolution.js +11 -7
  249. package/dist/utils/path-resolution.js.map +1 -1
  250. package/dist/utils/platform-mapper.js +134 -4
  251. package/dist/utils/platform-mapper.js.map +1 -1
  252. package/dist/utils/resolution-mode.js +16 -0
  253. package/dist/utils/resolution-mode.js.map +1 -0
  254. package/package.json +1 -1
  255. package/plans/conversion-context-architecture.md +695 -0
  256. package/plans/conversion-context-implementation-guide.md +1327 -0
  257. package/platforms.jsonc +319 -47
  258. package/schemas/agent-frontmatter-v1.json +250 -0
  259. package/schemas/platforms-v1.json +25 -9
  260. package/specs/add/README.md +107 -7
  261. package/specs/agents-frontmatter.md +967 -0
  262. package/specs/apply/apply-behavior.md +45 -1
  263. package/specs/apply/apply-command.md +5 -1
  264. package/specs/claude-plugins-marketplace-creation.md +564 -0
  265. package/specs/claude-settings.md +945 -0
  266. package/specs/cli-options.md +82 -0
  267. package/specs/commands-overview.md +17 -8
  268. package/specs/install/README.md +10 -1
  269. package/specs/install/install-behavior.md +118 -2
  270. package/specs/install/marketplace-installation.md +839 -0
  271. package/specs/install/plugin-installation.md +598 -0
  272. package/specs/install/plugin-source-normalization.md +773 -0
  273. package/specs/opencode-tools.md +345 -0
  274. package/specs/platforms/flow-reference.md +103 -0
  275. package/specs/platforms/flows.md +28 -2
  276. package/specs/remove/README.md +128 -20
  277. package/specs/uninstall/README.md +22 -3
@@ -2,12 +2,59 @@ import { withErrorHandling } from '../utils/errors.js';
2
2
  import { runAddToSourcePipeline } from '../core/add/add-to-source-pipeline.js';
3
3
  import { readWorkspaceIndex } from '../utils/workspace-index-yml.js';
4
4
  import { formatPathForDisplay } from '../utils/formatters.js';
5
+ /**
6
+ * Display add operation results in install-style format
7
+ */
8
+ function displayAddResults(data, options) {
9
+ const cwd = process.cwd();
10
+ const { filesAdded, sourcePath, sourceType, packageName: resolvedName, addedFilePaths } = data;
11
+ // Determine if this is a workspace root add
12
+ const displayPath = formatPathForDisplay(sourcePath, cwd);
13
+ const isWorkspaceRoot = displayPath.includes('.openpackage') && !displayPath.includes('.openpackage/packages');
14
+ // Main success message
15
+ if (isWorkspaceRoot) {
16
+ console.log(`āœ“ Added to workspace package`);
17
+ }
18
+ else {
19
+ console.log(`āœ“ Added to ${resolvedName}`);
20
+ }
21
+ // Display added files in install-style format
22
+ if (addedFilePaths && addedFilePaths.length > 0) {
23
+ console.log(`āœ“ Added files: ${addedFilePaths.length}`);
24
+ const sortedFiles = [...addedFilePaths].sort((a, b) => a.localeCompare(b));
25
+ for (const file of sortedFiles) {
26
+ console.log(` ā”œā”€ā”€ ${formatPathForDisplay(file, cwd)}`);
27
+ }
28
+ }
29
+ else {
30
+ console.log(`āœ“ Added files: ${filesAdded}`);
31
+ }
32
+ // Show hints only for non-workspace-root adds
33
+ if (!options.apply && !isWorkspaceRoot) {
34
+ // Check if package is installed in workspace
35
+ readWorkspaceIndex(cwd).then(workspaceIndexRecord => {
36
+ const isInstalled = !!workspaceIndexRecord.index.packages[resolvedName];
37
+ if (isInstalled) {
38
+ console.log(`\nšŸ’” Changes not synced to workspace.`);
39
+ console.log(` To sync changes, run:`);
40
+ console.log(` opkg apply ${resolvedName}`);
41
+ }
42
+ else {
43
+ console.log(`\nšŸ’” Package not installed in workspace.`);
44
+ console.log(` To install and sync, run:`);
45
+ console.log(` opkg install ${resolvedName}`);
46
+ }
47
+ }).catch(() => {
48
+ // Ignore errors reading workspace index
49
+ });
50
+ }
51
+ }
5
52
  export function setupAddCommand(program) {
6
53
  program
7
54
  .command('add')
8
- .argument('<package-name>', 'package name')
9
- .argument('<path>', 'file or directory to add')
10
- .description('Add files to a mutable package source')
55
+ .argument('[package-name]', 'package name (optional - defaults to workspace package)')
56
+ .argument('[path]', 'file or directory to add')
57
+ .description('Add files to a mutable package source or workspace package')
11
58
  .option('--platform-specific', 'Save platform-specific variants for platform subdir inputs')
12
59
  .option('--apply', 'Apply changes to workspace immediately (requires package to be installed)')
13
60
  .action(withErrorHandling(async (packageName, pathArg, options) => {
@@ -15,30 +62,9 @@ export function setupAddCommand(program) {
15
62
  if (!result.success) {
16
63
  throw new Error(result.error || 'Add operation failed');
17
64
  }
18
- // Provide helpful feedback
65
+ // Display results
19
66
  if (result.data) {
20
- const cwd = process.cwd();
21
- const { filesAdded, sourcePath, sourceType, packageName: resolvedName } = result.data;
22
- // Format the path for display using unified formatter
23
- const displayPath = formatPathForDisplay(sourcePath, cwd);
24
- console.log(`\nāœ“ Added ${filesAdded} file${filesAdded !== 1 ? 's' : ''} to ${resolvedName}`);
25
- console.log(` Path: ${displayPath}`);
26
- console.log(` Type: ${sourceType} package`);
27
- if (!options.apply) {
28
- // Check if package is installed in workspace
29
- const workspaceIndexRecord = await readWorkspaceIndex(cwd);
30
- const isInstalled = !!workspaceIndexRecord.index.packages[resolvedName];
31
- if (isInstalled) {
32
- console.log(`\nšŸ’” Changes not synced to workspace.`);
33
- console.log(` To sync changes, run:`);
34
- console.log(` opkg apply ${resolvedName}`);
35
- }
36
- else {
37
- console.log(`\nšŸ’” Package not installed in workspace.`);
38
- console.log(` To install and sync, run:`);
39
- console.log(` opkg install ${resolvedName}`);
40
- }
41
- }
67
+ displayAddResults(result.data, options);
42
68
  }
43
69
  }));
44
70
  }
@@ -1 +1 @@
1
- {"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAA2B,MAAM,uCAAuC,CAAC;AACxG,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,MAAM,UAAU,eAAe,CAAC,OAAgB;IAC9C,OAAO;SACJ,OAAO,CAAC,KAAK,CAAC;SACd,QAAQ,CAAC,gBAAgB,EAAE,cAAc,CAAC;SAC1C,QAAQ,CAAC,QAAQ,EAAE,0BAA0B,CAAC;SAC9C,WAAW,CAAC,uCAAuC,CAAC;SACpD,MAAM,CAAC,qBAAqB,EAAE,4DAA4D,CAAC;SAC3F,MAAM,CAAC,SAAS,EAAE,2EAA2E,CAAC;SAC9F,MAAM,CACL,iBAAiB,CAAC,KAAK,EAAE,WAA+B,EAAE,OAA2B,EAAE,OAA2B,EAAE,EAAE;QACpH,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC,WAAW,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAC3E,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,sBAAsB,CAAC,CAAC;QAC1D,CAAC;QAED,2BAA2B;QAC3B,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YAChB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;YAC1B,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC;YAEtF,sDAAsD;YACtD,MAAM,WAAW,GAAG,oBAAoB,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;YAE1D,OAAO,CAAC,GAAG,CAAC,aAAa,UAAU,QAAQ,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,OAAO,YAAY,EAAE,CAAC,CAAC;YAC7F,OAAO,CAAC,GAAG,CAAC,WAAW,WAAW,EAAE,CAAC,CAAC;YACtC,OAAO,CAAC,GAAG,CAAC,WAAW,UAAU,UAAU,CAAC,CAAC;YAE7C,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;gBACnB,6CAA6C;gBAC7C,MAAM,oBAAoB,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,CAAC;gBAC3D,MAAM,WAAW,GAAG,CAAC,CAAC,oBAAoB,CAAC,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;gBAExE,IAAI,WAAW,EAAE,CAAC;oBAChB,OAAO,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;oBACrD,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;oBACxC,OAAO,CAAC,GAAG,CAAC,mBAAmB,YAAY,EAAE,CAAC,CAAC;gBACjD,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;oBACxD,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;oBAC5C,OAAO,CAAC,GAAG,CAAC,qBAAqB,YAAY,EAAE,CAAC,CAAC;gBACnD,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CACH,CAAC;AACN,CAAC"}
1
+ {"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"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"}
@@ -1,16 +1,55 @@
1
1
  import { withErrorHandling } from '../utils/errors.js';
2
- import { runApplyPipeline } from '../core/apply/apply-pipeline.js';
2
+ import { buildApplyContext } from '../core/install/unified/context-builders.js';
3
+ import { runUnifiedInstallPipeline } from '../core/install/unified/pipeline.js';
4
+ /**
5
+ * Main apply command handler
6
+ */
7
+ async function applyCommand(packageName, options) {
8
+ const cwd = process.cwd();
9
+ // Handle bulk apply when no package name specified
10
+ if (!packageName) {
11
+ const contexts = await buildApplyContext(cwd, undefined, options);
12
+ return await applyBulk(contexts);
13
+ }
14
+ // Apply single package
15
+ const ctx = await buildApplyContext(cwd, packageName, options);
16
+ return await runUnifiedInstallPipeline(ctx);
17
+ }
18
+ /**
19
+ * Apply multiple packages (workspace root + all installed packages)
20
+ */
21
+ async function applyBulk(contexts) {
22
+ if (contexts.length === 0) {
23
+ return {
24
+ success: false,
25
+ error: `No packages installed in this workspace.\n` +
26
+ `Run 'opkg install <package-name>' to install a package first.`
27
+ };
28
+ }
29
+ console.log(`āœ“ Applying ${contexts.length} package${contexts.length === 1 ? '' : 's'}\n`);
30
+ for (const ctx of contexts) {
31
+ const result = await runUnifiedInstallPipeline(ctx);
32
+ if (!result.success) {
33
+ return result; // Stop on first failure
34
+ }
35
+ }
36
+ return { success: true };
37
+ }
38
+ /**
39
+ * Setup apply command
40
+ */
3
41
  export function setupApplyCommand(program) {
4
42
  program
5
43
  .command('apply')
6
44
  .description('Apply/sync package across platforms')
7
- .argument('[package-name]', 'package name to apply (defaults to current/root package)')
45
+ .argument('[package-name]', 'package name to apply (optional - applies workspace-level files and all installed packages if not specified)')
8
46
  .option('-f, --force', 'overwrite existing files without prompting')
9
47
  .option('--dry-run', 'plan apply without writing files')
10
48
  .action(withErrorHandling(async (packageName, options) => {
11
- const result = await runApplyPipeline(packageName, options ?? {});
12
- if (!result.success)
49
+ const result = await applyCommand(packageName, options);
50
+ if (!result.success) {
13
51
  throw new Error(result.error || 'Apply operation failed');
52
+ }
14
53
  }));
15
54
  }
16
55
  //# sourceMappingURL=apply.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/commands/apply.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAA6B,MAAM,iCAAiC,CAAC;AAE9F,MAAM,UAAU,iBAAiB,CAAC,OAAgB;IAChD,OAAO;SACJ,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,qCAAqC,CAAC;SAClD,QAAQ,CAAC,gBAAgB,EAAE,0DAA0D,CAAC;SACtF,MAAM,CAAC,aAAa,EAAE,4CAA4C,CAAC;SACnE,MAAM,CAAC,WAAW,EAAE,kCAAkC,CAAC;SACvD,MAAM,CACL,iBAAiB,CAAC,KAAK,EAAE,WAA+B,EAAE,OAA6B,EAAE,EAAE;QACzF,MAAM,MAAM,GAAkB,MAAM,gBAAgB,CAAC,WAAW,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC;QACjF,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,wBAAwB,CAAC,CAAC;IACjF,CAAC,CAAC,CACH,CAAC;AACN,CAAC"}
1
+ {"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/commands/apply.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,6CAA6C,CAAC;AAChF,OAAO,EAAE,yBAAyB,EAAE,MAAM,qCAAqC,CAAC;AAEhF;;GAEG;AACH,KAAK,UAAU,YAAY,CACzB,WAA+B,EAC/B,OAA8C;IAE9C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAE1B,mDAAmD;IACnD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;QAClE,OAAO,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC;IACnC,CAAC;IAED,uBAAuB;IACvB,MAAM,GAAG,GAAG,MAAM,iBAAiB,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;IAC/D,OAAO,MAAM,yBAAyB,CAAC,GAAG,CAAC,CAAC;AAC9C,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,SAAS,CAAC,QAA+B;IACtD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EACH,4CAA4C;gBAC5C,+DAA+D;SAClE,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,cAAc,QAAQ,CAAC,MAAM,WAAW,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAE1F,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,MAAM,yBAAyB,CAAC,GAAG,CAAC,CAAC;QAEpD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,MAAM,CAAC,CAAC,wBAAwB;QACzC,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAgB;IAChD,OAAO;SACJ,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,qCAAqC,CAAC;SAClD,QAAQ,CACP,gBAAgB,EAChB,8GAA8G,CAC/G;SACA,MAAM,CAAC,aAAa,EAAE,4CAA4C,CAAC;SACnE,MAAM,CAAC,WAAW,EAAE,kCAAkC,CAAC;SACvD,MAAM,CACL,iBAAiB,CAAC,KAAK,EAAE,WAA+B,EAAE,OAAY,EAAE,EAAE;QACxE,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAExD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,wBAAwB,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC,CAAC,CACH,CAAC;AACN,CAAC"}
@@ -1,19 +1,14 @@
1
- import { resolve } from 'path';
2
- import { formatPathForDisplay } from '../utils/formatters.js';
3
- import { DIR_PATTERNS, PACKAGE_PATHS } from '../constants/index.js';
4
- import { runBulkInstallPipeline } from '../core/install/bulk-install-pipeline.js';
5
- import { runInstallPipeline, determineResolutionMode } from '../core/install/install-pipeline.js';
6
- import { runPathInstallPipeline } from '../core/install/path-install-pipeline.js';
7
- import { loadPackageFromGit } from '../core/install/git-package-loader.js';
8
- import { inferSourceType } from '../core/install/path-package-loader.js';
9
- import { detectPluginType } from '../core/install/plugin-detector.js';
10
- import { parseMarketplace, promptPluginSelection, installMarketplacePlugins } from '../core/install/marketplace-handler.js';
11
- import { withErrorHandling, ValidationError } from '../utils/errors.js';
1
+ import { withErrorHandling } from '../utils/errors.js';
12
2
  import { normalizePlatforms } from '../utils/platform-mapper.js';
13
- import { classifyPackageInput } from '../utils/package-input.js';
14
- import { findExistingPathOrGitSource } from '../utils/install-helpers.js';
15
- import { logger } from '../utils/logger.js';
3
+ import { buildInstallContext } from '../core/install/unified/context-builders.js';
4
+ import { runUnifiedInstallPipeline } from '../core/install/unified/pipeline.js';
5
+ import { determineResolutionMode } from '../utils/resolution-mode.js';
6
+ import { DIR_PATTERNS, PACKAGE_PATHS } from '../constants/index.js';
16
7
  import { normalizePathForProcessing } from '../utils/path-normalization.js';
8
+ import { getLoaderForSource } from '../core/install/sources/loader-factory.js';
9
+ /**
10
+ * Validate that target directory is not inside .openpackage metadata
11
+ */
17
12
  function assertTargetDirOutsideMetadata(targetDir) {
18
13
  const normalized = normalizePathForProcessing(targetDir ?? '.');
19
14
  if (!normalized || normalized === '.') {
@@ -21,204 +16,150 @@ function assertTargetDirOutsideMetadata(targetDir) {
21
16
  }
22
17
  if (normalized === DIR_PATTERNS.OPENPACKAGE ||
23
18
  normalized.startsWith(`${DIR_PATTERNS.OPENPACKAGE}/`)) {
24
- throw new Error(`Installation target '${targetDir}' cannot point inside ${DIR_PATTERNS.OPENPACKAGE} (reserved for metadata like ${PACKAGE_PATHS.INDEX_RELATIVE}). Choose a workspace path outside metadata.`);
19
+ throw new Error(`Installation target '${targetDir}' cannot point inside ${DIR_PATTERNS.OPENPACKAGE} ` +
20
+ `(reserved for metadata like ${PACKAGE_PATHS.INDEX_RELATIVE}). ` +
21
+ `Choose a workspace path outside metadata.`);
25
22
  }
26
23
  }
24
+ /**
25
+ * Validate resolution flags
26
+ */
27
27
  export function validateResolutionFlags(options) {
28
28
  if (options.remote && options.local) {
29
29
  throw new Error('--remote and --local cannot be used together. Choose one resolution mode.');
30
30
  }
31
31
  }
32
+ /**
33
+ * Main install command handler
34
+ */
32
35
  async function installCommand(packageInput, options) {
33
- const targetDir = '.';
34
36
  const cwd = process.cwd();
37
+ const targetDir = '.';
38
+ // Validate inputs
35
39
  assertTargetDirOutsideMetadata(targetDir);
40
+ validateResolutionFlags(options);
41
+ // Set resolution mode
36
42
  options.resolutionMode = determineResolutionMode(options);
37
- logger.debug('Install resolution mode selected', { mode: options.resolutionMode });
38
- if (!packageInput) {
39
- return await runBulkInstallPipeline(options);
43
+ // Build context(s)
44
+ const contexts = await buildInstallContext(cwd, packageInput, options);
45
+ // Handle bulk install (multiple contexts)
46
+ if (Array.isArray(contexts)) {
47
+ return await runBulkInstall(contexts);
40
48
  }
41
- // Classify the input to determine if it's a registry name, directory, or tarball
42
- const classification = await classifyPackageInput(packageInput, cwd);
43
- // For registry-type inputs (package names), check if it's actually a path/git dependency in openpackage.yml
44
- // This ensures we respect the manifest's declared source type on subsequent installs
45
- if (classification.type === 'registry' && classification.name) {
46
- const existingSource = await findExistingPathOrGitSource(cwd, classification.name);
47
- if (existingSource) {
48
- if (existingSource.type === 'git') {
49
- const subdirPart = existingSource.subdirectory ? `&subdirectory=${existingSource.subdirectory}` : '';
50
- logger.info(`Using git source from openpackage.yml for '${classification.name}': ${existingSource.url}`);
51
- console.log(`āœ“ Using git source from openpackage.yml: ${existingSource.url}${existingSource.ref ? `#${existingSource.ref}` : ''}${subdirPart}`);
52
- const result = await loadPackageFromGit({
53
- url: existingSource.url,
54
- ref: existingSource.ref,
55
- subdirectory: existingSource.subdirectory
56
- });
57
- if (result.isMarketplace) {
58
- throw new ValidationError(`Package '${classification.name}' is declared as a git source in openpackage.yml, ` +
59
- `but the repository is a Claude Code plugin marketplace. ` +
60
- `Marketplaces cannot be used as dependencies via openpackage.yml.`);
61
- }
62
- return await runPathInstallPipeline({
63
- ...options,
64
- sourcePath: result.sourcePath,
65
- sourceType: 'directory',
66
- targetDir,
67
- gitUrl: existingSource.url,
68
- gitRef: existingSource.ref,
69
- gitSubdirectory: existingSource.subdirectory
70
- });
71
- }
72
- else if (existingSource.type === 'path') {
73
- logger.info(`Using path source from openpackage.yml for '${classification.name}': ${existingSource.path}`);
74
- const displayPath = formatPathForDisplay(existingSource.path, cwd);
75
- console.log(`āœ“ Using path source from openpackage.yml: ${displayPath}`);
76
- const resolvedPath = resolve(cwd, existingSource.path);
77
- const sourceType = inferSourceType(existingSource.path);
78
- return await runPathInstallPipeline({
79
- ...options,
80
- sourcePath: resolvedPath,
81
- sourceType,
82
- targetDir
83
- });
84
- }
85
- }
86
- }
87
- if (classification.type === 'git') {
88
- const result = await loadPackageFromGit({
89
- url: classification.gitUrl,
90
- ref: classification.gitRef,
91
- subdirectory: classification.gitSubdirectory
92
- });
93
- // Check if this is a marketplace
94
- if (result.isMarketplace) {
95
- logger.info('Detected Claude Code marketplace, prompting for plugin selection', {
96
- url: classification.gitUrl
97
- });
98
- const pluginDetection = await detectPluginType(result.sourcePath);
99
- if (!pluginDetection.manifestPath) {
100
- throw new ValidationError('Marketplace manifest not found');
101
- }
102
- // Parse marketplace and prompt for selection (pass context for fallback naming)
103
- const marketplace = await parseMarketplace(pluginDetection.manifestPath, {
104
- gitUrl: classification.gitUrl,
105
- repoPath: result.repoPath
106
- });
107
- const selectedPlugins = await promptPluginSelection(marketplace);
108
- if (selectedPlugins.length === 0) {
109
- console.log('No plugins selected. Installation cancelled.');
110
- return { success: true };
111
- }
112
- // Install selected plugins
113
- return await installMarketplacePlugins(result.repoPath, marketplace, selectedPlugins, classification.gitUrl, classification.gitRef, options);
49
+ // For git sources, we need to load the package first to detect if it's a marketplace
50
+ // Marketplaces are detected during loadPackagePhase, so we need to check after loading
51
+ if (contexts.source.type === 'git') {
52
+ // Load package to detect marketplace
53
+ const loader = getLoaderForSource(contexts.source);
54
+ const loaded = await loader.load(contexts.source, options, cwd);
55
+ // Update context with loaded info
56
+ contexts.source.packageName = loaded.packageName;
57
+ contexts.source.version = loaded.version;
58
+ contexts.source.contentRoot = loaded.contentRoot;
59
+ contexts.source.pluginMetadata = loaded.pluginMetadata;
60
+ // Check if marketplace - handle at command level
61
+ if (contexts.source.pluginMetadata?.pluginType === 'marketplace') {
62
+ return await handleMarketplaceInstallation(contexts, options, cwd);
114
63
  }
115
- // Not a marketplace, install as regular package/plugin
116
- return await runPathInstallPipeline({
117
- ...options,
118
- sourcePath: result.sourcePath,
119
- sourceType: 'directory',
120
- targetDir,
121
- gitUrl: classification.gitUrl,
122
- gitRef: classification.gitRef,
123
- gitSubdirectory: classification.gitSubdirectory
124
- });
64
+ // Not a marketplace, continue with normal pipeline
65
+ // Create resolved package for the loaded package
66
+ contexts.resolvedPackages = [{
67
+ name: loaded.packageName,
68
+ version: loaded.version,
69
+ pkg: { metadata: loaded.metadata, files: [], _format: undefined },
70
+ isRoot: true,
71
+ source: 'git',
72
+ contentRoot: loaded.contentRoot
73
+ }];
125
74
  }
126
- if (classification.type === 'directory' || classification.type === 'tarball') {
127
- // Display source comparison info if available
128
- if (classification.sourceComparisonInfo) {
129
- displayPackageSourceResolution(classification.sourceComparisonInfo);
130
- }
131
- // Check if this is a marketplace (only for directories, not tarballs)
132
- if (classification.type === 'directory') {
133
- const pluginDetection = await detectPluginType(classification.resolvedPath);
134
- if (pluginDetection.isPlugin && pluginDetection.type === 'marketplace') {
135
- logger.info('Detected Claude Code marketplace from local path, prompting for plugin selection', {
136
- path: classification.resolvedPath
137
- });
138
- // Parse marketplace and prompt for selection (pass context for fallback naming)
139
- const marketplace = await parseMarketplace(pluginDetection.manifestPath, {
140
- repoPath: classification.resolvedPath
141
- });
142
- const selectedPlugins = await promptPluginSelection(marketplace);
143
- if (selectedPlugins.length === 0) {
144
- console.log('No plugins selected. Installation cancelled.');
145
- return { success: true };
146
- }
147
- // Install selected plugins (no git URL for local paths)
148
- return await installMarketplacePlugins(classification.resolvedPath, marketplace, selectedPlugins, classification.resolvedPath, // Use path as "url" for tracking
149
- undefined, // No git ref for local paths
150
- options);
151
- }
152
- }
153
- return await runPathInstallPipeline({
154
- ...options,
155
- sourcePath: classification.resolvedPath,
156
- sourceType: classification.type,
157
- targetDir
158
- });
75
+ // Single package install
76
+ return await runUnifiedInstallPipeline(contexts);
77
+ }
78
+ /**
79
+ * Handle marketplace installation with plugin selection
80
+ */
81
+ async function handleMarketplaceInstallation(context, options, cwd) {
82
+ const { parseMarketplace, promptPluginSelection, installMarketplacePlugins } = await import('../core/install/marketplace-handler.js');
83
+ const { Spinner } = await import('../utils/spinner.js');
84
+ // Load the marketplace package (already loaded, use context data)
85
+ if (!context.source.pluginMetadata?.manifestPath) {
86
+ throw new Error('Marketplace manifest not found');
159
87
  }
160
- // Registry-based install (existing flow)
161
- const { name, version, registryPath } = classification;
162
- return await runInstallPipeline({
163
- ...options,
164
- packageName: name,
165
- version,
166
- registryPath,
167
- targetDir
88
+ const spinner = new Spinner('Loading marketplace');
89
+ spinner.start();
90
+ // Parse marketplace manifest
91
+ const marketplace = await parseMarketplace(context.source.pluginMetadata.manifestPath, {
92
+ repoPath: context.source.contentRoot
168
93
  });
94
+ spinner.stop();
95
+ // Prompt user to select plugins
96
+ const selectedPlugins = await promptPluginSelection(marketplace);
97
+ if (selectedPlugins.length === 0) {
98
+ console.log('No plugins selected. Installation cancelled.');
99
+ return { success: true, data: { installed: 0, skipped: 0 } };
100
+ }
101
+ // Install selected plugins using marketplace handler
102
+ // At this point we know it's a git source with a gitUrl
103
+ if (context.source.type !== 'git' || !context.source.gitUrl) {
104
+ throw new Error('Marketplace must be from a git source');
105
+ }
106
+ return await installMarketplacePlugins(context.source.contentRoot, marketplace, selectedPlugins, context.source.gitUrl, context.source.gitRef, options, cwd);
169
107
  }
170
108
  /**
171
- * Display user-friendly information about package source resolution
109
+ * Run bulk installation for multiple packages
172
110
  */
173
- function displayPackageSourceResolution(info) {
174
- const { candidates, selected, reason } = info;
175
- // Workspace override - simple message
176
- if (reason === 'workspace-override') {
177
- console.log(`āœ“ Found ${selected.packageName} in workspace packages`);
178
- console.log(`šŸ’” Workspace packages always override global/registry`);
179
- return;
180
- }
181
- // Single source - simple message
182
- if (reason === 'only-source' && candidates.length === 1) {
183
- const sourceType = selected.type === 'global' ? 'global packages' :
184
- selected.type === 'registry' ? 'registry' : 'workspace packages';
185
- console.log(`āœ“ Found ${selected.packageName} in ${sourceType}`);
186
- return;
111
+ async function runBulkInstall(contexts) {
112
+ if (contexts.length === 0) {
113
+ console.log('āš ļø No packages found in openpackage.yml');
114
+ console.log('\nšŸ’” Tips:');
115
+ console.log(' • Add packages to the "packages" array in openpackage.yml');
116
+ console.log(' • Add development packages to the "dev-packages" array');
117
+ console.log(' • Use "opkg install <package-name>" to install a specific package');
118
+ return { success: true, data: { installed: 0, skipped: 0 } };
187
119
  }
188
- // Multiple sources - show comparison
189
- if (candidates.length > 1) {
190
- console.log(`Resolving ${selected.packageName}...`);
191
- for (const candidate of candidates) {
192
- const label = candidate.type === 'global' ? 'Global packages' : 'Registry';
193
- const suffix = candidate.type === 'global' ? ' (mutable)' : ' (stable)';
194
- console.log(` • ${label}: ${candidate.version}${suffix}`);
195
- }
196
- const sourceLabel = selected.type === 'global' ? 'global packages' : 'registry';
197
- if (reason === 'newer-version') {
198
- console.log(`āœ“ Using ${selected.packageName}@${selected.version} from ${sourceLabel} (newer version)`);
199
- // Warn about outdated global if registry was selected
200
- if (selected.type === 'registry') {
201
- const global = candidates.find((c) => c.type === 'global');
202
- if (global) {
203
- console.log(`āš ļø Global packages has older version (${global.version})`);
204
- console.log(`šŸ’” To update global: cd ~/.openpackage/packages/${selected.packageName} && opkg pack`);
205
- }
120
+ console.log(`\nāœ“ Installing ${contexts.length} package${contexts.length === 1 ? '' : 's'} from openpackage.yml\n`);
121
+ let totalInstalled = 0;
122
+ let totalSkipped = 0;
123
+ const results = [];
124
+ for (const ctx of contexts) {
125
+ try {
126
+ const result = await runUnifiedInstallPipeline(ctx);
127
+ if (result.success) {
128
+ totalInstalled++;
129
+ results.push({ name: ctx.source.packageName, success: true });
130
+ console.log(`āœ“ ${ctx.source.packageName}`);
131
+ }
132
+ else {
133
+ totalSkipped++;
134
+ results.push({ name: ctx.source.packageName, success: false, error: result.error });
135
+ console.log(`āŒ ${ctx.source.packageName}: ${result.error}`);
206
136
  }
207
137
  }
208
- else if (reason === 'same-version-prefer-mutable') {
209
- console.log(`āœ“ Using ${selected.packageName}@${selected.version} from ${sourceLabel} (same version, prefer mutable)`);
210
- }
211
- else {
212
- console.log(`āœ“ Using ${selected.packageName}@${selected.version} from ${sourceLabel}`);
138
+ catch (error) {
139
+ totalSkipped++;
140
+ results.push({ name: ctx.source.packageName, success: false, error: String(error) });
141
+ console.log(`āŒ ${ctx.source.packageName}: ${error}`);
213
142
  }
214
143
  }
144
+ // Display summary
145
+ console.log(`\nāœ“ Installation complete: ${totalInstalled} installed${totalSkipped > 0 ? `, ${totalSkipped} failed` : ''}`);
146
+ const allSuccessful = totalSkipped === 0;
147
+ return {
148
+ success: allSuccessful,
149
+ data: { installed: totalInstalled, skipped: totalSkipped, results },
150
+ error: allSuccessful ? undefined : `${totalSkipped} packages failed to install`
151
+ };
215
152
  }
153
+ /**
154
+ * Setup install command
155
+ */
216
156
  export function setupInstallCommand(program) {
217
157
  program
218
158
  .command('install')
219
159
  .alias('i')
220
160
  .description('Install packages to workspace')
221
- .argument('[package-name]', 'name of the package to install (optional - installs all from openpackage.yml if not specified). Supports package@version syntax.')
161
+ .argument('[package-name]', 'name of the package to install (optional - installs workspace-level files and all packages from openpackage.yml if not specified). ' +
162
+ 'Supports package@version syntax.')
222
163
  .option('--dry-run', 'preview changes without applying them')
223
164
  .option('--force', 'overwrite existing files')
224
165
  .option('--conflicts <strategy>', 'conflict handling strategy: keep-both, overwrite, skip, or ask')
@@ -229,23 +170,27 @@ export function setupInstallCommand(program) {
229
170
  .option('--profile <profile>', 'profile to use for authentication')
230
171
  .option('--api-key <key>', 'API key for authentication (overrides profile)')
231
172
  .action(withErrorHandling(async (packageName, options) => {
173
+ // Normalize platforms
232
174
  options.platforms = normalizePlatforms(options.platforms);
175
+ // Normalize conflict strategy
233
176
  const commandOptions = options;
234
177
  const rawConflictStrategy = commandOptions.conflicts ?? options.conflictStrategy;
235
178
  if (rawConflictStrategy) {
236
179
  const normalizedStrategy = rawConflictStrategy.toLowerCase();
237
- const allowedStrategies = ['keep-both', 'overwrite', 'skip', 'ask'];
180
+ const allowedStrategies = [
181
+ 'keep-both', 'overwrite', 'skip', 'ask'
182
+ ];
238
183
  if (!allowedStrategies.includes(normalizedStrategy)) {
239
- throw new Error(`Invalid --conflicts value '${rawConflictStrategy}'. Use one of: keep-both, overwrite, skip, ask.`);
184
+ throw new Error(`Invalid --conflicts value '${rawConflictStrategy}'. ` +
185
+ `Use one of: keep-both, overwrite, skip, ask.`);
240
186
  }
241
187
  options.conflictStrategy = normalizedStrategy;
242
188
  }
243
- validateResolutionFlags(options);
244
- options.resolutionMode = determineResolutionMode(options);
189
+ // Execute install
245
190
  const result = await installCommand(packageName, options);
246
191
  if (!result.success) {
247
192
  if (result.error === 'Package not found') {
248
- return;
193
+ return; // Already displayed message
249
194
  }
250
195
  throw new Error(result.error || 'Installation operation failed');
251
196
  }