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,700 @@
|
|
|
1
|
+
# Platform Specification
|
|
2
|
+
|
|
3
|
+
Technical requirements and contracts for the platform system. This document uses SHALL/MUST for normative requirements with scenario-based specifications.
|
|
4
|
+
|
|
5
|
+
## Platform Configuration Requirements
|
|
6
|
+
|
|
7
|
+
### Requirement: Platform Configuration Schema
|
|
8
|
+
|
|
9
|
+
Each platform entry in `platforms.jsonc` SHALL have the following structure:
|
|
10
|
+
|
|
11
|
+
- `name` (string): Human-readable display name
|
|
12
|
+
- `rootDir` (string): Platform root directory (e.g., `.cursor`, `.claude`)
|
|
13
|
+
- `rootFile?` (string): Optional root file at project root (e.g., `CLAUDE.md`, `QWEN.md`)
|
|
14
|
+
- `aliases?` (string[]): Optional CLI aliases
|
|
15
|
+
- `enabled?` (boolean): Whether platform is enabled (default: `true`)
|
|
16
|
+
- `export?` (Flow[]): Export flows (package → workspace, used by install/apply)
|
|
17
|
+
- `import?` (Flow[]): Import flows (workspace → package, used by save)
|
|
18
|
+
|
|
19
|
+
#### Scenario: Load platform with valid configuration
|
|
20
|
+
|
|
21
|
+
- **WHEN** platform config defines all required fields with valid types
|
|
22
|
+
- **THEN** platform is loaded successfully and available for use
|
|
23
|
+
|
|
24
|
+
#### Scenario: Load platform with export/import flows configuration
|
|
25
|
+
|
|
26
|
+
- **WHEN** platform config defines `export` and/or `import` arrays with valid flow objects
|
|
27
|
+
- **THEN** flows are loaded and validated according to flow schema
|
|
28
|
+
|
|
29
|
+
#### Scenario: Invalid platform configuration missing required field
|
|
30
|
+
|
|
31
|
+
- **WHEN** platform config is missing `name`, `rootDir`, or both `export`/`import`/`rootFile` fields
|
|
32
|
+
- **THEN** configuration load fails with error: "Platform 'id': Must define at least one of 'export', 'import', or 'rootFile'"
|
|
33
|
+
|
|
34
|
+
#### Scenario: Invalid platform configuration with wrong types
|
|
35
|
+
|
|
36
|
+
- **WHEN** platform config has field with incorrect type (e.g., `name` as number)
|
|
37
|
+
- **THEN** configuration load fails with type error and expected type
|
|
38
|
+
|
|
39
|
+
### Requirement: Configuration Merge Hierarchy
|
|
40
|
+
|
|
41
|
+
Platform configurations SHALL be loaded and merged from three sources in priority order:
|
|
42
|
+
|
|
43
|
+
1. **Built-in**: Default configurations shipped with CLI
|
|
44
|
+
2. **Global**: User overrides in `~/.openpackage/platforms.jsonc`
|
|
45
|
+
3. **Workspace**: Project-specific overrides in `<workspace>/.openpackage/platforms.jsonc`
|
|
46
|
+
|
|
47
|
+
Merge order: workspace > global > built-in (last writer wins)
|
|
48
|
+
|
|
49
|
+
#### Scenario: Global override of platform flows
|
|
50
|
+
|
|
51
|
+
- **WHEN** global config defines export/import flows for existing built-in platform
|
|
52
|
+
- **THEN** global export/import arrays completely replace built-in flows for that platform (per array)
|
|
53
|
+
|
|
54
|
+
#### Scenario: Workspace adds custom platform
|
|
55
|
+
|
|
56
|
+
- **WHEN** workspace config defines new platform not in built-in or global
|
|
57
|
+
- **THEN** custom platform is added and available for detection and flow execution
|
|
58
|
+
|
|
59
|
+
#### Scenario: Workspace disables built-in platform
|
|
60
|
+
|
|
61
|
+
- **WHEN** workspace config sets `enabled: false` for built-in platform
|
|
62
|
+
- **THEN** platform is skipped during detection and flow execution
|
|
63
|
+
|
|
64
|
+
#### Scenario: Invalid merged configuration
|
|
65
|
+
|
|
66
|
+
- **WHEN** merged configuration results in invalid platform definition
|
|
67
|
+
- **THEN** configuration load fails with error indicating which source/platform caused issue
|
|
68
|
+
|
|
69
|
+
#### Scenario: Field-level merge behavior
|
|
70
|
+
|
|
71
|
+
- **WHEN** platform field is defined in multiple configs
|
|
72
|
+
- **THEN** last writer wins (workspace > global > built-in)
|
|
73
|
+
- **AND** export/import arrays are replaced entirely, not merged at element level
|
|
74
|
+
|
|
75
|
+
### Requirement: Platform Detection
|
|
76
|
+
|
|
77
|
+
Platform detection SHALL use following logic:
|
|
78
|
+
|
|
79
|
+
- **Directory detection**: Check if platform `rootDir` exists in workspace
|
|
80
|
+
- **Root file detection**: Check if platform `rootFile` exists at project root
|
|
81
|
+
- **Enabled flag**: Only detect platforms where `enabled` is `true` or omitted
|
|
82
|
+
- **Detection signal**: Platform detected if rootDir OR rootFile exists
|
|
83
|
+
|
|
84
|
+
#### Scenario: Detect platform by root directory
|
|
85
|
+
|
|
86
|
+
- **WHEN** platform's `rootDir` exists in workspace
|
|
87
|
+
- **THEN** platform is marked as detected and flows can execute
|
|
88
|
+
|
|
89
|
+
#### Scenario: Detect platform by root file
|
|
90
|
+
|
|
91
|
+
- **WHEN** platform's `rootFile` exists at project root
|
|
92
|
+
- **THEN** platform is marked as detected even without directory structure
|
|
93
|
+
|
|
94
|
+
#### Scenario: Skip disabled platform during detection
|
|
95
|
+
|
|
96
|
+
- **WHEN** platform has `enabled: false` in configuration
|
|
97
|
+
- **THEN** platform is not detected regardless of directory/file presence
|
|
98
|
+
|
|
99
|
+
#### Scenario: Platform detection with both signals
|
|
100
|
+
|
|
101
|
+
- **WHEN** both `rootDir` and `rootFile` exist
|
|
102
|
+
- **THEN** platform is detected (redundant but valid)
|
|
103
|
+
|
|
104
|
+
## Flow Configuration Requirements
|
|
105
|
+
|
|
106
|
+
### Requirement: Flow Schema Validation
|
|
107
|
+
|
|
108
|
+
The system SHALL support declarative flow configurations with following structure:
|
|
109
|
+
|
|
110
|
+
- **Required fields**: `from` (source pattern), `to` (target path or multi-target object)
|
|
111
|
+
- **Optional transforms**: `pipe`, `map`, `pick`, `omit`, `path`, `embed`, `section`, `when`, `merge`, `namespace`, `handler`
|
|
112
|
+
- **Multi-target support**: `to` can be object mapping target paths to transform options
|
|
113
|
+
- **Validation**: Validate all flows on configuration load
|
|
114
|
+
|
|
115
|
+
#### Scenario: Simple file mapping flow loads successfully
|
|
116
|
+
|
|
117
|
+
- **WHEN** flow defines `{ "from": "rules/**/*.md", "to": ".cursor/rules/**/*.mdc" }`
|
|
118
|
+
- **THEN** flow is validated and ready for execution
|
|
119
|
+
|
|
120
|
+
#### Scenario: Recursive glob pattern flow loads successfully
|
|
121
|
+
|
|
122
|
+
- **WHEN** flow defines `{ "from": "skills/**/*", "to": ".platform/skills/**/*" }`
|
|
123
|
+
- **THEN** flow is validated and supports recursive directory traversal
|
|
124
|
+
|
|
125
|
+
#### Scenario: Multi-target flow with different transforms loads successfully
|
|
126
|
+
|
|
127
|
+
- **WHEN** flow defines `to` as object with multiple target paths
|
|
128
|
+
- **THEN** each target configuration is validated independently
|
|
129
|
+
|
|
130
|
+
#### Scenario: Invalid flow missing required field
|
|
131
|
+
|
|
132
|
+
- **WHEN** flow is missing `from` or `to` field
|
|
133
|
+
- **THEN** validation fails with error: "Flow missing required field 'from'/'to'"
|
|
134
|
+
|
|
135
|
+
#### Scenario: Invalid flow with wrong field types
|
|
136
|
+
|
|
137
|
+
- **WHEN** flow has field with incorrect type (e.g., `merge` as number)
|
|
138
|
+
- **THEN** validation fails with type error
|
|
139
|
+
|
|
140
|
+
### Requirement: Flow Execution Pipeline
|
|
141
|
+
|
|
142
|
+
The system SHALL execute flows through multi-stage pipeline:
|
|
143
|
+
|
|
144
|
+
1. **Load**: Read source file, auto-detect format (YAML/JSON/JSONC/TOML/Markdown)
|
|
145
|
+
2. **Extract**: Apply JSONPath extraction if `path` specified
|
|
146
|
+
3. **Filter**: Apply `pick` (whitelist) or `omit` (blacklist) key filters
|
|
147
|
+
4. **Map**: Transform keys and values using `map` configuration
|
|
148
|
+
5. **Transform**: Apply pipe transforms in order
|
|
149
|
+
6. **Namespace**: Wrap content if `namespace` enabled
|
|
150
|
+
7. **Embed**: Wrap under key/section if `embed` or `section` specified
|
|
151
|
+
8. **Merge**: Merge with existing target using strategy
|
|
152
|
+
9. **Write**: Serialize to target format and write atomically
|
|
153
|
+
|
|
154
|
+
#### Scenario: Simple format conversion through pipeline
|
|
155
|
+
|
|
156
|
+
- **WHEN** YAML file flows to JSON target with no additional transforms
|
|
157
|
+
- **THEN** content is parsed as YAML, converted to JSON object, serialized as JSON
|
|
158
|
+
|
|
159
|
+
#### Scenario: Complex transformation pipeline with multiple stages
|
|
160
|
+
|
|
161
|
+
- **WHEN** flow defines `path`, `map`, `pipe`, `embed`, and `merge` options
|
|
162
|
+
- **THEN** transformations are applied in defined pipeline order
|
|
163
|
+
|
|
164
|
+
#### Scenario: Pipeline stage failure stops execution
|
|
165
|
+
|
|
166
|
+
- **WHEN** any pipeline stage fails (parse error, transform error, write error)
|
|
167
|
+
- **THEN** execution stops immediately and error is reported with context (stage, file, reason)
|
|
168
|
+
|
|
169
|
+
#### Scenario: Simple file copy bypasses pipeline
|
|
170
|
+
|
|
171
|
+
- **WHEN** flow has no transform options (only `from` and `to`)
|
|
172
|
+
- **THEN** file is copied directly without parsing for performance optimization
|
|
173
|
+
|
|
174
|
+
### Requirement: Glob Pattern Support
|
|
175
|
+
|
|
176
|
+
The system SHALL support glob patterns for file matching:
|
|
177
|
+
|
|
178
|
+
- **Single-level glob** (`*`): Matches files in a single directory level
|
|
179
|
+
- **Recursive glob** (`**`): Matches files in all subdirectories recursively
|
|
180
|
+
- **Extension mapping**: Target patterns can specify different extensions
|
|
181
|
+
- **Directory structure preservation**: Recursive globs maintain nested directory structure
|
|
182
|
+
|
|
183
|
+
#### Scenario: Single-level glob matches files in directory
|
|
184
|
+
|
|
185
|
+
- **WHEN** flow uses pattern `rules/*.md`
|
|
186
|
+
- **THEN** all `.md` files in `rules/` directory are matched (not subdirectories)
|
|
187
|
+
|
|
188
|
+
#### Scenario: Recursive glob matches nested files
|
|
189
|
+
|
|
190
|
+
- **WHEN** flow uses pattern `rules/**/*.md`
|
|
191
|
+
- **THEN** all `.md` files in `rules/` and all subdirectories are matched
|
|
192
|
+
- **AND** directory structure is preserved in target
|
|
193
|
+
|
|
194
|
+
#### Scenario: Recursive glob with all file types
|
|
195
|
+
|
|
196
|
+
- **WHEN** flow uses pattern `skills/**/*`
|
|
197
|
+
- **THEN** all files of any type in `skills/` and subdirectories are matched
|
|
198
|
+
- **AND** complete directory tree is replicated in target
|
|
199
|
+
|
|
200
|
+
#### Scenario: Extension mapping in recursive glob
|
|
201
|
+
|
|
202
|
+
- **WHEN** flow defines `from: "rules/**/*.md", to: ".cursor/rules/**/*.mdc"`
|
|
203
|
+
- **THEN** all `.md` files are copied with `.mdc` extension
|
|
204
|
+
- **AND** directory structure `rules/advanced/types.md` → `.cursor/rules/advanced/types.mdc`
|
|
205
|
+
|
|
206
|
+
#### Scenario: Empty glob match returns no error
|
|
207
|
+
|
|
208
|
+
- **WHEN** glob pattern matches no files
|
|
209
|
+
- **THEN** flow succeeds with warning "No files matched pattern"
|
|
210
|
+
- **AND** no error is raised
|
|
211
|
+
|
|
212
|
+
#### Scenario: Glob pattern preserves directory structure
|
|
213
|
+
|
|
214
|
+
- **WHEN** source has `rules/typescript/advanced/generics.md`
|
|
215
|
+
- **AND** flow uses `rules/**/*.md` → `.cursor/rules/**/*.md`
|
|
216
|
+
- **THEN** target is `.cursor/rules/typescript/advanced/generics.md`
|
|
217
|
+
|
|
218
|
+
## Format Conversion Requirements
|
|
219
|
+
|
|
220
|
+
### Requirement: Automatic Format Conversion
|
|
221
|
+
|
|
222
|
+
The system SHALL support bidirectional format conversion:
|
|
223
|
+
|
|
224
|
+
- **JSONC**: Parse JSON with comments, strip comments when converting to strict JSON
|
|
225
|
+
- **YAML**: Convert between YAML and JSON object representations
|
|
226
|
+
- **TOML**: Convert between TOML and JSON object representations
|
|
227
|
+
- **Markdown**: Parse frontmatter as YAML, transform frontmatter, preserve body
|
|
228
|
+
- **Auto-detection**: Detect format from file extension or content analysis
|
|
229
|
+
|
|
230
|
+
#### Scenario: YAML to JSON conversion
|
|
231
|
+
|
|
232
|
+
- **WHEN** source is YAML and target is JSON
|
|
233
|
+
- **THEN** content is parsed as YAML object and serialized as JSON
|
|
234
|
+
|
|
235
|
+
#### Scenario: JSONC to JSON conversion strips comments
|
|
236
|
+
|
|
237
|
+
- **WHEN** source is JSONC and target is JSON
|
|
238
|
+
- **THEN** comments are stripped during conversion, content preserved
|
|
239
|
+
|
|
240
|
+
#### Scenario: Format auto-detection from extension
|
|
241
|
+
|
|
242
|
+
- **WHEN** file extension is `.yaml`, `.json`, `.toml`, or `.md`
|
|
243
|
+
- **THEN** format is detected from extension and appropriate parser used
|
|
244
|
+
|
|
245
|
+
#### Scenario: Format auto-detection from content
|
|
246
|
+
|
|
247
|
+
- **WHEN** file extension is ambiguous or missing
|
|
248
|
+
- **THEN** format is detected by attempting to parse with multiple parsers
|
|
249
|
+
|
|
250
|
+
## Merge Strategy Requirements
|
|
251
|
+
|
|
252
|
+
### Requirement: Configurable Merge Strategies
|
|
253
|
+
|
|
254
|
+
The system SHALL support multiple merge strategies:
|
|
255
|
+
|
|
256
|
+
- **Deep merge** (`merge: "deep"`): Recursively merge nested objects and arrays
|
|
257
|
+
- **Shallow merge** (`merge: "shallow"`): Merge only top-level keys
|
|
258
|
+
- **Replace** (default): Completely replace target content with source
|
|
259
|
+
- **Composite** (`merge: "composite"`): Compose multiple package contributions using delimiters
|
|
260
|
+
- **Priority-based**: Workspace > direct deps > nested deps (shallower = higher priority)
|
|
261
|
+
|
|
262
|
+
#### Scenario: Deep merge of nested objects
|
|
263
|
+
|
|
264
|
+
- **WHEN** two JSON files are merged with `merge: "deep"`
|
|
265
|
+
- **THEN** nested objects are recursively merged, preserving non-overlapping keys at all levels
|
|
266
|
+
|
|
267
|
+
#### Scenario: Shallow merge of top-level keys only
|
|
268
|
+
|
|
269
|
+
- **WHEN** two JSON files are merged with `merge: "shallow"`
|
|
270
|
+
- **THEN** only top-level keys are merged, nested objects are replaced entirely
|
|
271
|
+
|
|
272
|
+
#### Scenario: Replace strategy overwrites target
|
|
273
|
+
|
|
274
|
+
- **WHEN** no merge strategy is specified
|
|
275
|
+
- **THEN** target file is completely replaced with source content
|
|
276
|
+
|
|
277
|
+
#### Scenario: Composite merge with multiple packages
|
|
278
|
+
|
|
279
|
+
- **WHEN** multiple packages define flows to same target with `merge: "composite"`
|
|
280
|
+
- **THEN** each package's content is wrapped in HTML comment delimiters with package name
|
|
281
|
+
- **AND** updates replace only that package's section
|
|
282
|
+
- **AND** all other packages' sections are preserved
|
|
283
|
+
|
|
284
|
+
#### Scenario: Composite merge preserves manual edits
|
|
285
|
+
|
|
286
|
+
- **WHEN** target file has manual edits outside package markers
|
|
287
|
+
- **AND** package content is merged with `merge: "composite"`
|
|
288
|
+
- **THEN** manual edits are preserved
|
|
289
|
+
- **AND** only the package's marked section is updated
|
|
290
|
+
|
|
291
|
+
#### Scenario: Composite merge format
|
|
292
|
+
|
|
293
|
+
- **WHEN** composite merge is used
|
|
294
|
+
- **THEN** content is wrapped in markers: `<!-- package: @scope/name -->` content `<!-- -->`
|
|
295
|
+
- **AND** each package gets its own section
|
|
296
|
+
- **AND** sections can be independently updated or removed
|
|
297
|
+
|
|
298
|
+
#### Scenario: Priority-based merge with multiple packages
|
|
299
|
+
|
|
300
|
+
- **WHEN** multiple packages define flows to same target with merge strategy
|
|
301
|
+
- **THEN** content is merged according to priority order (workspace > direct > nested)
|
|
302
|
+
- **AND** conflicts at leaf nodes resolved by last-writer-wins using priority
|
|
303
|
+
|
|
304
|
+
#### Scenario: Conflict warning logged during merge
|
|
305
|
+
|
|
306
|
+
- **WHEN** multiple packages write to same file and content conflicts
|
|
307
|
+
- **THEN** warning is logged: "Package @scope/b overwrites content from @scope/a in path"
|
|
308
|
+
|
|
309
|
+
## Key Mapping Requirements
|
|
310
|
+
|
|
311
|
+
### Requirement: Sophisticated Key Transformations
|
|
312
|
+
|
|
313
|
+
The system SHALL support key mapping with:
|
|
314
|
+
|
|
315
|
+
- **Dot notation**: Map to nested paths (`theme` → `workbench.colorTheme`)
|
|
316
|
+
- **Wildcard patterns**: Map multiple keys (`ai.*` → `cursor.*`)
|
|
317
|
+
- **Value transforms**: Apply type/string transforms during mapping
|
|
318
|
+
- **Value lookup tables**: Map values to platform-specific equivalents
|
|
319
|
+
- **Default values**: Provide fallback for missing keys
|
|
320
|
+
|
|
321
|
+
#### Scenario: Simple key rename with dot notation
|
|
322
|
+
|
|
323
|
+
- **WHEN** map defines `{ "theme": "workbench.colorTheme" }`
|
|
324
|
+
- **THEN** key `theme` is moved to nested path `workbench.colorTheme`
|
|
325
|
+
|
|
326
|
+
#### Scenario: Wildcard key mapping
|
|
327
|
+
|
|
328
|
+
- **WHEN** map defines `{ "ai.*": "cursor.*" }`
|
|
329
|
+
- **THEN** all keys under `ai` namespace are moved under `cursor` namespace
|
|
330
|
+
|
|
331
|
+
#### Scenario: Value transformation during mapping
|
|
332
|
+
|
|
333
|
+
- **WHEN** map defines `{ "fontSize": { "to": "editor.fontSize", "transform": "number" } }`
|
|
334
|
+
- **THEN** value is converted to number type and moved to target key
|
|
335
|
+
|
|
336
|
+
#### Scenario: Value lookup table mapping
|
|
337
|
+
|
|
338
|
+
- **WHEN** map defines `values` object with source-to-target mapping
|
|
339
|
+
- **THEN** source values are replaced with corresponding target values from table
|
|
340
|
+
|
|
341
|
+
#### Scenario: Default value for missing key
|
|
342
|
+
|
|
343
|
+
- **WHEN** map defines `default` value and source key is missing
|
|
344
|
+
- **THEN** default value is used in target
|
|
345
|
+
|
|
346
|
+
## Markdown Frontmatter Requirements
|
|
347
|
+
|
|
348
|
+
### Requirement: Frontmatter Transformation
|
|
349
|
+
|
|
350
|
+
The system SHALL support transforming YAML frontmatter in Markdown files:
|
|
351
|
+
|
|
352
|
+
- **Parse frontmatter**: Extract YAML frontmatter from Markdown
|
|
353
|
+
- **Transform frontmatter**: Apply key mapping and transforms to frontmatter only
|
|
354
|
+
- **Preserve body**: Keep Markdown body content unchanged
|
|
355
|
+
- **Serialize**: Reconstruct file with transformed frontmatter and original body
|
|
356
|
+
|
|
357
|
+
#### Scenario: Transform agent frontmatter with key mapping
|
|
358
|
+
|
|
359
|
+
- **WHEN** agent Markdown file has frontmatter with keys defined in map
|
|
360
|
+
- **THEN** frontmatter keys/values are transformed according to map
|
|
361
|
+
- **AND** markdown body content is preserved byte-for-byte
|
|
362
|
+
|
|
363
|
+
#### Scenario: Add frontmatter keys with defaults
|
|
364
|
+
|
|
365
|
+
- **WHEN** map defines new keys with default values
|
|
366
|
+
- **THEN** new keys are added to frontmatter without affecting body
|
|
367
|
+
|
|
368
|
+
#### Scenario: Remove frontmatter keys with omit
|
|
369
|
+
|
|
370
|
+
- **WHEN** omit list includes frontmatter keys
|
|
371
|
+
- **THEN** specified keys are removed from frontmatter without affecting body
|
|
372
|
+
|
|
373
|
+
## Multi-Package Composition Requirements
|
|
374
|
+
|
|
375
|
+
### Requirement: Priority-Based Multi-Package Merging
|
|
376
|
+
|
|
377
|
+
The system SHALL support composition from multiple packages using priority-based conflict resolution:
|
|
378
|
+
|
|
379
|
+
- **Priority order**: Workspace content > direct dependencies > nested dependencies (shallower = higher)
|
|
380
|
+
- **Conflict detection**: Detect when multiple packages write to same file paths
|
|
381
|
+
- **Conflict warnings**: Log warnings when conflicts occur with package information
|
|
382
|
+
- **Last-writer-wins**: Package with highest priority overwrites conflicting content at leaf nodes
|
|
383
|
+
- **Merge strategies**: Apply deep/shallow/replace merge based on flow configuration
|
|
384
|
+
|
|
385
|
+
#### Scenario: Direct dependency wins over nested dependency
|
|
386
|
+
|
|
387
|
+
- **WHEN** direct dependency and its nested dependency target same file
|
|
388
|
+
- **THEN** direct dependency content takes precedence (shallower = higher priority)
|
|
389
|
+
- **AND** warning logged: "Package @scope/direct overwrites @scope/nested in path"
|
|
390
|
+
|
|
391
|
+
#### Scenario: Later direct dependency wins over earlier
|
|
392
|
+
|
|
393
|
+
- **WHEN** two direct dependencies define conflicting content for same target
|
|
394
|
+
- **THEN** package listed later in dependency order wins (higher priority)
|
|
395
|
+
- **AND** warning logged with package information
|
|
396
|
+
|
|
397
|
+
#### Scenario: Workspace content preserved with highest priority
|
|
398
|
+
|
|
399
|
+
- **WHEN** workspace has manually-edited content in target file
|
|
400
|
+
- **THEN** workspace content is preserved (highest priority)
|
|
401
|
+
- **AND** package content does not overwrite manual edits
|
|
402
|
+
|
|
403
|
+
#### Scenario: Multi-package deep merge with priority resolution
|
|
404
|
+
|
|
405
|
+
- **WHEN** multiple packages define flows to same target with `merge: "deep"`
|
|
406
|
+
- **THEN** content is deeply merged according to priority order
|
|
407
|
+
- **AND** conflicts at leaf nodes resolved by priority (last-writer-wins)
|
|
408
|
+
|
|
409
|
+
## Conditional Execution Requirements
|
|
410
|
+
|
|
411
|
+
### Requirement: Context-Based Conditional Flows
|
|
412
|
+
|
|
413
|
+
The system SHALL support conditional flow execution:
|
|
414
|
+
|
|
415
|
+
- **Platform checks**: Execute only if specific platform detected (`platform: "cursor"`)
|
|
416
|
+
- **Existence checks**: Execute only if file/directory exists (`exists: ".cursor"`)
|
|
417
|
+
- **Key checks**: Execute only if source key exists (`key: "servers"`)
|
|
418
|
+
- **Value checks**: Execute only if key equals value (`equals: "production"`)
|
|
419
|
+
- **Composite conditions**: Support `and` and `or` operators for complex logic
|
|
420
|
+
|
|
421
|
+
#### Scenario: Platform-conditional flow execution
|
|
422
|
+
|
|
423
|
+
- **WHEN** flow has `when: { "platform": "cursor" }` condition
|
|
424
|
+
- **THEN** flow executes only when Cursor platform is detected in workspace
|
|
425
|
+
|
|
426
|
+
#### Scenario: File existence check before execution
|
|
427
|
+
|
|
428
|
+
- **WHEN** flow has `when: { "exists": ".cursor" }` condition
|
|
429
|
+
- **THEN** flow executes only if `.cursor` directory exists
|
|
430
|
+
|
|
431
|
+
#### Scenario: Composite AND condition requires all true
|
|
432
|
+
|
|
433
|
+
- **WHEN** flow has `when: { "and": [{ "platform": "cursor" }, { "exists": "mcp.jsonc" }] }`
|
|
434
|
+
- **THEN** flow executes only if both Cursor detected AND mcp.jsonc exists
|
|
435
|
+
|
|
436
|
+
#### Scenario: Composite OR condition requires any true
|
|
437
|
+
|
|
438
|
+
- **WHEN** flow has `when: { "or": [{ "platform": "cursor" }, { "platform": "claude" }] }`
|
|
439
|
+
- **THEN** flow executes if either Cursor OR Claude platform is detected
|
|
440
|
+
|
|
441
|
+
## Content Embedding Requirements
|
|
442
|
+
|
|
443
|
+
### Requirement: Content Embedding in Target Structures
|
|
444
|
+
|
|
445
|
+
The system SHALL support embedding content within target structures:
|
|
446
|
+
|
|
447
|
+
- **JSON embedding**: Wrap content under specified key with `embed: "key"`
|
|
448
|
+
- **TOML sections**: Place content in TOML section with `section: "section_name"`
|
|
449
|
+
- **Merge with embedding**: Combine embedding with merge strategies
|
|
450
|
+
|
|
451
|
+
#### Scenario: Embed content in JSON structure
|
|
452
|
+
|
|
453
|
+
- **WHEN** flow defines `embed: "mcp"` for JSON target
|
|
454
|
+
- **THEN** source content is wrapped under `{ "mcp": <content> }` in target
|
|
455
|
+
|
|
456
|
+
#### Scenario: TOML section embedding
|
|
457
|
+
|
|
458
|
+
- **WHEN** flow defines `section: "mcp_servers"` for TOML target
|
|
459
|
+
- **THEN** content is placed under `[mcp_servers]` section in TOML file
|
|
460
|
+
|
|
461
|
+
#### Scenario: Embed and deep merge together
|
|
462
|
+
|
|
463
|
+
- **WHEN** flow defines both `embed: "mcp"` and `merge: "deep"`
|
|
464
|
+
- **THEN** embedded content is deep merged with existing embedded section in target
|
|
465
|
+
|
|
466
|
+
## Built-in Transform Requirements
|
|
467
|
+
|
|
468
|
+
### Requirement: Comprehensive Built-in Value Transforms
|
|
469
|
+
|
|
470
|
+
The system SHALL provide built-in value transforms:
|
|
471
|
+
|
|
472
|
+
**Type Converters:** `number`, `string`, `boolean`, `json`, `date`
|
|
473
|
+
**String Transforms:** `uppercase`, `lowercase`, `title-case`, `camel-case`, `kebab-case`, `snake-case`, `trim`, `slugify`
|
|
474
|
+
**Array Transforms:** `array-append`, `array-unique`, `array-flatten`
|
|
475
|
+
**Object Transforms:** `flatten`, `unflatten`, `pick-keys`, `omit-keys`
|
|
476
|
+
|
|
477
|
+
#### Scenario: Type conversion transform
|
|
478
|
+
|
|
479
|
+
- **WHEN** transform is `number` and value is string "42"
|
|
480
|
+
- **THEN** value is converted to number 42
|
|
481
|
+
|
|
482
|
+
#### Scenario: String case transform
|
|
483
|
+
|
|
484
|
+
- **WHEN** transform is `kebab-case` and value is "helloWorld"
|
|
485
|
+
- **THEN** value is converted to "hello-world"
|
|
486
|
+
|
|
487
|
+
#### Scenario: Array deduplication transform
|
|
488
|
+
|
|
489
|
+
- **WHEN** transform is `array-unique` and value is `[1, 2, 2, 3]`
|
|
490
|
+
- **THEN** value is converted to `[1, 2, 3]`
|
|
491
|
+
|
|
492
|
+
#### Scenario: Object flattening transform
|
|
493
|
+
|
|
494
|
+
- **WHEN** transform is `flatten` and value is `{ "a": { "b": 1 } }`
|
|
495
|
+
- **THEN** value is converted to `{ "a.b": 1 }`
|
|
496
|
+
|
|
497
|
+
## Namespace Isolation Requirements
|
|
498
|
+
|
|
499
|
+
### Requirement: Package Namespace Isolation
|
|
500
|
+
|
|
501
|
+
The system SHALL support namespace isolation to prevent package collisions:
|
|
502
|
+
|
|
503
|
+
- **Automatic wrapping**: Wrap content under `packages.{packageName}` when `namespace: true`
|
|
504
|
+
- **Custom namespace key**: Support custom key via `namespace: "customKey"`
|
|
505
|
+
- **Merge with namespacing**: Combine namespacing with merge strategies
|
|
506
|
+
- **Per-package isolation**: Each package gets separate namespace
|
|
507
|
+
|
|
508
|
+
#### Scenario: Automatic namespace wrapping
|
|
509
|
+
|
|
510
|
+
- **WHEN** flow has `namespace: true`
|
|
511
|
+
- **THEN** content is wrapped under `packages[@scope/package-name]` key in target
|
|
512
|
+
|
|
513
|
+
#### Scenario: Custom namespace key
|
|
514
|
+
|
|
515
|
+
- **WHEN** flow has `namespace: "extensions"`
|
|
516
|
+
- **THEN** content is wrapped under `extensions[@scope/package-name]` key in target
|
|
517
|
+
|
|
518
|
+
#### Scenario: Namespace isolation prevents conflicts
|
|
519
|
+
|
|
520
|
+
- **WHEN** multiple packages use namespacing for same target
|
|
521
|
+
- **THEN** each package's content is isolated under its own namespace
|
|
522
|
+
- **AND** no conflicts occur between packages
|
|
523
|
+
|
|
524
|
+
## Validation Requirements
|
|
525
|
+
|
|
526
|
+
### Requirement: Configuration Validation
|
|
527
|
+
|
|
528
|
+
The system SHALL validate configurations with clear error reporting:
|
|
529
|
+
|
|
530
|
+
- **Schema validation**: Validate required fields and types
|
|
531
|
+
- **Transform validation**: Verify transform names exist in built-ins
|
|
532
|
+
- **JSONPath validation**: Validate JSONPath expression syntax
|
|
533
|
+
- **Circular dependency detection**: Detect and report circular flow dependencies
|
|
534
|
+
- **Context-rich errors**: Include file path, platform, flow index, and fix suggestions
|
|
535
|
+
|
|
536
|
+
#### Scenario: Missing required field validation
|
|
537
|
+
|
|
538
|
+
- **WHEN** flow is missing `from` or `to` field
|
|
539
|
+
- **THEN** validation fails with error: "Platform 'id' flow N: missing required field 'from'/'to'"
|
|
540
|
+
|
|
541
|
+
#### Scenario: Invalid transform name validation
|
|
542
|
+
|
|
543
|
+
- **WHEN** flow references non-existent transform in `pipe`
|
|
544
|
+
- **THEN** validation fails with error: "Unknown transform 'xyz'. Available: [list]"
|
|
545
|
+
|
|
546
|
+
#### Scenario: Invalid JSONPath expression validation
|
|
547
|
+
|
|
548
|
+
- **WHEN** flow defines invalid JSONPath in `path` field
|
|
549
|
+
- **THEN** validation fails with error: "Invalid JSONPath expression: <expr>. <reason>"
|
|
550
|
+
|
|
551
|
+
#### Scenario: Circular dependency detection
|
|
552
|
+
|
|
553
|
+
- **WHEN** flows create circular transformation dependency
|
|
554
|
+
- **THEN** validation fails with error: "Circular dependency detected: A → B → A"
|
|
555
|
+
|
|
556
|
+
## Performance Requirements
|
|
557
|
+
|
|
558
|
+
### Requirement: Performance Optimization
|
|
559
|
+
|
|
560
|
+
The system SHALL optimize flow execution:
|
|
561
|
+
|
|
562
|
+
- **Simple file copy bypass**: Skip pipeline for flows with no transforms
|
|
563
|
+
- **Parser caching**: Cache format parsers per file type within execution context
|
|
564
|
+
- **Single source parse**: Parse source once for multi-target flows
|
|
565
|
+
- **Lazy evaluation**: Evaluate conditional flows only when conditions might be true
|
|
566
|
+
- **Structural sharing**: Share unchanged object structures during merges
|
|
567
|
+
|
|
568
|
+
#### Scenario: Simple file copy optimization
|
|
569
|
+
|
|
570
|
+
- **WHEN** flow has no transforms (just `from` and `to` with extension change)
|
|
571
|
+
- **THEN** file is copied directly without parsing pipeline
|
|
572
|
+
|
|
573
|
+
#### Scenario: Multi-target source caching
|
|
574
|
+
|
|
575
|
+
- **WHEN** flow has multiple targets from same source
|
|
576
|
+
- **THEN** source is parsed once and AST/object is reused for all targets
|
|
577
|
+
|
|
578
|
+
#### Scenario: Conditional flow lazy evaluation
|
|
579
|
+
|
|
580
|
+
- **WHEN** flow has `when` condition that evaluates to false
|
|
581
|
+
- **THEN** flow is skipped without loading or parsing source file
|
|
582
|
+
|
|
583
|
+
## Bidirectional Flow Requirements
|
|
584
|
+
|
|
585
|
+
### Requirement: Explicit Bidirectional Flow Configuration
|
|
586
|
+
|
|
587
|
+
The system SHALL define flows as explicit bidirectional transformations using separate export and import flows:
|
|
588
|
+
|
|
589
|
+
- **Export flows**: Transform from universal package format to platform-specific workspace format (package → workspace)
|
|
590
|
+
- **Import flows**: Transform from platform-specific workspace format to universal package format (workspace → package)
|
|
591
|
+
- **Export `from`**: Always relative to package root (universal format)
|
|
592
|
+
- **Export `to`**: Always relative to workspace root (platform-specific format)
|
|
593
|
+
- **Import `from`**: Always relative to workspace root (platform-specific format)
|
|
594
|
+
- **Import `to`**: Always relative to package root (universal format)
|
|
595
|
+
- **No automatic inversion**: Import flows must be explicitly defined, no automatic reversal of export flows
|
|
596
|
+
- **Independent flows**: Export and import flows are independent; no pairing or coupling required
|
|
597
|
+
|
|
598
|
+
#### Scenario: Install executes export flows (package → workspace)
|
|
599
|
+
|
|
600
|
+
- **WHEN** installing a package with export flows
|
|
601
|
+
- **THEN** export flows execute transforming package files to workspace files
|
|
602
|
+
- **AND** source files are in universal package format
|
|
603
|
+
- **AND** target files are in platform-specific format
|
|
604
|
+
|
|
605
|
+
#### Scenario: Apply re-executes export flows (package → workspace)
|
|
606
|
+
|
|
607
|
+
- **WHEN** applying a package with export flows
|
|
608
|
+
- **THEN** export flows execute again transforming package files to workspace files
|
|
609
|
+
- **AND** existing workspace files may be overwritten based on merge strategy
|
|
610
|
+
|
|
611
|
+
#### Scenario: Save executes import flows (workspace → package)
|
|
612
|
+
|
|
613
|
+
- **WHEN** saving workspace files to package
|
|
614
|
+
- **THEN** system matches workspace files against import flow `from` patterns
|
|
615
|
+
- **AND** executes import flows to transform workspace format to universal format
|
|
616
|
+
- **AND** only processes files tracked in workspace index
|
|
617
|
+
|
|
618
|
+
#### Scenario: Save with no matching import flow
|
|
619
|
+
|
|
620
|
+
- **WHEN** workspace file is tracked in index but no import flow matches
|
|
621
|
+
- **THEN** file is silently skipped (no error)
|
|
622
|
+
- **AND** package is not updated for that file
|
|
623
|
+
|
|
624
|
+
#### Scenario: Save only processes indexed files
|
|
625
|
+
|
|
626
|
+
- **WHEN** workspace contains files not in workspace index
|
|
627
|
+
- **THEN** import flows do not process untracked files
|
|
628
|
+
- **AND** only files previously exported are candidates for import
|
|
629
|
+
|
|
630
|
+
#### Scenario: Independent export and import flows
|
|
631
|
+
|
|
632
|
+
- **WHEN** platform defines export flows without corresponding import flows
|
|
633
|
+
- **THEN** install/apply work normally but save cannot update package
|
|
634
|
+
- **WHEN** platform defines import flows without corresponding export flows
|
|
635
|
+
- **THEN** save works normally but install/apply do nothing
|
|
636
|
+
|
|
637
|
+
#### Scenario: Array pattern support in both directions
|
|
638
|
+
|
|
639
|
+
- **WHEN** export flow uses array pattern `from: ["file1.jsonc", "file1.json"]`
|
|
640
|
+
- **THEN** first matching file is used (priority order)
|
|
641
|
+
- **WHEN** import flow uses array pattern `from: [".platform/file1.json", ".platform/file1.jsonc"]`
|
|
642
|
+
- **THEN** first matching file is used (priority order)
|
|
643
|
+
|
|
644
|
+
## Schema Versioning Requirements
|
|
645
|
+
|
|
646
|
+
### Requirement: Local JSON Schema Support
|
|
647
|
+
|
|
648
|
+
The system SHALL support schema versioning using local JSON schema files:
|
|
649
|
+
|
|
650
|
+
- **Schema field**: Optional `$schema` field in platforms.jsonc referencing local schema
|
|
651
|
+
- **Local schema path**: Resolve relative to workspace or node_modules
|
|
652
|
+
- **IDE support**: Enable validation and autocomplete via JSON schema
|
|
653
|
+
- **Version detection**: Infer version from schema path or default to CLI version
|
|
654
|
+
- **Validation**: Validate config against specified schema version
|
|
655
|
+
|
|
656
|
+
#### Scenario: Explicit schema version reference
|
|
657
|
+
|
|
658
|
+
- **WHEN** platforms.jsonc includes `$schema: "./node_modules/opkg-cli/schemas/platforms-v1.json"`
|
|
659
|
+
- **THEN** config is validated against v1 schema
|
|
660
|
+
- **AND** IDE provides v1-specific autocomplete and validation
|
|
661
|
+
|
|
662
|
+
#### Scenario: Missing schema field defaults to current
|
|
663
|
+
|
|
664
|
+
- **WHEN** platforms.jsonc has no `$schema` field
|
|
665
|
+
- **THEN** config defaults to current CLI version schema
|
|
666
|
+
- **AND** validation uses latest schema rules
|
|
667
|
+
|
|
668
|
+
#### Scenario: Schema path resolution
|
|
669
|
+
|
|
670
|
+
- **WHEN** schema path is relative (e.g., `./node_modules/...` or `./schemas/...`)
|
|
671
|
+
- **THEN** system resolves path relative to config file location
|
|
672
|
+
- **AND** loads schema for IDE and CLI validation
|
|
673
|
+
|
|
674
|
+
## Custom Handler Requirements
|
|
675
|
+
|
|
676
|
+
### Requirement: Custom Handler Escape Hatch
|
|
677
|
+
|
|
678
|
+
The system SHALL support custom handlers for edge cases not expressible via declarative options:
|
|
679
|
+
|
|
680
|
+
- **Handler registration**: Register handler functions in CLI code
|
|
681
|
+
- **Handler invocation**: Invoke handler when `handler: "name"` specified in flow
|
|
682
|
+
- **Handler context**: Provide full flow context (source, target, package info) to handlers
|
|
683
|
+
- **Handler errors**: Report handler errors clearly with handler name and context
|
|
684
|
+
- **Not user-configurable**: Handlers require CLI code changes, not available in user configs
|
|
685
|
+
|
|
686
|
+
#### Scenario: Custom handler for complex transformation
|
|
687
|
+
|
|
688
|
+
- **WHEN** flow defines `handler: "custom-mcp-transform"`
|
|
689
|
+
- **AND** handler is registered in CLI code
|
|
690
|
+
- **THEN** handler function is invoked with source content and full context
|
|
691
|
+
|
|
692
|
+
#### Scenario: Handler not found error
|
|
693
|
+
|
|
694
|
+
- **WHEN** flow references unregistered handler name
|
|
695
|
+
- **THEN** execution fails with error: "Handler 'xyz' not found. Available: [list]"
|
|
696
|
+
|
|
697
|
+
#### Scenario: Handler error with context
|
|
698
|
+
|
|
699
|
+
- **WHEN** custom handler throws error during execution
|
|
700
|
+
- **THEN** error is caught and reported with handler name, source file, and error details
|