opkg 0.6.1 → 0.7.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/README.md +109 -186
- package/assets/openpackage_ascii_dark.png +0 -0
- package/assets/openpackage_ascii_light.png +0 -0
- package/dist/commands/add.js +34 -10
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/apply.js +16 -0
- package/dist/commands/apply.js.map +1 -0
- package/dist/commands/delete.js +1 -1
- package/dist/commands/delete.js.map +1 -1
- package/dist/commands/install.js +177 -8
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/list.js +2 -2
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/login.js +1 -1
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logout.js +1 -1
- package/dist/commands/logout.js.map +1 -1
- package/dist/commands/new.js +125 -0
- package/dist/commands/new.js.map +1 -0
- package/dist/commands/pack.js +7 -13
- package/dist/commands/pack.js.map +1 -1
- package/dist/commands/pull.js +1 -1
- package/dist/commands/pull.js.map +1 -1
- package/dist/commands/push.js +1 -1
- package/dist/commands/push.js.map +1 -1
- package/dist/commands/remove.js +63 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/commands/save.js +11 -17
- package/dist/commands/save.js.map +1 -1
- package/dist/commands/set.js +33 -0
- package/dist/commands/set.js.map +1 -0
- package/dist/commands/show.js +16 -94
- package/dist/commands/show.js.map +1 -1
- package/dist/commands/status.js +26 -701
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/uninstall.js +14 -427
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/constants/index.js +72 -16
- package/dist/constants/index.js.map +1 -1
- package/dist/core/add/add-conflict-handler.js +1 -8
- package/dist/core/add/add-conflict-handler.js.map +1 -1
- package/dist/core/add/add-pipeline.js +12 -10
- package/dist/core/add/add-pipeline.js.map +1 -1
- package/dist/core/add/add-to-source-pipeline.js +123 -0
- package/dist/core/add/add-to-source-pipeline.js.map +1 -0
- package/dist/core/add/package-index-updater.js +77 -78
- package/dist/core/add/package-index-updater.js.map +1 -1
- package/dist/core/add/platform-path-transformer.js +6 -4
- package/dist/core/add/platform-path-transformer.js.map +1 -1
- package/dist/core/add/source-collector.js +2 -3
- package/dist/core/add/source-collector.js.map +1 -1
- package/dist/core/apply/apply-pipeline.js +110 -0
- package/dist/core/apply/apply-pipeline.js.map +1 -0
- package/dist/core/dependency-resolver.js +263 -21
- package/dist/core/dependency-resolver.js.map +1 -1
- package/dist/core/discovery/file-discovery.js +1 -2
- package/dist/core/discovery/file-discovery.js.map +1 -1
- package/dist/core/discovery/platform-files-discovery.js +33 -18
- package/dist/core/discovery/platform-files-discovery.js.map +1 -1
- package/dist/core/flows/flow-executor.js +974 -0
- package/dist/core/flows/flow-executor.js.map +1 -0
- package/dist/core/flows/flow-inverter.js +442 -0
- package/dist/core/flows/flow-inverter.js.map +1 -0
- package/dist/core/flows/flow-key-extractor.js +101 -0
- package/dist/core/flows/flow-key-extractor.js.map +1 -0
- package/dist/core/flows/flow-key-mapper.js +382 -0
- package/dist/core/flows/flow-key-mapper.js.map +1 -0
- package/dist/core/flows/flow-transforms.js +632 -0
- package/dist/core/flows/flow-transforms.js.map +1 -0
- package/dist/core/flows/map-pipeline/context.js +73 -0
- package/dist/core/flows/map-pipeline/context.js.map +1 -0
- package/dist/core/flows/map-pipeline/index.js +156 -0
- package/dist/core/flows/map-pipeline/index.js.map +1 -0
- package/dist/core/flows/map-pipeline/operations/copy.js +104 -0
- package/dist/core/flows/map-pipeline/operations/copy.js.map +1 -0
- package/dist/core/flows/map-pipeline/operations/pipe.js +70 -0
- package/dist/core/flows/map-pipeline/operations/pipe.js.map +1 -0
- package/dist/core/flows/map-pipeline/operations/rename.js +102 -0
- package/dist/core/flows/map-pipeline/operations/rename.js.map +1 -0
- package/dist/core/flows/map-pipeline/operations/set.js +50 -0
- package/dist/core/flows/map-pipeline/operations/set.js.map +1 -0
- package/dist/core/flows/map-pipeline/operations/switch.js +79 -0
- package/dist/core/flows/map-pipeline/operations/switch.js.map +1 -0
- package/dist/core/flows/map-pipeline/operations/transform.js +543 -0
- package/dist/core/flows/map-pipeline/operations/transform.js.map +1 -0
- package/dist/core/flows/map-pipeline/operations/unset.js +65 -0
- package/dist/core/flows/map-pipeline/operations/unset.js.map +1 -0
- package/dist/core/flows/map-pipeline/types.js +8 -0
- package/dist/core/flows/map-pipeline/types.js.map +1 -0
- package/dist/core/flows/map-pipeline/utils.js +278 -0
- package/dist/core/flows/map-pipeline/utils.js.map +1 -0
- package/dist/core/flows/platform-converter.js +328 -0
- package/dist/core/flows/platform-converter.js.map +1 -0
- package/dist/core/flows/source-resolver.js +192 -0
- package/dist/core/flows/source-resolver.js.map +1 -0
- package/dist/core/flows/toml-domain-transforms.js +23 -0
- package/dist/core/flows/toml-domain-transforms.js.map +1 -0
- package/dist/core/install/bulk-install-pipeline.js +68 -7
- package/dist/core/install/bulk-install-pipeline.js.map +1 -1
- package/dist/core/install/canonical-plan.js +3 -3
- package/dist/core/install/canonical-plan.js.map +1 -1
- package/dist/core/install/dry-run.js +3 -3
- package/dist/core/install/dry-run.js.map +1 -1
- package/dist/core/install/flow-based-installer.js +1158 -0
- package/dist/core/install/flow-based-installer.js.map +1 -0
- package/dist/core/install/flow-workspace-tracker.js +111 -0
- package/dist/core/install/flow-workspace-tracker.js.map +1 -0
- package/dist/core/install/format-detector.js +228 -0
- package/dist/core/install/format-detector.js.map +1 -0
- package/dist/core/install/git-package-loader.js +20 -0
- package/dist/core/install/git-package-loader.js.map +1 -0
- package/dist/core/install/install-errors.js +1 -1
- package/dist/core/install/install-errors.js.map +1 -1
- package/dist/core/install/install-flow.js +34 -14
- package/dist/core/install/install-flow.js.map +1 -1
- package/dist/core/install/install-pipeline.js +52 -17
- package/dist/core/install/install-pipeline.js.map +1 -1
- package/dist/core/install/install-reporting.js +26 -8
- package/dist/core/install/install-reporting.js.map +1 -1
- package/dist/core/install/local-source-resolution.js +103 -0
- package/dist/core/install/local-source-resolution.js.map +1 -0
- package/dist/core/install/marketplace-handler.js +221 -0
- package/dist/core/install/marketplace-handler.js.map +1 -0
- package/dist/core/install/path-install-pipeline.js +241 -0
- package/dist/core/install/path-install-pipeline.js.map +1 -0
- package/dist/core/install/path-package-loader.js +116 -0
- package/dist/core/install/path-package-loader.js.map +1 -0
- package/dist/core/install/plugin-detector.js +72 -0
- package/dist/core/install/plugin-detector.js.map +1 -0
- package/dist/core/install/plugin-to-universal-converter.js +218 -0
- package/dist/core/install/plugin-to-universal-converter.js.map +1 -0
- package/dist/core/install/plugin-transformer.js +191 -0
- package/dist/core/install/plugin-transformer.js.map +1 -0
- package/dist/core/install/version-selection.js +1 -1
- package/dist/core/install/version-selection.js.map +1 -1
- package/dist/core/openpackage.js +40 -22
- package/dist/core/openpackage.js.map +1 -1
- package/dist/core/pack/pack-output.js +62 -0
- package/dist/core/pack/pack-output.js.map +1 -0
- package/dist/core/pack/pack-pipeline.js +186 -0
- package/dist/core/pack/pack-pipeline.js.map +1 -0
- package/dist/core/package-context.js +45 -70
- package/dist/core/package-context.js.map +1 -1
- package/dist/core/package-creation.js +203 -0
- package/dist/core/package-creation.js.map +1 -0
- package/dist/core/package.js +20 -6
- package/dist/core/package.js.map +1 -1
- package/dist/core/platforms.js +665 -209
- package/dist/core/platforms.js.map +1 -1
- package/dist/core/push/push-context.js +1 -1
- package/dist/core/push/push-context.js.map +1 -1
- package/dist/core/push/push-upload.js +2 -2
- package/dist/core/push/push-upload.js.map +1 -1
- package/dist/core/registry.js +6 -6
- package/dist/core/registry.js.map +1 -1
- package/dist/core/remote-pull.js +2 -2
- package/dist/core/remote-pull.js.map +1 -1
- package/dist/core/remove/removal-collector.js +52 -0
- package/dist/core/remove/removal-collector.js.map +1 -0
- package/dist/core/remove/removal-confirmation.js +39 -0
- package/dist/core/remove/removal-confirmation.js.map +1 -0
- package/dist/core/remove/remove-from-source-pipeline.js +173 -0
- package/dist/core/remove/remove-from-source-pipeline.js.map +1 -0
- package/dist/core/save/constants.js +3 -3
- package/dist/core/save/constants.js.map +1 -1
- package/dist/core/save/flow-based-saver.js +270 -0
- package/dist/core/save/flow-based-saver.js.map +1 -0
- package/dist/core/save/name-resolution.js +1 -1
- package/dist/core/save/name-resolution.js.map +1 -1
- package/dist/core/save/package-yml-generator.js +4 -5
- package/dist/core/save/package-yml-generator.js.map +1 -1
- package/dist/core/save/save-candidate-builder.js +215 -0
- package/dist/core/save/save-candidate-builder.js.map +1 -0
- package/dist/core/save/save-candidate-loader.js +12 -11
- package/dist/core/save/save-candidate-loader.js.map +1 -1
- package/dist/core/save/save-conflict-analyzer.js +150 -0
- package/dist/core/save/save-conflict-analyzer.js.map +1 -0
- package/dist/core/save/save-conflict-resolution.js +28 -14
- package/dist/core/save/save-conflict-resolution.js.map +1 -1
- package/dist/core/save/save-conflict-resolver.js +31 -275
- package/dist/core/save/save-conflict-resolver.js.map +1 -1
- package/dist/core/save/save-group-builder.js +52 -0
- package/dist/core/save/save-group-builder.js.map +1 -0
- package/dist/core/save/save-interactive-resolver.js +190 -0
- package/dist/core/save/save-interactive-resolver.js.map +1 -0
- package/dist/core/save/save-pipeline.js +58 -34
- package/dist/core/save/save-pipeline.js.map +1 -1
- package/dist/core/save/save-platform-handler.js +53 -0
- package/dist/core/save/save-platform-handler.js.map +1 -0
- package/dist/core/save/save-resolution-executor.js +145 -0
- package/dist/core/save/save-resolution-executor.js.map +1 -0
- package/dist/core/save/save-result-reporter.js +167 -0
- package/dist/core/save/save-result-reporter.js.map +1 -0
- package/dist/core/save/save-to-source-pipeline.js +154 -0
- package/dist/core/save/save-to-source-pipeline.js.map +1 -0
- package/dist/core/save/save-versioning.js +4 -4
- package/dist/core/save/save-versioning.js.map +1 -1
- package/dist/core/save/save-write-coordinator.js +204 -0
- package/dist/core/save/save-write-coordinator.js.map +1 -0
- package/dist/core/save/save-yml-resolution.js +28 -216
- package/dist/core/save/save-yml-resolution.js.map +1 -1
- package/dist/core/save/workspace-rename.js +7 -8
- package/dist/core/save/workspace-rename.js.map +1 -1
- package/dist/core/set/set-output.js +72 -0
- package/dist/core/set/set-output.js.map +1 -0
- package/dist/core/set/set-pipeline.js +361 -0
- package/dist/core/set/set-pipeline.js.map +1 -0
- package/dist/core/set/set-types.js +5 -0
- package/dist/core/set/set-types.js.map +1 -0
- package/dist/core/show/package-resolver.js +257 -0
- package/dist/core/show/package-resolver.js.map +1 -0
- package/dist/core/show/scope-discovery.js +165 -0
- package/dist/core/show/scope-discovery.js.map +1 -0
- package/dist/core/show/show-output.js +168 -0
- package/dist/core/show/show-output.js.map +1 -0
- package/dist/core/show/show-pipeline.js +113 -0
- package/dist/core/show/show-pipeline.js.map +1 -0
- package/dist/core/show/show-types.js +5 -0
- package/dist/core/show/show-types.js.map +1 -0
- package/dist/core/source-resolution/dependency-graph.js +104 -0
- package/dist/core/source-resolution/dependency-graph.js.map +1 -0
- package/dist/core/source-resolution/resolve-mutable-source.js +109 -0
- package/dist/core/source-resolution/resolve-mutable-source.js.map +1 -0
- package/dist/core/source-resolution/resolve-package-source.js +29 -0
- package/dist/core/source-resolution/resolve-package-source.js.map +1 -0
- package/dist/core/source-resolution/resolve-registry-version.js +35 -0
- package/dist/core/source-resolution/resolve-registry-version.js.map +1 -0
- package/dist/core/source-resolution/types.js.map +1 -0
- package/dist/core/status/status-file-discovery.js +23 -12
- package/dist/core/status/status-file-discovery.js.map +1 -1
- package/dist/core/status/status-pipeline.js +134 -0
- package/dist/core/status/status-pipeline.js.map +1 -0
- package/dist/core/sync/platform-sync-summary.js +27 -0
- package/dist/core/sync/platform-sync-summary.js.map +1 -0
- package/dist/core/uninstall/flow-aware-uninstaller.js +189 -0
- package/dist/core/uninstall/flow-aware-uninstaller.js.map +1 -0
- package/dist/core/uninstall/uninstall-file-discovery.js +11 -6
- package/dist/core/uninstall/uninstall-file-discovery.js.map +1 -1
- package/dist/core/uninstall/uninstall-pipeline.js +141 -0
- package/dist/core/uninstall/uninstall-pipeline.js.map +1 -0
- package/dist/core/universal-patterns.js +64 -0
- package/dist/core/universal-patterns.js.map +1 -0
- package/dist/index.js +99 -6
- package/dist/index.js.map +1 -1
- package/dist/types/flows.js +8 -0
- package/dist/types/flows.js.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/platform-flows.js +8 -0
- package/dist/types/platform-flows.js.map +1 -0
- package/dist/types/workspace-index.js +6 -0
- package/dist/types/workspace-index.js.map +1 -0
- package/dist/utils/custom-path-resolution.js +160 -0
- package/dist/utils/custom-path-resolution.js.map +1 -0
- package/dist/utils/dependency-coverage.js +1 -1
- package/dist/utils/dependency-coverage.js.map +1 -1
- package/dist/utils/file-processing.js +1 -1
- package/dist/utils/flow-index-installer.js +209 -0
- package/dist/utils/flow-index-installer.js.map +1 -0
- package/dist/utils/formatters.js +47 -1
- package/dist/utils/formatters.js.map +1 -1
- package/dist/utils/fs.js +17 -0
- package/dist/utils/fs.js.map +1 -1
- package/dist/utils/git-clone-registry.js +88 -0
- package/dist/utils/git-clone-registry.js.map +1 -0
- package/dist/utils/git-clone.js +69 -0
- package/dist/utils/git-clone.js.map +1 -0
- package/dist/utils/git-spec.js +96 -0
- package/dist/utils/git-spec.js.map +1 -0
- package/dist/utils/http-client.js +7 -0
- package/dist/utils/http-client.js.map +1 -1
- package/dist/utils/index-based-installer.js +356 -163
- package/dist/utils/index-based-installer.js.map +1 -1
- package/dist/utils/install-conflict-handler.js +2 -2
- package/dist/utils/install-conflict-handler.js.map +1 -1
- package/dist/utils/install-file-discovery.js +18 -13
- package/dist/utils/install-file-discovery.js.map +1 -1
- package/dist/utils/install-helpers.js +43 -20
- package/dist/utils/install-helpers.js.map +1 -1
- package/dist/utils/jsonc.js +23 -1
- package/dist/utils/jsonc.js.map +1 -1
- package/dist/utils/manifest-paths.js +1 -1
- package/dist/utils/manifest-paths.js.map +1 -1
- package/dist/utils/markdown-frontmatter.js +46 -0
- package/dist/utils/markdown-frontmatter.js.map +1 -1
- package/dist/utils/package-copy.js +5 -103
- package/dist/utils/package-copy.js.map +1 -1
- package/dist/utils/package-filters.js +9 -105
- package/dist/utils/package-filters.js.map +1 -1
- package/dist/utils/package-index-yml.js +27 -6
- package/dist/utils/package-index-yml.js.map +1 -1
- package/dist/utils/package-input.js +98 -0
- package/dist/utils/package-input.js.map +1 -0
- package/dist/utils/package-management.js +80 -28
- package/dist/utils/package-management.js.map +1 -1
- package/dist/utils/package-name-resolution.js +327 -0
- package/dist/utils/package-name-resolution.js.map +1 -0
- package/dist/utils/package-name.js +18 -16
- package/dist/utils/package-name.js.map +1 -1
- package/dist/utils/package-versioning.js +2 -33
- package/dist/utils/package-versioning.js.map +1 -1
- package/dist/utils/package-yml.js +19 -28
- package/dist/utils/package-yml.js.map +1 -1
- package/dist/utils/path-resolution.js +102 -0
- package/dist/utils/path-resolution.js.map +1 -0
- package/dist/utils/paths.js +6 -6
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/platform-file.js +36 -24
- package/dist/utils/platform-file.js.map +1 -1
- package/dist/utils/platform-mapper.js +222 -68
- package/dist/utils/platform-mapper.js.map +1 -1
- package/dist/utils/platform-root-files.js +44 -0
- package/dist/utils/platform-root-files.js.map +1 -0
- package/dist/utils/platform-utils.js +35 -54
- package/dist/utils/platform-utils.js.map +1 -1
- package/dist/utils/platform-yaml-merge.js +20 -140
- package/dist/utils/platform-yaml-merge.js.map +1 -1
- package/dist/utils/prompts.js +92 -7
- package/dist/utils/prompts.js.map +1 -1
- package/dist/utils/registry-entry-filter.js +50 -27
- package/dist/utils/registry-entry-filter.js.map +1 -1
- package/dist/utils/registry-paths.js +5 -4
- package/dist/utils/registry-paths.js.map +1 -1
- package/dist/utils/scope-resolution.js +156 -0
- package/dist/utils/scope-resolution.js.map +1 -0
- package/dist/utils/source-mutability.js +15 -0
- package/dist/utils/source-mutability.js.map +1 -0
- package/dist/utils/tarball.js +29 -4
- package/dist/utils/tarball.js.map +1 -1
- package/dist/utils/version-ranges.js +1 -32
- package/dist/utils/version-ranges.js.map +1 -1
- package/dist/utils/workspace-index-helpers.js +28 -0
- package/dist/utils/workspace-index-helpers.js.map +1 -0
- package/dist/utils/workspace-index-ownership.js +100 -0
- package/dist/utils/workspace-index-ownership.js.map +1 -0
- package/dist/utils/workspace-index-yml.js +173 -0
- package/dist/utils/workspace-index-yml.js.map +1 -0
- package/examples/custom-subdirs-platform.jsonc +157 -0
- package/package.json +7 -2
- package/platforms.jsonc +531 -84
- package/schemas/map-pipeline-v1.json +256 -0
- package/schemas/platforms-v1.json +400 -0
- package/specs/README.md +88 -0
- package/specs/add/README.md +166 -0
- package/specs/agents-claude.md +570 -0
- package/specs/agents-opencode.md +622 -0
- package/specs/apply/README.md +21 -0
- package/specs/apply/apply-behavior.md +58 -0
- package/specs/apply/apply-command.md +51 -0
- package/specs/apply/conflicts.md +41 -0
- package/specs/apply/index-effects.md +81 -0
- package/specs/architecture.md +107 -0
- package/specs/auth/README.md +17 -0
- package/specs/auth/auth-http-contract.md +25 -0
- package/specs/auth/cli/credentials.md +39 -0
- package/specs/auth/cli/login.md +32 -0
- package/specs/auth/cli/logout.md +16 -0
- package/specs/claude-mcp.md +1065 -0
- package/specs/claude-plugins-marketplace.md +363 -0
- package/specs/claude-plugins.md +413 -0
- package/specs/cli-options.md +52 -0
- package/specs/codex-mcp.md +114 -0
- package/specs/commands-overview.md +175 -0
- package/specs/directory-layout.md +95 -0
- package/specs/install/README.md +12 -4
- package/specs/install/git-sources.md +230 -0
- package/specs/install/install-behavior.md +483 -73
- package/specs/install/package-yml-canonical.md +67 -35
- package/specs/install/version-resolution.md +69 -115
- package/specs/new/README.md +769 -0
- package/specs/new/SUMMARY.md +310 -0
- package/specs/new/scope-behavior.md +793 -0
- package/specs/pack/README.md +77 -0
- package/specs/pack/package-name-resolution.md +330 -0
- package/specs/package/README.md +18 -17
- package/specs/package/nested-packages-and-parent-packages.md +32 -31
- package/specs/package/package-index-yml.md +95 -101
- package/specs/package/package-root-layout.md +64 -46
- package/specs/package/registry-payload-and-copy.md +50 -44
- package/specs/package/universal-content.md +33 -56
- package/specs/package-sources.md +248 -0
- package/specs/platforms/README.md +52 -0
- package/specs/platforms/configuration.md +571 -0
- package/specs/platforms/detection.md +552 -0
- package/specs/platforms/directory-layout.md +599 -0
- package/specs/platforms/examples.md +1146 -0
- package/specs/platforms/flow-reference.md +1240 -0
- package/specs/platforms/flows.md +1488 -0
- package/specs/platforms/map-pipeline.md +801 -0
- package/specs/platforms/overview.md +349 -0
- package/specs/platforms/specification.md +700 -0
- package/specs/platforms/troubleshooting.md +697 -0
- package/specs/platforms/universal-converter.md +520 -0
- package/specs/push/README.md +1 -0
- package/specs/push/push-behavior.md +11 -3
- package/specs/push/push-remote-upload.md +1 -1
- package/specs/push/push-scoping.md +1 -1
- package/specs/push/push-version-selection.md +1 -1
- package/specs/registry.md +111 -0
- package/specs/remove/README.md +257 -0
- package/specs/save/README.md +21 -17
- package/specs/save/save-conflict-resolution.md +205 -83
- package/specs/save/save-file-discovery.md +6 -4
- package/specs/save/save-frontmatter-overrides.md +11 -15
- package/specs/save/save-modes-inputs.md +9 -39
- package/specs/save/save-naming-scoping.md +4 -4
- package/specs/save/save-package-detection.md +13 -13
- package/specs/save/save-registry-sync.md +16 -106
- package/specs/save/save-versioning.md +80 -0
- package/specs/scope-management.md +92 -0
- package/specs/set/README.md +520 -0
- package/specs/set/set-behavior.md +563 -0
- package/specs/show/README.md +483 -0
- package/specs/show/show-remote.md +494 -0
- package/specs/status/README.md +38 -0
- package/specs/uninstall/README.md +231 -0
- package/dist/commands/duplicate.js +0 -69
- package/dist/commands/duplicate.js.map +0 -1
- package/dist/commands/init.js +0 -117
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/prune.js +0 -357
- package/dist/commands/prune.js.map +0 -1
- package/dist/commands/tui.js +0 -61
- package/dist/commands/tui.js.map +0 -1
- package/dist/core/install/index.js +0 -3
- package/dist/core/install/index.js.map +0 -1
- package/dist/core/push/push-single-file.js +0 -56
- package/dist/core/push/push-single-file.js.map +0 -1
- package/dist/core/save/package-detection.js +0 -147
- package/dist/core/save/package-detection.js.map +0 -1
- package/dist/core/save/save-single-file.js +0 -124
- package/dist/core/save/save-single-file.js.map +0 -1
- package/dist/core/token-store.js +0 -73
- package/dist/core/token-store.js.map +0 -1
- package/dist/tui/app.js +0 -95
- package/dist/tui/app.js.map +0 -1
- package/dist/tui/components/package-list.js +0 -73
- package/dist/tui/components/package-list.js.map +0 -1
- package/dist/tui/controller.js +0 -365
- package/dist/tui/controller.js.map +0 -1
- package/dist/tui/index.js +0 -12
- package/dist/tui/index.js.map +0 -1
- package/dist/tui/services/file-index.js +0 -64
- package/dist/tui/services/file-index.js.map +0 -1
- package/dist/tui/services/packages.js +0 -18
- package/dist/tui/services/packages.js.map +0 -1
- package/dist/tui/services/save.js +0 -21
- package/dist/tui/services/save.js.map +0 -1
- package/dist/tui/state/app-state.js +0 -15
- package/dist/tui/state/app-state.js.map +0 -1
- package/dist/tui/state.js +0 -17
- package/dist/tui/state.js.map +0 -1
- package/dist/tui/types.js.map +0 -1
- package/dist/tui/views/add-file-modal.js +0 -129
- package/dist/tui/views/add-file-modal.js.map +0 -1
- package/dist/tui/views/file-preview.js +0 -44
- package/dist/tui/views/file-preview.js.map +0 -1
- package/dist/tui/views/list-packages.js +0 -73
- package/dist/tui/views/list-packages.js.map +0 -1
- package/dist/tui/views/main-menu.js +0 -29
- package/dist/tui/views/main-menu.js.map +0 -1
- package/dist/tui/views/manage-view.js +0 -81
- package/dist/tui/views/manage-view.js.map +0 -1
- package/dist/tui/views/package-hub.js +0 -120
- package/dist/tui/views/package-hub.js.map +0 -1
- package/dist/tui/views/placeholder.js +0 -24
- package/dist/tui/views/placeholder.js.map +0 -1
- package/dist/utils/bun-bootstrap.js +0 -72
- package/dist/utils/bun-bootstrap.js.map +0 -1
- package/dist/utils/entity-id.js +0 -19
- package/dist/utils/entity-id.js.map +0 -1
- package/dist/utils/package-local-files.js +0 -5
- package/dist/utils/package-local-files.js.map +0 -1
- package/dist/utils/path-matching.js +0 -74
- package/dist/utils/path-matching.js.map +0 -1
- package/dist/utils/root-file-operations.js +0 -39
- package/dist/utils/root-file-operations.js.map +0 -1
- package/dist/utils/root-file-transformer.js +0 -27
- package/dist/utils/root-file-transformer.js.map +0 -1
- package/dist/utils/yaml-frontmatter.js +0 -25
- package/dist/utils/yaml-frontmatter.js.map +0 -1
- package/specs/auth/auth-device-flow.md +0 -70
- package/specs/login/login-device-flow.md +0 -70
- package/specs/platforms.md +0 -193
- package/specs/save-pack-versioning.md +0 -224
- package/specs/save-pack.md +0 -68
- /package/dist/{tui → core/source-resolution}/types.js +0 -0
|
@@ -0,0 +1,1488 @@
|
|
|
1
|
+
# Platform Flows
|
|
2
|
+
|
|
3
|
+
## What are Flows?
|
|
4
|
+
|
|
5
|
+
**Flows** are declarative transformation rules that define bidirectional mappings between universal package content and platform-specific formats.
|
|
6
|
+
|
|
7
|
+
**Two types of flows:**
|
|
8
|
+
- **Export flows** (`export`): Package → Workspace (used by `install` and `apply`)
|
|
9
|
+
- **Import flows** (`import`): Workspace → Package (used by `save`)
|
|
10
|
+
|
|
11
|
+
**Core concept:** Explicit bidirectional transformations without automatic inversion.
|
|
12
|
+
|
|
13
|
+
## Flow Types
|
|
14
|
+
|
|
15
|
+
### Export Flows
|
|
16
|
+
|
|
17
|
+
Transform package files into workspace files (Package → Workspace).
|
|
18
|
+
|
|
19
|
+
**Used by:** `opkg install`, `opkg apply`
|
|
20
|
+
|
|
21
|
+
**Schema:**
|
|
22
|
+
```typescript
|
|
23
|
+
interface ExportFlow {
|
|
24
|
+
from: string | string[] // Source pattern in package (required)
|
|
25
|
+
to: string | MultiTarget // Target path in workspace (required)
|
|
26
|
+
|
|
27
|
+
// Optional transformation fields
|
|
28
|
+
map?: Operation[] // Map pipeline operations (includes $pipe for transforms)
|
|
29
|
+
pick?: string[] // Extract specific keys
|
|
30
|
+
omit?: string[] // Exclude keys
|
|
31
|
+
path?: string // JSONPath extraction
|
|
32
|
+
embed?: string // Embed under key
|
|
33
|
+
section?: string // TOML/INI section
|
|
34
|
+
when?: Condition // Conditional execution
|
|
35
|
+
merge?: "deep"|"shallow"|"replace"|"composite" // Merge strategy
|
|
36
|
+
namespace?: boolean | string // Namespace isolation
|
|
37
|
+
handler?: string // Custom handler
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Import Flows
|
|
42
|
+
|
|
43
|
+
Transform workspace files back into package files (Workspace → Package).
|
|
44
|
+
|
|
45
|
+
**Used by:** `opkg save`
|
|
46
|
+
|
|
47
|
+
**Schema:**
|
|
48
|
+
```typescript
|
|
49
|
+
interface ImportFlow {
|
|
50
|
+
from: string | string[] // Source pattern in workspace (required)
|
|
51
|
+
to: string | MultiTarget // Target path in package (required)
|
|
52
|
+
|
|
53
|
+
// Optional transformation fields (same as export)
|
|
54
|
+
map?: Operation[] // Map pipeline operations (includes $pipe for transforms)
|
|
55
|
+
pick?: string[]
|
|
56
|
+
omit?: string[]
|
|
57
|
+
path?: string
|
|
58
|
+
embed?: string
|
|
59
|
+
section?: string
|
|
60
|
+
when?: Condition
|
|
61
|
+
merge?: "deep"|"shallow"|"replace"|"composite"
|
|
62
|
+
namespace?: boolean | string
|
|
63
|
+
handler?: string
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Key difference:** Import flows only process files tracked in the workspace index (files previously exported).
|
|
68
|
+
|
|
69
|
+
### Required Fields
|
|
70
|
+
|
|
71
|
+
#### `from` (string)
|
|
72
|
+
|
|
73
|
+
Source file pattern relative to package root.
|
|
74
|
+
|
|
75
|
+
**Simple path:**
|
|
76
|
+
```jsonc
|
|
77
|
+
{ "from": "rules/code-quality.md" }
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Single-level glob:**
|
|
81
|
+
```jsonc
|
|
82
|
+
{ "from": "rules/*.md" } // All .md files in rules/ only (not subdirs)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Recursive glob:**
|
|
86
|
+
```jsonc
|
|
87
|
+
{ "from": "rules/**/*.md" } // All .md files in rules/ and subdirectories
|
|
88
|
+
{ "from": "skills/**/*" } // All files of any type, recursively
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Examples:**
|
|
92
|
+
```jsonc
|
|
93
|
+
{ "from": "config.yaml" } // Single file
|
|
94
|
+
{ "from": "rules/*.md" } // Top-level only
|
|
95
|
+
{ "from": "rules/**/*.md" } // Recursive with extension filter
|
|
96
|
+
{ "from": "skills/**/*" } // All files recursively
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Array with priority (first match wins):**
|
|
100
|
+
```jsonc
|
|
101
|
+
{ "from": ["mcp.jsonc", "mcp.json"] } // Prefer .jsonc, fallback to .json
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
When an array of patterns is provided:
|
|
105
|
+
- Patterns are tried in order (first = highest priority)
|
|
106
|
+
- First matching pattern is used
|
|
107
|
+
- Subsequent patterns are skipped
|
|
108
|
+
- Warning logged if multiple patterns match
|
|
109
|
+
- Useful for format preferences or platform-specific fallbacks
|
|
110
|
+
|
|
111
|
+
**Array pattern use cases:**
|
|
112
|
+
```jsonc
|
|
113
|
+
// Format preference
|
|
114
|
+
{ "from": ["mcp.jsonc", "mcp.json"] }
|
|
115
|
+
|
|
116
|
+
// Platform-specific fallback
|
|
117
|
+
{ "from": ["config.cursor.json", "config.json"] }
|
|
118
|
+
|
|
119
|
+
// Version fallback
|
|
120
|
+
{ "from": ["config.v2.yaml", "config.yaml"] }
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
#### `to` (string | object)
|
|
124
|
+
|
|
125
|
+
Target file path relative to workspace root.
|
|
126
|
+
|
|
127
|
+
**Simple target:**
|
|
128
|
+
```jsonc
|
|
129
|
+
{ "to": ".cursor/rules/*.mdc" } // Single-level glob with extension change
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**Recursive target:**
|
|
133
|
+
```jsonc
|
|
134
|
+
{ "to": ".cursor/rules/**/*.mdc" } // Preserves directory structure
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Multi-target object:**
|
|
138
|
+
```jsonc
|
|
139
|
+
{
|
|
140
|
+
"to": {
|
|
141
|
+
".cursor/mcp.json": { "namespace": true, "merge": "deep" },
|
|
142
|
+
".opencode/config.json": { "embed": "mcp", "merge": "deep" },
|
|
143
|
+
".codex/config.toml": { "section": "mcp", "merge": "deep" }
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Glob Patterns
|
|
149
|
+
|
|
150
|
+
The flow system supports powerful glob patterns for file matching:
|
|
151
|
+
|
|
152
|
+
### Single-Level Glob (`*`)
|
|
153
|
+
|
|
154
|
+
Matches files in a single directory level only:
|
|
155
|
+
|
|
156
|
+
```jsonc
|
|
157
|
+
{
|
|
158
|
+
"from": "rules/*.md",
|
|
159
|
+
"to": ".cursor/rules/*.md"
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Package structure:**
|
|
164
|
+
```
|
|
165
|
+
rules/
|
|
166
|
+
├── typescript.md ← Matched
|
|
167
|
+
├── python.md ← Matched
|
|
168
|
+
└── advanced/
|
|
169
|
+
└── generics.md ← NOT matched (in subdirectory)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**Result:**
|
|
173
|
+
```
|
|
174
|
+
.cursor/rules/
|
|
175
|
+
├── typescript.md
|
|
176
|
+
└── python.md
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Recursive Glob (`**`)
|
|
180
|
+
|
|
181
|
+
Matches files in all subdirectories recursively:
|
|
182
|
+
|
|
183
|
+
```jsonc
|
|
184
|
+
{
|
|
185
|
+
"from": "rules/**/*.md",
|
|
186
|
+
"to": ".cursor/rules/**/*.md"
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**Package structure:**
|
|
191
|
+
```
|
|
192
|
+
rules/
|
|
193
|
+
├── typescript.md
|
|
194
|
+
├── python.md
|
|
195
|
+
└── advanced/
|
|
196
|
+
├── generics.md
|
|
197
|
+
└── types/
|
|
198
|
+
└── unions.md
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Result (preserves structure):**
|
|
202
|
+
```
|
|
203
|
+
.cursor/rules/
|
|
204
|
+
├── typescript.md
|
|
205
|
+
├── python.md
|
|
206
|
+
└── advanced/
|
|
207
|
+
├── generics.md
|
|
208
|
+
└── types/
|
|
209
|
+
└── unions.md
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**Key features:**
|
|
213
|
+
- `**` means "any number of directories" (including zero)
|
|
214
|
+
- Directory structure is fully preserved in target
|
|
215
|
+
- Relative paths maintained
|
|
216
|
+
|
|
217
|
+
### All Files Recursively (`**/*`)
|
|
218
|
+
|
|
219
|
+
Matches all files of any type:
|
|
220
|
+
|
|
221
|
+
```jsonc
|
|
222
|
+
{
|
|
223
|
+
"from": "skills/**/*",
|
|
224
|
+
"to": ".claude/skills/**/*"
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**Package structure:**
|
|
229
|
+
```
|
|
230
|
+
skills/
|
|
231
|
+
├── code-review/
|
|
232
|
+
│ ├── analyze.md
|
|
233
|
+
│ ├── config.json
|
|
234
|
+
│ └── helpers/
|
|
235
|
+
│ ├── utils.ts
|
|
236
|
+
│ └── types.d.ts
|
|
237
|
+
└── testing/
|
|
238
|
+
└── test-gen.md
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**Result (all files copied):**
|
|
242
|
+
```
|
|
243
|
+
.claude/skills/
|
|
244
|
+
├── code-review/
|
|
245
|
+
│ ├── analyze.md
|
|
246
|
+
│ ├── config.json
|
|
247
|
+
│ └── helpers/
|
|
248
|
+
│ ├── utils.ts
|
|
249
|
+
│ └── types.d.ts
|
|
250
|
+
└── testing/
|
|
251
|
+
└── test-gen.md
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
**Use cases:**
|
|
255
|
+
- Mixed file types (`.md`, `.json`, `.ts`, etc.)
|
|
256
|
+
- Complete directory replication
|
|
257
|
+
- Skills, tools, or utility directories
|
|
258
|
+
|
|
259
|
+
### Extension Mapping with Recursive Globs
|
|
260
|
+
|
|
261
|
+
Change file extensions while preserving structure:
|
|
262
|
+
|
|
263
|
+
```jsonc
|
|
264
|
+
{
|
|
265
|
+
"from": "rules/**/*.md",
|
|
266
|
+
"to": ".cursor/rules/**/*.mdc"
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
**Package:**
|
|
271
|
+
```
|
|
272
|
+
rules/
|
|
273
|
+
├── typescript.md
|
|
274
|
+
└── advanced/
|
|
275
|
+
└── generics.md
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
**Result:**
|
|
279
|
+
```
|
|
280
|
+
.cursor/rules/
|
|
281
|
+
├── typescript.mdc ← Extension changed
|
|
282
|
+
└── advanced/
|
|
283
|
+
└── generics.mdc ← Extension changed
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
**Extension mapping rules:**
|
|
287
|
+
- Source extension specified: `/**/*.md`
|
|
288
|
+
- Target extension specified: `/**/*.mdc`
|
|
289
|
+
- All matched files get extension changed
|
|
290
|
+
- Works at any depth
|
|
291
|
+
|
|
292
|
+
### Common Patterns
|
|
293
|
+
|
|
294
|
+
#### Pattern 1: Recursive Rules with Extension Mapping
|
|
295
|
+
```jsonc
|
|
296
|
+
{
|
|
297
|
+
"from": "rules/**/*.md",
|
|
298
|
+
"to": ".cursor/rules/**/*.mdc"
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
Use for: Cursor-style rules with nested structure
|
|
302
|
+
|
|
303
|
+
#### Pattern 2: Recursive Commands
|
|
304
|
+
```jsonc
|
|
305
|
+
{
|
|
306
|
+
"from": "commands/**/*.md",
|
|
307
|
+
"to": ".agent/workflows/**/*.md"
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
Use for: Commands organized in subdirectories
|
|
311
|
+
|
|
312
|
+
#### Pattern 3: Complete Skills Directory
|
|
313
|
+
```jsonc
|
|
314
|
+
{
|
|
315
|
+
"from": "skills/**/*",
|
|
316
|
+
"to": ".claude/skills/**/*"
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
Use for: Mixed file types with full structure
|
|
320
|
+
|
|
321
|
+
#### Pattern 4: Recursive Agents
|
|
322
|
+
```jsonc
|
|
323
|
+
{
|
|
324
|
+
"from": "agents/**/*.md",
|
|
325
|
+
"to": ".factory/droids/**/*.md"
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
Use for: Agent definitions with categories
|
|
329
|
+
|
|
330
|
+
### Glob Matching Behavior
|
|
331
|
+
|
|
332
|
+
#### Empty Matches
|
|
333
|
+
|
|
334
|
+
If no files match the pattern:
|
|
335
|
+
- Flow succeeds with warning
|
|
336
|
+
- No error thrown
|
|
337
|
+
- Warning: "No files matched pattern"
|
|
338
|
+
|
|
339
|
+
```jsonc
|
|
340
|
+
{
|
|
341
|
+
"from": "nonexistent/**/*.md",
|
|
342
|
+
"to": ".cursor/rules/**/*.md"
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
**Result:** Success, 0 files processed, warning logged
|
|
346
|
+
|
|
347
|
+
#### Case Sensitivity
|
|
348
|
+
|
|
349
|
+
Glob patterns are case-sensitive:
|
|
350
|
+
- `Rules/*.md` ≠ `rules/*.md`
|
|
351
|
+
- `README.md` ≠ `readme.md`
|
|
352
|
+
|
|
353
|
+
#### Hidden Files
|
|
354
|
+
|
|
355
|
+
Glob patterns do NOT match hidden files by default:
|
|
356
|
+
- `.gitignore` not matched by `*`
|
|
357
|
+
- `.config/**/*` not matched by `**/*`
|
|
358
|
+
|
|
359
|
+
To match hidden files explicitly:
|
|
360
|
+
```jsonc
|
|
361
|
+
{ "from": ".config/**/*" }
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Best Practices
|
|
365
|
+
|
|
366
|
+
#### 1. Use `**` for Nested Structures
|
|
367
|
+
|
|
368
|
+
**Good:**
|
|
369
|
+
```jsonc
|
|
370
|
+
{ "from": "rules/**/*.md" }
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
**Bad (misses nested files):**
|
|
374
|
+
```jsonc
|
|
375
|
+
{ "from": "rules/*.md" }
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
#### 2. Match Target Pattern to Source
|
|
379
|
+
|
|
380
|
+
**Good (consistent structure):**
|
|
381
|
+
```jsonc
|
|
382
|
+
{
|
|
383
|
+
"from": "rules/**/*.md",
|
|
384
|
+
"to": ".cursor/rules/**/*.md"
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
**Bad (structure mismatch):**
|
|
389
|
+
```jsonc
|
|
390
|
+
{
|
|
391
|
+
"from": "rules/**/*.md",
|
|
392
|
+
"to": ".cursor/rules/*.md" // Wrong: single-level target
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
#### 3. Use `**/*` for Mixed Types
|
|
397
|
+
|
|
398
|
+
**Good (all files):**
|
|
399
|
+
```jsonc
|
|
400
|
+
{ "from": "skills/**/*" }
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
**Bad (only markdown):**
|
|
404
|
+
```jsonc
|
|
405
|
+
{ "from": "skills/**/*.md" }
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
#### 4. Prefer Recursive Patterns
|
|
409
|
+
|
|
410
|
+
Recommended approach:
|
|
411
|
+
```jsonc
|
|
412
|
+
{ "from": "rules/**/*.md" }
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
## Execution Pipeline
|
|
416
|
+
|
|
417
|
+
Flows execute through a multi-stage pipeline:
|
|
418
|
+
|
|
419
|
+
```
|
|
420
|
+
1. Load → Read source file, detect format
|
|
421
|
+
2. Extract → Apply JSONPath if specified
|
|
422
|
+
3. Filter → Apply pick/omit on keys
|
|
423
|
+
4. Map → Transform keys/values (includes $pipe operations)
|
|
424
|
+
5. Namespace → Wrap in namespace if enabled
|
|
425
|
+
6. Embed → Wrap under key/section if specified
|
|
426
|
+
7. Merge → Merge with existing target
|
|
427
|
+
8. Write → Serialize and write to disk
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Stage 1: Load
|
|
431
|
+
|
|
432
|
+
**Auto-detects format** from extension or content:
|
|
433
|
+
- `.json`, `.jsonc` → JSON parser
|
|
434
|
+
- `.yaml`, `.yml` → YAML parser
|
|
435
|
+
- `.toml` → TOML parser
|
|
436
|
+
- `.md` → Markdown with frontmatter parser
|
|
437
|
+
|
|
438
|
+
**Example:**
|
|
439
|
+
```yaml
|
|
440
|
+
# Source: config.yaml
|
|
441
|
+
theme: dark
|
|
442
|
+
fontSize: 14
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
### Stage 2: Extract (optional)
|
|
446
|
+
|
|
447
|
+
Apply **JSONPath** to extract subset:
|
|
448
|
+
|
|
449
|
+
```jsonc
|
|
450
|
+
{
|
|
451
|
+
"from": "config.yaml",
|
|
452
|
+
"to": ".cursor/config.json",
|
|
453
|
+
"path": "$.editor" // Extract only editor config
|
|
454
|
+
}
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
```yaml
|
|
458
|
+
# Source
|
|
459
|
+
editor:
|
|
460
|
+
theme: dark
|
|
461
|
+
fontSize: 14
|
|
462
|
+
terminal:
|
|
463
|
+
shell: bash
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
**Result after extraction:**
|
|
467
|
+
```json
|
|
468
|
+
{
|
|
469
|
+
"theme": "dark",
|
|
470
|
+
"fontSize": 14
|
|
471
|
+
}
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
### Stage 3: Filter (optional)
|
|
475
|
+
|
|
476
|
+
**Pick** (whitelist) specific keys:
|
|
477
|
+
```jsonc
|
|
478
|
+
{
|
|
479
|
+
"pick": ["theme", "fontSize"] // Only include these keys
|
|
480
|
+
}
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
**Omit** (blacklist) specific keys:
|
|
484
|
+
```jsonc
|
|
485
|
+
{
|
|
486
|
+
"omit": ["internal", "debug"] // Exclude these keys
|
|
487
|
+
}
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
**Cannot use both** `pick` and `omit` in same flow.
|
|
491
|
+
|
|
492
|
+
### Stage 4: Map (optional)
|
|
493
|
+
|
|
494
|
+
Transform document fields using a **MongoDB-inspired pipeline**:
|
|
495
|
+
|
|
496
|
+
```jsonc
|
|
497
|
+
{
|
|
498
|
+
"map": [
|
|
499
|
+
{ "$set": { "name": "$$filename" } },
|
|
500
|
+
{ "$rename": { "mcp": "mcpServers" } },
|
|
501
|
+
{ "$unset": "deprecated" }
|
|
502
|
+
]
|
|
503
|
+
}
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
**Map Pipeline** is an array of operations that execute sequentially on the document:
|
|
507
|
+
|
|
508
|
+
**Seven core operations:**
|
|
509
|
+
1. **`$set`** - Set field values (supports context variables like `$$filename`)
|
|
510
|
+
2. **`$rename`** - Rename fields (supports wildcards)
|
|
511
|
+
3. **`$unset`** - Remove fields
|
|
512
|
+
4. **`$switch`** - Pattern-based value replacement
|
|
513
|
+
5. **`$pipeline`** - Multi-step field transformation (MongoDB-aligned)
|
|
514
|
+
6. **`$copy`** - Copy field with optional transformation
|
|
515
|
+
7. **`$pipe`** - Apply transform registry operations (format conversions, validations)
|
|
516
|
+
|
|
517
|
+
**Example transformation:**
|
|
518
|
+
```jsonc
|
|
519
|
+
{
|
|
520
|
+
"map": [
|
|
521
|
+
{ "$set": { "name": "$$filename" } },
|
|
522
|
+
{
|
|
523
|
+
"$switch": {
|
|
524
|
+
"field": "model",
|
|
525
|
+
"cases": [
|
|
526
|
+
{ "pattern": "anthropic/claude-sonnet-*", "value": "sonnet" }
|
|
527
|
+
],
|
|
528
|
+
"default": "inherit"
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
]
|
|
532
|
+
}
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
**Before:**
|
|
536
|
+
```yaml
|
|
537
|
+
model: anthropic/claude-sonnet-4-20250514
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
**After:**
|
|
541
|
+
```yaml
|
|
542
|
+
name: code-reviewer
|
|
543
|
+
model: sonnet
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
See [Map Pipeline](./map-pipeline.md) for complete operation reference and [Flow Reference](./flow-reference.md#map-pipeline) for usage in flows.
|
|
547
|
+
|
|
548
|
+
### Stage 5: Transform (optional)
|
|
549
|
+
|
|
550
|
+
Apply **transform registry operations** using the `$pipe` operation within the map pipeline:
|
|
551
|
+
|
|
552
|
+
```jsonc
|
|
553
|
+
{
|
|
554
|
+
"map": [
|
|
555
|
+
{ "$rename": { "old": "new" } },
|
|
556
|
+
{ "$pipe": ["json-to-toml"] } // Apply transforms from registry
|
|
557
|
+
]
|
|
558
|
+
}
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
**Available transforms:**
|
|
562
|
+
- Format converters: `jsonc`, `yaml`, `toml`, `json-to-toml`, `toml-to-json`, `xml`, `ini`
|
|
563
|
+
- Filtering: `filter-comments`, `filter-empty`, `filter-null`
|
|
564
|
+
- Markdown: `sections`, `frontmatter`, `body`
|
|
565
|
+
- Validation: `validate`, `validate-schema(path)`
|
|
566
|
+
|
|
567
|
+
See [Map Pipeline](./map-pipeline.md#7-pipe---apply-transform-registry-operations) for `$pipe` details and
|
|
568
|
+
[Flow Reference](./flow-reference.md#built-in-transforms) for all available transforms.
|
|
569
|
+
|
|
570
|
+
### Stage 6: Namespace (optional)
|
|
571
|
+
|
|
572
|
+
Wrap content under package-specific namespace:
|
|
573
|
+
|
|
574
|
+
```jsonc
|
|
575
|
+
{
|
|
576
|
+
"namespace": true // or string for custom namespace key
|
|
577
|
+
}
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
**Before:**
|
|
581
|
+
```json
|
|
582
|
+
{ "servers": { "db": {} } }
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
**After:**
|
|
586
|
+
```json
|
|
587
|
+
{
|
|
588
|
+
"packages": {
|
|
589
|
+
"@user/package-name": {
|
|
590
|
+
"servers": { "db": {} }
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
**Purpose:** Prevent collisions when multiple packages target same file.
|
|
597
|
+
|
|
598
|
+
### Stage 7: Embed (optional)
|
|
599
|
+
|
|
600
|
+
Wrap content under specified key:
|
|
601
|
+
|
|
602
|
+
**JSON embedding:**
|
|
603
|
+
```jsonc
|
|
604
|
+
{
|
|
605
|
+
"embed": "mcp"
|
|
606
|
+
}
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
```json
|
|
610
|
+
// Before: { "servers": {} }
|
|
611
|
+
// After: { "mcp": { "servers": {} } }
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
**TOML sections:**
|
|
615
|
+
```jsonc
|
|
616
|
+
{
|
|
617
|
+
"section": "mcp_servers"
|
|
618
|
+
}
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
```toml
|
|
622
|
+
# Before: [servers]
|
|
623
|
+
# After: [mcp_servers]
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
### Stage 8: Merge
|
|
627
|
+
|
|
628
|
+
Combine with existing target file:
|
|
629
|
+
|
|
630
|
+
**Strategies:**
|
|
631
|
+
- `"deep"` - Recursively merge nested objects (default for objects)
|
|
632
|
+
- `"shallow"` - Merge only top-level keys
|
|
633
|
+
- `"replace"` - Overwrite entire file (default for arrays/primitives)
|
|
634
|
+
|
|
635
|
+
```jsonc
|
|
636
|
+
{
|
|
637
|
+
"merge": "deep"
|
|
638
|
+
}
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
**Existing target:**
|
|
642
|
+
```json
|
|
643
|
+
{ "servers": { "db": {} } }
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
**Source content:**
|
|
647
|
+
```json
|
|
648
|
+
{ "servers": { "api": {} } }
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
**Result:**
|
|
652
|
+
```json
|
|
653
|
+
{
|
|
654
|
+
"servers": {
|
|
655
|
+
"db": {}, // Preserved from target
|
|
656
|
+
"api": {} // Added from source
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
### Stage 9: Write
|
|
662
|
+
|
|
663
|
+
Serialize to target format and write to disk:
|
|
664
|
+
- Detects target format from extension
|
|
665
|
+
- Creates directories as needed
|
|
666
|
+
- Atomic write (temp file + rename)
|
|
667
|
+
|
|
668
|
+
## Format Conversion
|
|
669
|
+
|
|
670
|
+
Automatic bidirectional conversion between formats:
|
|
671
|
+
|
|
672
|
+
### YAML to JSON
|
|
673
|
+
|
|
674
|
+
```jsonc
|
|
675
|
+
{
|
|
676
|
+
"from": "config.yaml",
|
|
677
|
+
"to": ".cursor/config.json"
|
|
678
|
+
}
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
**Source (YAML):**
|
|
682
|
+
```yaml
|
|
683
|
+
theme: dark
|
|
684
|
+
fontSize: 14
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
**Target (JSON):**
|
|
688
|
+
```json
|
|
689
|
+
{
|
|
690
|
+
"theme": "dark",
|
|
691
|
+
"fontSize": 14
|
|
692
|
+
}
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
### JSONC to JSON
|
|
696
|
+
|
|
697
|
+
```jsonc
|
|
698
|
+
{
|
|
699
|
+
"from": "settings.jsonc",
|
|
700
|
+
"to": ".cursor/settings.json"
|
|
701
|
+
}
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
Comments are automatically stripped:
|
|
705
|
+
|
|
706
|
+
**Source (JSONC):**
|
|
707
|
+
```jsonc
|
|
708
|
+
{
|
|
709
|
+
// User theme
|
|
710
|
+
"theme": "dark"
|
|
711
|
+
}
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
**Target (JSON):**
|
|
715
|
+
```json
|
|
716
|
+
{
|
|
717
|
+
"theme": "dark"
|
|
718
|
+
}
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
### JSON to TOML
|
|
722
|
+
|
|
723
|
+
```jsonc
|
|
724
|
+
{
|
|
725
|
+
"from": "config.json",
|
|
726
|
+
"to": ".codex/config.toml"
|
|
727
|
+
}
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
**Source (JSON):**
|
|
731
|
+
```json
|
|
732
|
+
{
|
|
733
|
+
"server": {
|
|
734
|
+
"host": "localhost",
|
|
735
|
+
"port": 3000
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
```
|
|
739
|
+
|
|
740
|
+
**Target (TOML):**
|
|
741
|
+
```toml
|
|
742
|
+
[server]
|
|
743
|
+
host = "localhost"
|
|
744
|
+
port = 3000
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
### Markdown Frontmatter
|
|
748
|
+
|
|
749
|
+
Transforms YAML frontmatter while preserving body:
|
|
750
|
+
|
|
751
|
+
```jsonc
|
|
752
|
+
{
|
|
753
|
+
"from": "agents/**/*.md",
|
|
754
|
+
"to": ".claude/agents/**/*.md",
|
|
755
|
+
"map": {
|
|
756
|
+
"role": "type"
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
**Source:**
|
|
762
|
+
```markdown
|
|
763
|
+
---
|
|
764
|
+
role: assistant
|
|
765
|
+
model: claude-sonnet-4
|
|
766
|
+
---
|
|
767
|
+
# Agent Instructions
|
|
768
|
+
Help users with code reviews.
|
|
769
|
+
```
|
|
770
|
+
|
|
771
|
+
**Target:**
|
|
772
|
+
```markdown
|
|
773
|
+
---
|
|
774
|
+
type: assistant
|
|
775
|
+
model: claude-sonnet-4
|
|
776
|
+
---
|
|
777
|
+
# Agent Instructions
|
|
778
|
+
Help users with code reviews.
|
|
779
|
+
```
|
|
780
|
+
|
|
781
|
+
**Body is unchanged.**
|
|
782
|
+
|
|
783
|
+
## Merge Strategies
|
|
784
|
+
|
|
785
|
+
### Deep Merge
|
|
786
|
+
|
|
787
|
+
Recursively merge nested structures:
|
|
788
|
+
|
|
789
|
+
```jsonc
|
|
790
|
+
{ "merge": "deep" }
|
|
791
|
+
```
|
|
792
|
+
|
|
793
|
+
**Use when:**
|
|
794
|
+
- Composing configurations from multiple packages
|
|
795
|
+
- Preserving existing nested settings
|
|
796
|
+
- Adding keys at any depth
|
|
797
|
+
|
|
798
|
+
**Example:**
|
|
799
|
+
```json
|
|
800
|
+
// Target (existing)
|
|
801
|
+
{ "editor": { "theme": "dark", "fontSize": 12 } }
|
|
802
|
+
|
|
803
|
+
// Source (new)
|
|
804
|
+
{ "editor": { "fontSize": 14, "tabSize": 2 } }
|
|
805
|
+
|
|
806
|
+
// Result
|
|
807
|
+
{ "editor": { "theme": "dark", "fontSize": 14, "tabSize": 2 } }
|
|
808
|
+
```
|
|
809
|
+
|
|
810
|
+
### Shallow Merge
|
|
811
|
+
|
|
812
|
+
Merge only top-level keys:
|
|
813
|
+
|
|
814
|
+
```jsonc
|
|
815
|
+
{ "merge": "shallow" }
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
**Use when:**
|
|
819
|
+
- Replacing entire nested objects
|
|
820
|
+
- Avoiding deep merge complexity
|
|
821
|
+
- Clear ownership of nested structures
|
|
822
|
+
|
|
823
|
+
**Example:**
|
|
824
|
+
```json
|
|
825
|
+
// Target (existing)
|
|
826
|
+
{ "editor": { "theme": "dark" }, "terminal": { "shell": "bash" } }
|
|
827
|
+
|
|
828
|
+
// Source (new)
|
|
829
|
+
{ "editor": { "fontSize": 14 } }
|
|
830
|
+
|
|
831
|
+
// Result
|
|
832
|
+
{ "editor": { "fontSize": 14 }, "terminal": { "shell": "bash" } }
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
Note: `editor` object replaced entirely, `terminal` preserved.
|
|
836
|
+
|
|
837
|
+
### Replace
|
|
838
|
+
|
|
839
|
+
Completely overwrite target:
|
|
840
|
+
|
|
841
|
+
```jsonc
|
|
842
|
+
{ "merge": "replace" }
|
|
843
|
+
```
|
|
844
|
+
|
|
845
|
+
**Use when:**
|
|
846
|
+
- Source is authoritative
|
|
847
|
+
- Target should be discarded
|
|
848
|
+
- No composition needed
|
|
849
|
+
|
|
850
|
+
**Example:**
|
|
851
|
+
```json
|
|
852
|
+
// Target (existing) - ignored
|
|
853
|
+
{ "old": "config" }
|
|
854
|
+
|
|
855
|
+
// Source (new)
|
|
856
|
+
{ "new": "config" }
|
|
857
|
+
|
|
858
|
+
// Result
|
|
859
|
+
{ "new": "config" }
|
|
860
|
+
```
|
|
861
|
+
|
|
862
|
+
|
|
863
|
+
### Composite
|
|
864
|
+
|
|
865
|
+
Compose multiple package contributions using delimiters:
|
|
866
|
+
|
|
867
|
+
```jsonc
|
|
868
|
+
{ "merge": "composite" }
|
|
869
|
+
```
|
|
870
|
+
|
|
871
|
+
**Use when:**
|
|
872
|
+
- Multiple packages contribute to same text file
|
|
873
|
+
- Each package needs its own section
|
|
874
|
+
- Sections should be independently updatable
|
|
875
|
+
- Content outside package sections must be preserved
|
|
876
|
+
|
|
877
|
+
**Supported formats:**
|
|
878
|
+
- Markdown files with HTML comment delimiters
|
|
879
|
+
- Any text-based format with comment support
|
|
880
|
+
|
|
881
|
+
**Example:**
|
|
882
|
+
```markdown
|
|
883
|
+
// Target (existing)
|
|
884
|
+
# Instructions
|
|
885
|
+
|
|
886
|
+
<!-- package: @user/package-a -->
|
|
887
|
+
Instructions from Package A
|
|
888
|
+
<!-- -->
|
|
889
|
+
|
|
890
|
+
// Source (new package @user/package-b)
|
|
891
|
+
Instructions from Package B
|
|
892
|
+
|
|
893
|
+
// Result
|
|
894
|
+
# Instructions
|
|
895
|
+
|
|
896
|
+
<!-- package: @user/package-a -->
|
|
897
|
+
Instructions from Package A
|
|
898
|
+
<!-- -->
|
|
899
|
+
|
|
900
|
+
<!-- package: @user/package-b -->
|
|
901
|
+
Instructions from Package B
|
|
902
|
+
<!-- -->
|
|
903
|
+
```
|
|
904
|
+
|
|
905
|
+
**Update behavior:**
|
|
906
|
+
```markdown
|
|
907
|
+
// Target (existing)
|
|
908
|
+
<!-- package: @user/package-a -->
|
|
909
|
+
Old instructions from Package A
|
|
910
|
+
<!-- -->
|
|
911
|
+
|
|
912
|
+
<!-- package: @user/package-b -->
|
|
913
|
+
Instructions from Package B
|
|
914
|
+
<!-- -->
|
|
915
|
+
|
|
916
|
+
// Source (updated package @user/package-a)
|
|
917
|
+
New instructions from Package A
|
|
918
|
+
|
|
919
|
+
// Result
|
|
920
|
+
<!-- package: @user/package-a -->
|
|
921
|
+
New instructions from Package A
|
|
922
|
+
<!-- -->
|
|
923
|
+
|
|
924
|
+
<!-- package: @user/package-b -->
|
|
925
|
+
Instructions from Package B
|
|
926
|
+
<!-- -->
|
|
927
|
+
```
|
|
928
|
+
|
|
929
|
+
**Key features:**
|
|
930
|
+
- Each package's content wrapped in `<!-- package: name -->` ... `<!-- -->` markers
|
|
931
|
+
- Updates replace only that package's section
|
|
932
|
+
- Other packages' sections preserved
|
|
933
|
+
- Manual edits outside markers preserved
|
|
934
|
+
- Uninstalling removes only that package's section
|
|
935
|
+
|
|
936
|
+
**Common use cases:**
|
|
937
|
+
- Root files (AGENTS.md, CLAUDE.md, QWEN.md, WARP.md)
|
|
938
|
+
- Shared instruction files
|
|
939
|
+
- Multi-package documentation
|
|
940
|
+
- Composable configuration narratives
|
|
941
|
+
|
|
942
|
+
### Priority-Based Merging
|
|
943
|
+
|
|
944
|
+
When multiple packages write to same file:
|
|
945
|
+
|
|
946
|
+
**Priority order:**
|
|
947
|
+
1. Workspace content (highest)
|
|
948
|
+
2. Direct dependencies
|
|
949
|
+
3. Nested dependencies (shallower = higher priority)
|
|
950
|
+
|
|
951
|
+
**Conflicts:**
|
|
952
|
+
- Last writer wins (by priority)
|
|
953
|
+
- Warnings logged with package info
|
|
954
|
+
|
|
955
|
+
**Example:**
|
|
956
|
+
```
|
|
957
|
+
Package A (direct): { "servers": { "db": { "host": "localhost" } } }
|
|
958
|
+
Package B (direct): { "servers": { "db": { "port": 5432 } } }
|
|
959
|
+
|
|
960
|
+
Result: { "servers": { "db": { "host": "localhost", "port": 5432 } } }
|
|
961
|
+
Warning: "Package B merging with Package A in .cursor/mcp.json"
|
|
962
|
+
```
|
|
963
|
+
|
|
964
|
+
## Key Tracking for Uninstall
|
|
965
|
+
|
|
966
|
+
When flows use `merge: 'deep'` or `merge: 'shallow'`, the system automatically tracks which keys each package contributes to the target file. This enables precise removal during uninstall.
|
|
967
|
+
|
|
968
|
+
### How It Works
|
|
969
|
+
|
|
970
|
+
**During installation:**
|
|
971
|
+
1. Flow executes and merges content into target file
|
|
972
|
+
2. System extracts all top-level and nested keys written
|
|
973
|
+
3. Keys stored in workspace index with dot notation
|
|
974
|
+
4. Keys represent **transformed** paths (after `map` operations)
|
|
975
|
+
|
|
976
|
+
**During uninstall:**
|
|
977
|
+
1. Read tracked keys from workspace index
|
|
978
|
+
2. Load target file
|
|
979
|
+
3. Remove only the tracked keys
|
|
980
|
+
4. Clean up empty parent objects
|
|
981
|
+
5. Delete file if empty, otherwise save updated content
|
|
982
|
+
|
|
983
|
+
### Example: Key Transformation
|
|
984
|
+
|
|
985
|
+
Flow with key transformation:
|
|
986
|
+
|
|
987
|
+
```jsonc
|
|
988
|
+
{
|
|
989
|
+
"from": "mcp.jsonc",
|
|
990
|
+
"to": ".opencode/opencode.json",
|
|
991
|
+
"map": {
|
|
992
|
+
"mcpServers.*": "mcp.*" // Transform keys!
|
|
993
|
+
},
|
|
994
|
+
"merge": "deep"
|
|
995
|
+
}
|
|
996
|
+
```
|
|
997
|
+
|
|
998
|
+
**Package source:**
|
|
999
|
+
```json
|
|
1000
|
+
{
|
|
1001
|
+
"mcpServers": {
|
|
1002
|
+
"server1": { "url": "http://localhost:3000" },
|
|
1003
|
+
"server2": { "url": "http://localhost:4000" }
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
```
|
|
1007
|
+
|
|
1008
|
+
**Workspace index (after install):**
|
|
1009
|
+
```yaml
|
|
1010
|
+
files:
|
|
1011
|
+
mcp.jsonc:
|
|
1012
|
+
- target: .opencode/opencode.json
|
|
1013
|
+
merge: deep
|
|
1014
|
+
keys:
|
|
1015
|
+
- mcp.server1 # Note: transformed key, not mcpServers.server1
|
|
1016
|
+
- mcp.server2
|
|
1017
|
+
```
|
|
1018
|
+
|
|
1019
|
+
**Target file after install:**
|
|
1020
|
+
```json
|
|
1021
|
+
{
|
|
1022
|
+
"mcp": {
|
|
1023
|
+
"server1": { "url": "http://localhost:3000" },
|
|
1024
|
+
"server2": { "url": "http://localhost:4000" }
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
```
|
|
1028
|
+
|
|
1029
|
+
**On uninstall:**
|
|
1030
|
+
- Keys `mcp.server1` and `mcp.server2` are removed
|
|
1031
|
+
- If no other packages contributed to `mcp`, the entire object is removed
|
|
1032
|
+
- Other top-level keys in the file are preserved
|
|
1033
|
+
|
|
1034
|
+
### Why Track Transformed Keys?
|
|
1035
|
+
|
|
1036
|
+
**The challenge:** Flows can transform keys using `map`:
|
|
1037
|
+
- `servers.*` → `database.*`
|
|
1038
|
+
- `config.*` → `settings.*`
|
|
1039
|
+
- `mcpServers.*` → `mcp.*`
|
|
1040
|
+
|
|
1041
|
+
**The solution:** Track the **output** keys (after transformation), not the input keys. This works regardless of transformation complexity and allows precise removal without needing the original source.
|
|
1042
|
+
|
|
1043
|
+
### When Keys Are Tracked
|
|
1044
|
+
|
|
1045
|
+
**Keys tracked when:**
|
|
1046
|
+
- ✅ Flow uses `merge: 'deep'`
|
|
1047
|
+
- ✅ Flow uses `merge: 'shallow'`
|
|
1048
|
+
- ✅ Target file will be shared by multiple packages
|
|
1049
|
+
|
|
1050
|
+
**Keys NOT tracked when:**
|
|
1051
|
+
- ❌ `merge: 'replace'` - entire file owned by one package
|
|
1052
|
+
- ❌ `merge: 'composite'` - delimiter-based tracking used
|
|
1053
|
+
- ❌ Simple file copy - no merge involved
|
|
1054
|
+
|
|
1055
|
+
### Key Notation
|
|
1056
|
+
|
|
1057
|
+
Keys use dot notation for nested paths:
|
|
1058
|
+
|
|
1059
|
+
```
|
|
1060
|
+
mcp.server1 → { mcp: { server1: {...} } }
|
|
1061
|
+
editor.fontSize → { editor: { fontSize: 14 } }
|
|
1062
|
+
servers.db.host → { servers: { db: { host: "..." } } }
|
|
1063
|
+
```
|
|
1064
|
+
|
|
1065
|
+
### Parent Cleanup
|
|
1066
|
+
|
|
1067
|
+
When removing keys, empty parent objects are automatically cleaned up:
|
|
1068
|
+
|
|
1069
|
+
```json
|
|
1070
|
+
// Before uninstall
|
|
1071
|
+
{
|
|
1072
|
+
"mcp": {
|
|
1073
|
+
"server1": { "url": "..." },
|
|
1074
|
+
"server2": { "url": "..." }
|
|
1075
|
+
},
|
|
1076
|
+
"other": { "config": "..." }
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
// After uninstalling package with keys [mcp.server1, mcp.server2]
|
|
1080
|
+
{
|
|
1081
|
+
"other": { "config": "..." }
|
|
1082
|
+
}
|
|
1083
|
+
// Note: entire "mcp" object removed because it became empty
|
|
1084
|
+
```
|
|
1085
|
+
|
|
1086
|
+
### Multi-Package Scenarios
|
|
1087
|
+
|
|
1088
|
+
When multiple packages contribute to the same file:
|
|
1089
|
+
|
|
1090
|
+
**Package A installed:**
|
|
1091
|
+
```json
|
|
1092
|
+
{ "mcp": { "server1": {...}, "server2": {...} } }
|
|
1093
|
+
```
|
|
1094
|
+
|
|
1095
|
+
**Package B installed (same file, different keys):**
|
|
1096
|
+
```json
|
|
1097
|
+
{ "mcp": { "server1": {...}, "server2": {...}, "server3": {...} } }
|
|
1098
|
+
```
|
|
1099
|
+
|
|
1100
|
+
**Uninstall Package A:**
|
|
1101
|
+
- Only removes keys tracked for Package A
|
|
1102
|
+
- Package B's keys remain intact
|
|
1103
|
+
- File not deleted because content remains
|
|
1104
|
+
|
|
1105
|
+
**Index tracking:**
|
|
1106
|
+
```yaml
|
|
1107
|
+
packages:
|
|
1108
|
+
package-a:
|
|
1109
|
+
files:
|
|
1110
|
+
mcp.jsonc:
|
|
1111
|
+
- target: .opencode/opencode.json
|
|
1112
|
+
merge: deep
|
|
1113
|
+
keys: [mcp.server1, mcp.server2]
|
|
1114
|
+
|
|
1115
|
+
package-b:
|
|
1116
|
+
files:
|
|
1117
|
+
mcp.jsonc:
|
|
1118
|
+
- target: .opencode/opencode.json
|
|
1119
|
+
merge: deep
|
|
1120
|
+
keys: [mcp.server3]
|
|
1121
|
+
```
|
|
1122
|
+
|
|
1123
|
+
See [Uninstall](../uninstall/README.md) for complete uninstall behavior.
|
|
1124
|
+
|
|
1125
|
+
## Conditional Execution
|
|
1126
|
+
|
|
1127
|
+
Execute flows based on conditions:
|
|
1128
|
+
|
|
1129
|
+
### Platform Check
|
|
1130
|
+
|
|
1131
|
+
```jsonc
|
|
1132
|
+
{
|
|
1133
|
+
"from": "mcp.jsonc",
|
|
1134
|
+
"to": ".cursor/mcp.json",
|
|
1135
|
+
"when": { "platform": "cursor" }
|
|
1136
|
+
}
|
|
1137
|
+
```
|
|
1138
|
+
|
|
1139
|
+
Flow executes only if Cursor platform is detected.
|
|
1140
|
+
|
|
1141
|
+
### File Existence
|
|
1142
|
+
|
|
1143
|
+
```jsonc
|
|
1144
|
+
{
|
|
1145
|
+
"from": "config.yaml",
|
|
1146
|
+
"to": ".cursor/config.json",
|
|
1147
|
+
"when": { "exists": ".cursor" }
|
|
1148
|
+
}
|
|
1149
|
+
```
|
|
1150
|
+
|
|
1151
|
+
Flow executes only if `.cursor` directory exists.
|
|
1152
|
+
|
|
1153
|
+
### Key Check
|
|
1154
|
+
|
|
1155
|
+
```jsonc
|
|
1156
|
+
{
|
|
1157
|
+
"from": "settings.jsonc",
|
|
1158
|
+
"to": ".cursor/settings.json",
|
|
1159
|
+
"when": { "key": "cursor" }
|
|
1160
|
+
}
|
|
1161
|
+
```
|
|
1162
|
+
|
|
1163
|
+
Flow executes only if source has `cursor` key.
|
|
1164
|
+
|
|
1165
|
+
### Value Check
|
|
1166
|
+
|
|
1167
|
+
```jsonc
|
|
1168
|
+
{
|
|
1169
|
+
"from": "config.yaml",
|
|
1170
|
+
"to": ".cursor/dev.json",
|
|
1171
|
+
"when": {
|
|
1172
|
+
"key": "env",
|
|
1173
|
+
"equals": "development"
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
```
|
|
1177
|
+
|
|
1178
|
+
Flow executes only if `env === "development"`.
|
|
1179
|
+
|
|
1180
|
+
### Composite Conditions
|
|
1181
|
+
|
|
1182
|
+
**AND condition:**
|
|
1183
|
+
```jsonc
|
|
1184
|
+
{
|
|
1185
|
+
"when": {
|
|
1186
|
+
"and": [
|
|
1187
|
+
{ "platform": "cursor" },
|
|
1188
|
+
{ "exists": "mcp.jsonc" }
|
|
1189
|
+
]
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
```
|
|
1193
|
+
|
|
1194
|
+
**OR condition:**
|
|
1195
|
+
```jsonc
|
|
1196
|
+
{
|
|
1197
|
+
"when": {
|
|
1198
|
+
"or": [
|
|
1199
|
+
{ "platform": "cursor" },
|
|
1200
|
+
{ "platform": "claude" }
|
|
1201
|
+
]
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
```
|
|
1205
|
+
|
|
1206
|
+
## Multi-Target Flows
|
|
1207
|
+
|
|
1208
|
+
One source file can flow to multiple targets with different transforms:
|
|
1209
|
+
|
|
1210
|
+
```jsonc
|
|
1211
|
+
{
|
|
1212
|
+
"from": "mcp.jsonc",
|
|
1213
|
+
"to": {
|
|
1214
|
+
".cursor/mcp.json": {
|
|
1215
|
+
"namespace": true,
|
|
1216
|
+
"merge": "deep"
|
|
1217
|
+
},
|
|
1218
|
+
".opencode/opencode.json": {
|
|
1219
|
+
"embed": "mcp",
|
|
1220
|
+
"merge": "deep"
|
|
1221
|
+
},
|
|
1222
|
+
".codex/config.toml": {
|
|
1223
|
+
"path": "$.servers",
|
|
1224
|
+
"section": "mcp_servers",
|
|
1225
|
+
"merge": "deep"
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
```
|
|
1230
|
+
|
|
1231
|
+
**Behavior:**
|
|
1232
|
+
- Source parsed once
|
|
1233
|
+
- Each target gets independent transformation
|
|
1234
|
+
- Failures isolated per target
|
|
1235
|
+
|
|
1236
|
+
## Namespace Isolation
|
|
1237
|
+
|
|
1238
|
+
Prevent package collisions:
|
|
1239
|
+
|
|
1240
|
+
```jsonc
|
|
1241
|
+
{
|
|
1242
|
+
"from": "mcp.jsonc",
|
|
1243
|
+
"to": ".cursor/mcp.json",
|
|
1244
|
+
"namespace": true,
|
|
1245
|
+
"merge": "deep"
|
|
1246
|
+
}
|
|
1247
|
+
```
|
|
1248
|
+
|
|
1249
|
+
**Package A content:**
|
|
1250
|
+
```json
|
|
1251
|
+
{ "servers": { "db": {} } }
|
|
1252
|
+
```
|
|
1253
|
+
|
|
1254
|
+
**Package B content:**
|
|
1255
|
+
```json
|
|
1256
|
+
{ "servers": { "api": {} } }
|
|
1257
|
+
```
|
|
1258
|
+
|
|
1259
|
+
**Result:**
|
|
1260
|
+
```json
|
|
1261
|
+
{
|
|
1262
|
+
"packages": {
|
|
1263
|
+
"@user/package-a": {
|
|
1264
|
+
"servers": { "db": {} }
|
|
1265
|
+
},
|
|
1266
|
+
"@user/package-b": {
|
|
1267
|
+
"servers": { "api": {} }
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
```
|
|
1272
|
+
|
|
1273
|
+
**Custom namespace key:**
|
|
1274
|
+
```jsonc
|
|
1275
|
+
{ "namespace": "extensions" }
|
|
1276
|
+
```
|
|
1277
|
+
|
|
1278
|
+
```json
|
|
1279
|
+
{
|
|
1280
|
+
"extensions": {
|
|
1281
|
+
"@user/package-a": { /* ... */ }
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
```
|
|
1285
|
+
|
|
1286
|
+
## Performance Optimizations
|
|
1287
|
+
|
|
1288
|
+
### Simple File Copy Bypass
|
|
1289
|
+
|
|
1290
|
+
Flows with no transforms skip pipeline:
|
|
1291
|
+
|
|
1292
|
+
```jsonc
|
|
1293
|
+
{
|
|
1294
|
+
"from": "rules/**/*.md",
|
|
1295
|
+
"to": ".cursor/rules/**/*.mdc"
|
|
1296
|
+
}
|
|
1297
|
+
```
|
|
1298
|
+
|
|
1299
|
+
**Optimized:** Direct file copy for simple extension changes, no content parsing.
|
|
1300
|
+
|
|
1301
|
+
### Parser Caching
|
|
1302
|
+
|
|
1303
|
+
Format parsers cached per file type within execution context.
|
|
1304
|
+
|
|
1305
|
+
### Single Source Parse
|
|
1306
|
+
|
|
1307
|
+
Multi-target flows parse source once:
|
|
1308
|
+
|
|
1309
|
+
```jsonc
|
|
1310
|
+
{
|
|
1311
|
+
"from": "config.yaml",
|
|
1312
|
+
"to": {
|
|
1313
|
+
".cursor/config.json": {},
|
|
1314
|
+
".claude/config.json": {}
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
```
|
|
1318
|
+
|
|
1319
|
+
**Optimized:** YAML parsed once, serialized twice.
|
|
1320
|
+
|
|
1321
|
+
### Lazy Evaluation
|
|
1322
|
+
|
|
1323
|
+
Conditional flows evaluated before loading source:
|
|
1324
|
+
|
|
1325
|
+
```jsonc
|
|
1326
|
+
{
|
|
1327
|
+
"from": "large-file.json",
|
|
1328
|
+
"to": ".cursor/config.json",
|
|
1329
|
+
"when": { "platform": "claude" } // False for Cursor
|
|
1330
|
+
}
|
|
1331
|
+
```
|
|
1332
|
+
|
|
1333
|
+
**Optimized:** File not loaded if condition false.
|
|
1334
|
+
|
|
1335
|
+
## Error Handling
|
|
1336
|
+
|
|
1337
|
+
### Parse Errors
|
|
1338
|
+
|
|
1339
|
+
```
|
|
1340
|
+
Error: Failed to parse config.yaml: Invalid YAML syntax at line 5
|
|
1341
|
+
```
|
|
1342
|
+
|
|
1343
|
+
**Solution:** Fix source file syntax.
|
|
1344
|
+
|
|
1345
|
+
### Transform Errors
|
|
1346
|
+
|
|
1347
|
+
```
|
|
1348
|
+
Error: Transform 'unknown-transform' not found in pipe
|
|
1349
|
+
Available: [jsonc, yaml, toml, merge, ...]
|
|
1350
|
+
```
|
|
1351
|
+
|
|
1352
|
+
**Solution:** Use valid transform name from built-ins.
|
|
1353
|
+
|
|
1354
|
+
### Path Errors
|
|
1355
|
+
|
|
1356
|
+
```
|
|
1357
|
+
Error: JSONPath '$.invalid..path' is invalid
|
|
1358
|
+
```
|
|
1359
|
+
|
|
1360
|
+
**Solution:** Fix JSONPath syntax.
|
|
1361
|
+
|
|
1362
|
+
### Merge Conflicts
|
|
1363
|
+
|
|
1364
|
+
```
|
|
1365
|
+
Warning: Package @user/b overwrites content from @user/a in .cursor/mcp.json
|
|
1366
|
+
```
|
|
1367
|
+
|
|
1368
|
+
**Solution:** Check priority order or use namespace isolation.
|
|
1369
|
+
|
|
1370
|
+
## Best Practices
|
|
1371
|
+
|
|
1372
|
+
### 1. Start Simple
|
|
1373
|
+
|
|
1374
|
+
```jsonc
|
|
1375
|
+
{
|
|
1376
|
+
"from": "rules/*.md",
|
|
1377
|
+
"to": ".cursor/rules/*.md"
|
|
1378
|
+
}
|
|
1379
|
+
```
|
|
1380
|
+
|
|
1381
|
+
Add transforms only when needed.
|
|
1382
|
+
|
|
1383
|
+
### 2. Test Incrementally
|
|
1384
|
+
|
|
1385
|
+
```bash
|
|
1386
|
+
opkg install @user/package --dry-run
|
|
1387
|
+
```
|
|
1388
|
+
|
|
1389
|
+
Preview changes before applying.
|
|
1390
|
+
|
|
1391
|
+
### 3. Use Merge for Composition
|
|
1392
|
+
|
|
1393
|
+
```jsonc
|
|
1394
|
+
{
|
|
1395
|
+
"from": "mcp.jsonc",
|
|
1396
|
+
"to": ".cursor/mcp.json",
|
|
1397
|
+
"merge": "deep"
|
|
1398
|
+
}
|
|
1399
|
+
```
|
|
1400
|
+
|
|
1401
|
+
Allow multiple packages to compose content.
|
|
1402
|
+
|
|
1403
|
+
### 4. Isolate with Namespaces
|
|
1404
|
+
|
|
1405
|
+
```jsonc
|
|
1406
|
+
{
|
|
1407
|
+
"namespace": true,
|
|
1408
|
+
"merge": "deep"
|
|
1409
|
+
}
|
|
1410
|
+
```
|
|
1411
|
+
|
|
1412
|
+
Prevent unintended conflicts.
|
|
1413
|
+
|
|
1414
|
+
### 5. Document Complex Flows
|
|
1415
|
+
|
|
1416
|
+
```jsonc
|
|
1417
|
+
{
|
|
1418
|
+
// Transform MCP config for Cursor with namespacing
|
|
1419
|
+
"from": "mcp.jsonc",
|
|
1420
|
+
"to": ".cursor/mcp.json",
|
|
1421
|
+
"namespace": true,
|
|
1422
|
+
"merge": "deep"
|
|
1423
|
+
}
|
|
1424
|
+
```
|
|
1425
|
+
|
|
1426
|
+
## Export/Import Architecture
|
|
1427
|
+
|
|
1428
|
+
### Explicit Bidirectional Flows
|
|
1429
|
+
|
|
1430
|
+
Instead of automatic flow inversion, OpenPackage uses **explicit export and import flows**:
|
|
1431
|
+
|
|
1432
|
+
**Export flow (package → workspace):**
|
|
1433
|
+
```jsonc
|
|
1434
|
+
{
|
|
1435
|
+
"export": [
|
|
1436
|
+
{
|
|
1437
|
+
"from": ["mcp.jsonc", "mcp.json"],
|
|
1438
|
+
"to": ".claude/.mcp.json",
|
|
1439
|
+
"map": [
|
|
1440
|
+
{ "$rename": { "mcp": "mcpServers" } }
|
|
1441
|
+
]
|
|
1442
|
+
}
|
|
1443
|
+
]
|
|
1444
|
+
}
|
|
1445
|
+
```
|
|
1446
|
+
|
|
1447
|
+
**Import flow (workspace → package):**
|
|
1448
|
+
```jsonc
|
|
1449
|
+
{
|
|
1450
|
+
"import": [
|
|
1451
|
+
{
|
|
1452
|
+
"from": [".claude/.mcp.json", ".claude/mcp.json"],
|
|
1453
|
+
"to": "mcp.jsonc",
|
|
1454
|
+
"map": [{ "$rename": { "mcpServers": "mcp" } }]
|
|
1455
|
+
}
|
|
1456
|
+
]
|
|
1457
|
+
}
|
|
1458
|
+
```
|
|
1459
|
+
|
|
1460
|
+
### Benefits of Explicit Flows
|
|
1461
|
+
|
|
1462
|
+
1. **No inversion complexity** - Both directions explicitly defined
|
|
1463
|
+
2. **Asymmetric transforms** - Different logic per direction (e.g., add metadata on export, strip on import)
|
|
1464
|
+
3. **Array patterns both ways** - Full support for format preferences in both directions
|
|
1465
|
+
4. **Lossy transforms** - Can use transforms that can't be automatically inverted
|
|
1466
|
+
5. **Clear intent** - Reading config shows exactly what happens in each direction
|
|
1467
|
+
|
|
1468
|
+
### Universal Converter
|
|
1469
|
+
|
|
1470
|
+
The **Universal Platform Converter** allows installing platform-specific packages to any platform using **import flows** instead of flow inversion.
|
|
1471
|
+
|
|
1472
|
+
**Example scenario:**
|
|
1473
|
+
- Install a Claude Code plugin (with `.claude/` directories)
|
|
1474
|
+
- To Cursor platform (needs `.cursor/` directories)
|
|
1475
|
+
- System uses Claude's **import flows** to convert `.claude/` → universal
|
|
1476
|
+
- Then applies Cursor's **export flows** to convert universal → `.cursor/`
|
|
1477
|
+
|
|
1478
|
+
**No flow inversion needed** - Import flows are explicitly defined for this purpose.
|
|
1479
|
+
|
|
1480
|
+
**See:** [Universal Converter](./universal-converter.md) for complete details on cross-platform conversion.
|
|
1481
|
+
|
|
1482
|
+
## Next Steps
|
|
1483
|
+
|
|
1484
|
+
- **View complete flow options:** See [Flow Reference](./flow-reference.md)
|
|
1485
|
+
- **Cross-platform conversion:** See [Universal Converter](./universal-converter.md)
|
|
1486
|
+
- **See practical examples:** See [Examples](./examples.md)
|
|
1487
|
+
- **Learn key mapping:** See [Flow Reference](./flow-reference.md#key-mapping)
|
|
1488
|
+
- **Debug flows:** See [Troubleshooting](./troubleshooting.md)
|