@lesliechan721/aw 0.1.0-beta.3
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/dist/authoring/assets/aw-config.d.mts +2 -0
- package/dist/authoring/assets/aw-config.mjs +556 -0
- package/dist/authoring/assets/aw-config.mjs.map +1 -0
- package/dist/authoring/scripts/add-skill.d.mts +2 -0
- package/dist/authoring/scripts/add-skill.mjs +355 -0
- package/dist/authoring/scripts/add-skill.mjs.map +1 -0
- package/dist/authoring/scripts/check-plugin-versions.d.mts +2 -0
- package/dist/authoring/scripts/check-plugin-versions.mjs +5 -0
- package/dist/authoring/scripts/check-plugin-versions.mjs.map +1 -0
- package/dist/authoring/scripts/init-plugin.d.mts +2 -0
- package/dist/authoring/scripts/init-plugin.mjs +512 -0
- package/dist/authoring/scripts/init-plugin.mjs.map +1 -0
- package/dist/authoring/scripts/lib/javascript-import-scanner.d.mts +4 -0
- package/dist/authoring/scripts/lib/javascript-import-scanner.mjs +261 -0
- package/dist/authoring/scripts/lib/javascript-import-scanner.mjs.map +1 -0
- package/dist/authoring/scripts/lib/plugin-root.d.mts +26 -0
- package/dist/authoring/scripts/lib/plugin-root.mjs +125 -0
- package/dist/authoring/scripts/lib/plugin-root.mjs.map +1 -0
- package/dist/authoring/scripts/lib/plugin-version-check.d.mts +55 -0
- package/dist/authoring/scripts/lib/plugin-version-check.mjs +777 -0
- package/dist/authoring/scripts/lib/plugin-version-check.mjs.map +1 -0
- package/dist/authoring/scripts/lib/semver.d.mts +9 -0
- package/dist/authoring/scripts/lib/semver.mjs +63 -0
- package/dist/authoring/scripts/lib/semver.mjs.map +1 -0
- package/dist/authoring/scripts/lib/skill-scaffold.d.mts +124 -0
- package/dist/authoring/scripts/lib/skill-scaffold.mjs +374 -0
- package/dist/authoring/scripts/lib/skill-scaffold.mjs.map +1 -0
- package/dist/authoring/scripts/plugin-status.d.mts +2 -0
- package/dist/authoring/scripts/plugin-status.mjs +96 -0
- package/dist/authoring/scripts/plugin-status.mjs.map +1 -0
- package/dist/authoring/scripts/validate-plugin.d.mts +2 -0
- package/dist/authoring/scripts/validate-plugin.mjs +4442 -0
- package/dist/authoring/scripts/validate-plugin.mjs.map +1 -0
- package/dist/authoring/scripts/validate-skill.d.mts +2 -0
- package/dist/authoring/scripts/validate-skill.mjs +126 -0
- package/dist/authoring/scripts/validate-skill.mjs.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/scripts/aw-skill-eval-engine.d.ts +13 -0
- package/dist/scripts/aw-skill-eval-engine.js +31 -0
- package/dist/scripts/aw-skill-eval-engine.js.map +1 -0
- package/dist/scripts/bundle-plugins.d.ts +18 -0
- package/dist/scripts/bundle-plugins.js +123 -0
- package/dist/scripts/bundle-plugins.js.map +1 -0
- package/dist/scripts/codex-eval-app-server.d.ts +89 -0
- package/dist/scripts/codex-eval-app-server.js +1228 -0
- package/dist/scripts/codex-eval-app-server.js.map +1 -0
- package/dist/scripts/codex-eval-isolation.d.ts +61 -0
- package/dist/scripts/codex-eval-isolation.js +318 -0
- package/dist/scripts/codex-eval-isolation.js.map +1 -0
- package/dist/scripts/codex-eval-process-management.d.ts +8 -0
- package/dist/scripts/codex-eval-process-management.js +69 -0
- package/dist/scripts/codex-eval-process-management.js.map +1 -0
- package/dist/scripts/codex-eval-process-tree.d.ts +38 -0
- package/dist/scripts/codex-eval-process-tree.js +803 -0
- package/dist/scripts/codex-eval-process-tree.js.map +1 -0
- package/dist/scripts/codex-eval-runtime-config.d.ts +62 -0
- package/dist/scripts/codex-eval-runtime-config.js +843 -0
- package/dist/scripts/codex-eval-runtime-config.js.map +1 -0
- package/dist/scripts/codex-trigger-eval.d.ts +84 -0
- package/dist/scripts/codex-trigger-eval.js +968 -0
- package/dist/scripts/codex-trigger-eval.js.map +1 -0
- package/dist/scripts/eval-plugin-skills-audited.d.ts +6 -0
- package/dist/scripts/eval-plugin-skills-audited.js +261 -0
- package/dist/scripts/eval-plugin-skills-audited.js.map +1 -0
- package/dist/scripts/eval-plugin-skills.d.ts +45 -0
- package/dist/scripts/eval-plugin-skills.js +1586 -0
- package/dist/scripts/eval-plugin-skills.js.map +1 -0
- package/dist/scripts/eval-run-layout.d.ts +17 -0
- package/dist/scripts/eval-run-layout.js +26 -0
- package/dist/scripts/eval-run-layout.js.map +1 -0
- package/dist/scripts/plugin-eval-contract.d.ts +185 -0
- package/dist/scripts/plugin-eval-contract.js +695 -0
- package/dist/scripts/plugin-eval-contract.js.map +1 -0
- package/dist/scripts/plugin-eval-materializer.d.ts +13 -0
- package/dist/scripts/plugin-eval-materializer.js +421 -0
- package/dist/scripts/plugin-eval-materializer.js.map +1 -0
- package/dist/scripts/plugin-staging.d.ts +43 -0
- package/dist/scripts/plugin-staging.js +196 -0
- package/dist/scripts/plugin-staging.js.map +1 -0
- package/dist/scripts/skill-reporting.d.ts +212 -0
- package/dist/scripts/skill-reporting.js +922 -0
- package/dist/scripts/skill-reporting.js.map +1 -0
- package/dist/scripts/test-plugin-scripts.d.ts +7 -0
- package/dist/scripts/test-plugin-scripts.js +674 -0
- package/dist/scripts/test-plugin-scripts.js.map +1 -0
- package/dist/src/adapters/helpers.d.ts +44 -0
- package/dist/src/adapters/helpers.js +95 -0
- package/dist/src/adapters/helpers.js.map +1 -0
- package/dist/src/authoring/workspace-commands.d.ts +46 -0
- package/dist/src/authoring/workspace-commands.js +133 -0
- package/dist/src/authoring/workspace-commands.js.map +1 -0
- package/dist/src/commands/catalog-publish.d.ts +33 -0
- package/dist/src/commands/catalog-publish.js +374 -0
- package/dist/src/commands/catalog-publish.js.map +1 -0
- package/dist/src/commands/catalog-source.d.ts +111 -0
- package/dist/src/commands/catalog-source.js +266 -0
- package/dist/src/commands/catalog-source.js.map +1 -0
- package/dist/src/commands/console.d.ts +3 -0
- package/dist/src/commands/console.js +44 -0
- package/dist/src/commands/console.js.map +1 -0
- package/dist/src/commands/dependency-operation-plan.d.ts +28 -0
- package/dist/src/commands/dependency-operation-plan.js +15 -0
- package/dist/src/commands/dependency-operation-plan.js.map +1 -0
- package/dist/src/commands/init.d.ts +31 -0
- package/dist/src/commands/init.js +63 -0
- package/dist/src/commands/init.js.map +1 -0
- package/dist/src/commands/options.d.ts +68 -0
- package/dist/src/commands/options.js +146 -0
- package/dist/src/commands/options.js.map +1 -0
- package/dist/src/commands/rebuild-command.d.ts +77 -0
- package/dist/src/commands/rebuild-command.js +1681 -0
- package/dist/src/commands/rebuild-command.js.map +1 -0
- package/dist/src/commands/rebuild-integration.d.ts +94 -0
- package/dist/src/commands/rebuild-integration.js +3289 -0
- package/dist/src/commands/rebuild-integration.js.map +1 -0
- package/dist/src/commands/rebuild-operations.d.ts +110 -0
- package/dist/src/commands/rebuild-operations.js +791 -0
- package/dist/src/commands/rebuild-operations.js.map +1 -0
- package/dist/src/commands/review-publication.d.ts +99 -0
- package/dist/src/commands/review-publication.js +904 -0
- package/dist/src/commands/review-publication.js.map +1 -0
- package/dist/src/commands/runtime.d.ts +176 -0
- package/dist/src/commands/runtime.js +746 -0
- package/dist/src/commands/runtime.js.map +1 -0
- package/dist/src/commands/status-v4.d.ts +102 -0
- package/dist/src/commands/status-v4.js +844 -0
- package/dist/src/commands/status-v4.js.map +1 -0
- package/dist/src/commands/status.d.ts +93 -0
- package/dist/src/commands/status.js +442 -0
- package/dist/src/commands/status.js.map +1 -0
- package/dist/src/commands/wizard.d.ts +57 -0
- package/dist/src/commands/wizard.js +58 -0
- package/dist/src/commands/wizard.js.map +1 -0
- package/dist/src/commands/write-commands.d.ts +7 -0
- package/dist/src/commands/write-commands.js +167 -0
- package/dist/src/commands/write-commands.js.map +1 -0
- package/dist/src/constants.d.ts +25 -0
- package/dist/src/constants.js +26 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/generators/agents.d.ts +3 -0
- package/dist/src/generators/agents.js +46 -0
- package/dist/src/generators/agents.js.map +1 -0
- package/dist/src/generators/hooks.d.ts +15 -0
- package/dist/src/generators/hooks.js +76 -0
- package/dist/src/generators/hooks.js.map +1 -0
- package/dist/src/generators/instructions.d.ts +13 -0
- package/dist/src/generators/instructions.js +66 -0
- package/dist/src/generators/instructions.js.map +1 -0
- package/dist/src/generators/local-plugin.d.ts +53 -0
- package/dist/src/generators/local-plugin.js +1268 -0
- package/dist/src/generators/local-plugin.js.map +1 -0
- package/dist/src/generators/permissions.d.ts +10 -0
- package/dist/src/generators/permissions.js +37 -0
- package/dist/src/generators/permissions.js.map +1 -0
- package/dist/src/generators/shared.d.ts +2 -0
- package/dist/src/generators/shared.js +15 -0
- package/dist/src/generators/shared.js.map +1 -0
- package/dist/src/index.d.ts +35 -0
- package/dist/src/index.js +2344 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/output/command-receipt.d.ts +90 -0
- package/dist/src/output/command-receipt.js +129 -0
- package/dist/src/output/command-receipt.js.map +1 -0
- package/dist/src/output/debug-log.d.ts +4 -0
- package/dist/src/output/debug-log.js +97 -0
- package/dist/src/output/debug-log.js.map +1 -0
- package/dist/src/output/equivalent-command.d.ts +9 -0
- package/dist/src/output/equivalent-command.js +39 -0
- package/dist/src/output/equivalent-command.js.map +1 -0
- package/dist/src/output/model.d.ts +117 -0
- package/dist/src/output/model.js +145 -0
- package/dist/src/output/model.js.map +1 -0
- package/dist/src/output/rebuild-progress.d.ts +21 -0
- package/dist/src/output/rebuild-progress.js +138 -0
- package/dist/src/output/rebuild-progress.js.map +1 -0
- package/dist/src/output/redact.d.ts +3 -0
- package/dist/src/output/redact.js +39 -0
- package/dist/src/output/redact.js.map +1 -0
- package/dist/src/output/reporter.d.ts +9 -0
- package/dist/src/output/reporter.js +133 -0
- package/dist/src/output/reporter.js.map +1 -0
- package/dist/src/portable/commands.d.ts +120 -0
- package/dist/src/portable/commands.js +506 -0
- package/dist/src/portable/commands.js.map +1 -0
- package/dist/src/portable/materializer.d.ts +50 -0
- package/dist/src/portable/materializer.js +408 -0
- package/dist/src/portable/materializer.js.map +1 -0
- package/dist/src/portable/skills-cli.d.ts +43 -0
- package/dist/src/portable/skills-cli.js +148 -0
- package/dist/src/portable/skills-cli.js.map +1 -0
- package/dist/src/tui/components.d.ts +32 -0
- package/dist/src/tui/components.js +42 -0
- package/dist/src/tui/components.js.map +1 -0
- package/dist/src/tui/console-app-v4.d.ts +20 -0
- package/dist/src/tui/console-app-v4.js +2613 -0
- package/dist/src/tui/console-app-v4.js.map +1 -0
- package/dist/src/tui/controller-runtime.d.ts +11 -0
- package/dist/src/tui/controller-runtime.js +902 -0
- package/dist/src/tui/controller-runtime.js.map +1 -0
- package/dist/src/tui/controller.d.ts +367 -0
- package/dist/src/tui/controller.js +1724 -0
- package/dist/src/tui/controller.js.map +1 -0
- package/dist/src/tui/index.d.ts +13 -0
- package/dist/src/tui/index.js +14 -0
- package/dist/src/tui/index.js.map +1 -0
- package/dist/src/tui/keys.d.ts +12 -0
- package/dist/src/tui/keys.js +22 -0
- package/dist/src/tui/keys.js.map +1 -0
- package/dist/src/tui/layout.d.ts +12 -0
- package/dist/src/tui/layout.js +19 -0
- package/dist/src/tui/layout.js.map +1 -0
- package/dist/src/tui/model.d.ts +279 -0
- package/dist/src/tui/model.js +652 -0
- package/dist/src/tui/model.js.map +1 -0
- package/dist/src/tui/prompt.d.ts +8 -0
- package/dist/src/tui/prompt.js +242 -0
- package/dist/src/tui/prompt.js.map +1 -0
- package/dist/src/tui/router.d.ts +153 -0
- package/dist/src/tui/router.js +102 -0
- package/dist/src/tui/router.js.map +1 -0
- package/dist/src/tui/runner.d.ts +11 -0
- package/dist/src/tui/runner.js +71 -0
- package/dist/src/tui/runner.js.map +1 -0
- package/dist/src/tui/theme.d.ts +18 -0
- package/dist/src/tui/theme.js +20 -0
- package/dist/src/tui/theme.js.map +1 -0
- package/dist/src/tui/views.d.ts +57 -0
- package/dist/src/tui/views.js +173 -0
- package/dist/src/tui/views.js.map +1 -0
- package/dist/src/tui/wizard.d.ts +11 -0
- package/dist/src/tui/wizard.js +321 -0
- package/dist/src/tui/wizard.js.map +1 -0
- package/dist/src/types.d.ts +313 -0
- package/dist/src/types.js +33 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/utils/active-marketplace-runtime-lock.d.ts +12 -0
- package/dist/src/utils/active-marketplace-runtime-lock.js +133 -0
- package/dist/src/utils/active-marketplace-runtime-lock.js.map +1 -0
- package/dist/src/utils/agent-version.d.ts +13 -0
- package/dist/src/utils/agent-version.js +172 -0
- package/dist/src/utils/agent-version.js.map +1 -0
- package/dist/src/utils/artifact-plan.d.ts +26 -0
- package/dist/src/utils/artifact-plan.js +444 -0
- package/dist/src/utils/artifact-plan.js.map +1 -0
- package/dist/src/utils/artifact-renderer.d.ts +124 -0
- package/dist/src/utils/artifact-renderer.js +442 -0
- package/dist/src/utils/artifact-renderer.js.map +1 -0
- package/dist/src/utils/artifact-sources.d.ts +8 -0
- package/dist/src/utils/artifact-sources.js +10 -0
- package/dist/src/utils/artifact-sources.js.map +1 -0
- package/dist/src/utils/aw-home-mutation-lock.d.ts +10 -0
- package/dist/src/utils/aw-home-mutation-lock.js +55 -0
- package/dist/src/utils/aw-home-mutation-lock.js.map +1 -0
- package/dist/src/utils/bundle-integrity.d.ts +3 -0
- package/dist/src/utils/bundle-integrity.js +88 -0
- package/dist/src/utils/bundle-integrity.js.map +1 -0
- package/dist/src/utils/bundle-layout.d.ts +4 -0
- package/dist/src/utils/bundle-layout.js +546 -0
- package/dist/src/utils/bundle-layout.js.map +1 -0
- package/dist/src/utils/catalog-digests.d.ts +8 -0
- package/dist/src/utils/catalog-digests.js +108 -0
- package/dist/src/utils/catalog-digests.js.map +1 -0
- package/dist/src/utils/catalog-manifest-v3.d.ts +2 -0
- package/dist/src/utils/catalog-manifest-v3.js +3 -0
- package/dist/src/utils/catalog-manifest-v3.js.map +1 -0
- package/dist/src/utils/catalog-manifest-v4.d.ts +5 -0
- package/dist/src/utils/catalog-manifest-v4.js +106 -0
- package/dist/src/utils/catalog-manifest-v4.js.map +1 -0
- package/dist/src/utils/catalog-public-error.d.ts +15 -0
- package/dist/src/utils/catalog-public-error.js +84 -0
- package/dist/src/utils/catalog-public-error.js.map +1 -0
- package/dist/src/utils/catalog-runtime-projection.d.ts +36 -0
- package/dist/src/utils/catalog-runtime-projection.js +172 -0
- package/dist/src/utils/catalog-runtime-projection.js.map +1 -0
- package/dist/src/utils/catalog-snapshot.d.ts +8 -0
- package/dist/src/utils/catalog-snapshot.js +12 -0
- package/dist/src/utils/catalog-snapshot.js.map +1 -0
- package/dist/src/utils/catalog-source-cache.d.ts +61 -0
- package/dist/src/utils/catalog-source-cache.js +276 -0
- package/dist/src/utils/catalog-source-cache.js.map +1 -0
- package/dist/src/utils/catalog-source-identity.d.ts +4 -0
- package/dist/src/utils/catalog-source-identity.js +118 -0
- package/dist/src/utils/catalog-source-identity.js.map +1 -0
- package/dist/src/utils/catalog-source-presentation.d.ts +1 -0
- package/dist/src/utils/catalog-source-presentation.js +32 -0
- package/dist/src/utils/catalog-source-presentation.js.map +1 -0
- package/dist/src/utils/catalog-source-references.d.ts +65 -0
- package/dist/src/utils/catalog-source-references.js +1418 -0
- package/dist/src/utils/catalog-source-references.js.map +1 -0
- package/dist/src/utils/catalog-sources.d.ts +39 -0
- package/dist/src/utils/catalog-sources.js +293 -0
- package/dist/src/utils/catalog-sources.js.map +1 -0
- package/dist/src/utils/codex-config.d.ts +124 -0
- package/dist/src/utils/codex-config.js +1011 -0
- package/dist/src/utils/codex-config.js.map +1 -0
- package/dist/src/utils/codex-project-surface.d.ts +3 -0
- package/dist/src/utils/codex-project-surface.js +49 -0
- package/dist/src/utils/codex-project-surface.js.map +1 -0
- package/dist/src/utils/codex-roles.d.ts +71 -0
- package/dist/src/utils/codex-roles.js +257 -0
- package/dist/src/utils/codex-roles.js.map +1 -0
- package/dist/src/utils/codex-skill-staging.d.ts +9 -0
- package/dist/src/utils/codex-skill-staging.js +8 -0
- package/dist/src/utils/codex-skill-staging.js.map +1 -0
- package/dist/src/utils/config-value.d.ts +3 -0
- package/dist/src/utils/config-value.js +23 -0
- package/dist/src/utils/config-value.js.map +1 -0
- package/dist/src/utils/dynamic-skill-tree.d.ts +32 -0
- package/dist/src/utils/dynamic-skill-tree.js +436 -0
- package/dist/src/utils/dynamic-skill-tree.js.map +1 -0
- package/dist/src/utils/file-rules.d.ts +1 -0
- package/dist/src/utils/file-rules.js +2 -0
- package/dist/src/utils/file-rules.js.map +1 -0
- package/dist/src/utils/git-catalog-provider.d.ts +7 -0
- package/dist/src/utils/git-catalog-provider.js +510 -0
- package/dist/src/utils/git-catalog-provider.js.map +1 -0
- package/dist/src/utils/hooks-contract.d.ts +1 -0
- package/dist/src/utils/hooks-contract.js +2 -0
- package/dist/src/utils/hooks-contract.js.map +1 -0
- package/dist/src/utils/json.d.ts +4 -0
- package/dist/src/utils/json.js +29 -0
- package/dist/src/utils/json.js.map +1 -0
- package/dist/src/utils/lifecycle-active-store.d.ts +175 -0
- package/dist/src/utils/lifecycle-active-store.js +1276 -0
- package/dist/src/utils/lifecycle-active-store.js.map +1 -0
- package/dist/src/utils/local-marketplace.d.ts +41 -0
- package/dist/src/utils/local-marketplace.js +317 -0
- package/dist/src/utils/local-marketplace.js.map +1 -0
- package/dist/src/utils/manifest.d.ts +14 -0
- package/dist/src/utils/manifest.js +36 -0
- package/dist/src/utils/manifest.js.map +1 -0
- package/dist/src/utils/marketplace.d.ts +3 -0
- package/dist/src/utils/marketplace.js +76 -0
- package/dist/src/utils/marketplace.js.map +1 -0
- package/dist/src/utils/multi-source-catalog.d.ts +72 -0
- package/dist/src/utils/multi-source-catalog.js +402 -0
- package/dist/src/utils/multi-source-catalog.js.map +1 -0
- package/dist/src/utils/native-cli.d.ts +75 -0
- package/dist/src/utils/native-cli.js +435 -0
- package/dist/src/utils/native-cli.js.map +1 -0
- package/dist/src/utils/orphan-marketplace-cleanup.d.ts +18 -0
- package/dist/src/utils/orphan-marketplace-cleanup.js +202 -0
- package/dist/src/utils/orphan-marketplace-cleanup.js.map +1 -0
- package/dist/src/utils/ownership.d.ts +130 -0
- package/dist/src/utils/ownership.js +766 -0
- package/dist/src/utils/ownership.js.map +1 -0
- package/dist/src/utils/path-catalog-provider.d.ts +7 -0
- package/dist/src/utils/path-catalog-provider.js +87 -0
- package/dist/src/utils/path-catalog-provider.js.map +1 -0
- package/dist/src/utils/paths.d.ts +41 -0
- package/dist/src/utils/paths.js +138 -0
- package/dist/src/utils/paths.js.map +1 -0
- package/dist/src/utils/platform-entries.d.ts +1 -0
- package/dist/src/utils/platform-entries.js +2 -0
- package/dist/src/utils/platform-entries.js.map +1 -0
- package/dist/src/utils/platform-support.d.ts +1 -0
- package/dist/src/utils/platform-support.js +2 -0
- package/dist/src/utils/platform-support.js.map +1 -0
- package/dist/src/utils/plugin-authoring-capabilities.d.ts +23 -0
- package/dist/src/utils/plugin-authoring-capabilities.js +37 -0
- package/dist/src/utils/plugin-authoring-capabilities.js.map +1 -0
- package/dist/src/utils/plugin-authoring-capabilities.json +92 -0
- package/dist/src/utils/plugin-config-write.d.ts +107 -0
- package/dist/src/utils/plugin-config-write.js +565 -0
- package/dist/src/utils/plugin-config-write.js.map +1 -0
- package/dist/src/utils/plugin-config.d.ts +396 -0
- package/dist/src/utils/plugin-config.js +1898 -0
- package/dist/src/utils/plugin-config.js.map +1 -0
- package/dist/src/utils/plugin-dependencies.d.ts +12 -0
- package/dist/src/utils/plugin-dependencies.js +162 -0
- package/dist/src/utils/plugin-dependencies.js.map +1 -0
- package/dist/src/utils/plugin-release.d.ts +2 -0
- package/dist/src/utils/plugin-release.js +2 -0
- package/dist/src/utils/plugin-release.js.map +1 -0
- package/dist/src/utils/plugin-script-contract.d.ts +1 -0
- package/dist/src/utils/plugin-script-contract.js +2 -0
- package/dist/src/utils/plugin-script-contract.js.map +1 -0
- package/dist/src/utils/plugin-scripts.d.ts +172 -0
- package/dist/src/utils/plugin-scripts.js +585 -0
- package/dist/src/utils/plugin-scripts.js.map +1 -0
- package/dist/src/utils/process-lock.d.ts +47 -0
- package/dist/src/utils/process-lock.js +532 -0
- package/dist/src/utils/process-lock.js.map +1 -0
- package/dist/src/utils/process-tree.d.ts +2 -0
- package/dist/src/utils/process-tree.js +2 -0
- package/dist/src/utils/process-tree.js.map +1 -0
- package/dist/src/utils/project-boundary.d.ts +21 -0
- package/dist/src/utils/project-boundary.js +95 -0
- package/dist/src/utils/project-boundary.js.map +1 -0
- package/dist/src/utils/rendered-contract.d.ts +8 -0
- package/dist/src/utils/rendered-contract.js +134 -0
- package/dist/src/utils/rendered-contract.js.map +1 -0
- package/dist/src/utils/runtime-skill-closure.d.ts +13 -0
- package/dist/src/utils/runtime-skill-closure.js +863 -0
- package/dist/src/utils/runtime-skill-closure.js.map +1 -0
- package/dist/src/utils/skill-authoring.d.ts +1 -0
- package/dist/src/utils/skill-authoring.js +2 -0
- package/dist/src/utils/skill-authoring.js.map +1 -0
- package/dist/src/utils/skill-frontmatter-capabilities.d.ts +201 -0
- package/dist/src/utils/skill-frontmatter-capabilities.js +5 -0
- package/dist/src/utils/skill-frontmatter-capabilities.js.map +1 -0
- package/dist/src/utils/skill-frontmatter-capabilities.json +200 -0
- package/dist/src/utils/skill-validation.d.ts +37 -0
- package/dist/src/utils/skill-validation.js +326 -0
- package/dist/src/utils/skill-validation.js.map +1 -0
- package/dist/src/utils/slash-commands.d.ts +1 -0
- package/dist/src/utils/slash-commands.js +2 -0
- package/dist/src/utils/slash-commands.js.map +1 -0
- package/dist/src/utils/state-paths.d.ts +13 -0
- package/dist/src/utils/state-paths.js +129 -0
- package/dist/src/utils/state-paths.js.map +1 -0
- package/dist/src/utils/target-eligibility.d.ts +7 -0
- package/dist/src/utils/target-eligibility.js +26 -0
- package/dist/src/utils/target-eligibility.js.map +1 -0
- package/dist/src/utils/target-order.d.ts +7 -0
- package/dist/src/utils/target-order.js +10 -0
- package/dist/src/utils/target-order.js.map +1 -0
- package/dist/src/utils/template-engine.d.ts +1 -0
- package/dist/src/utils/template-engine.js +2 -0
- package/dist/src/utils/template-engine.js.map +1 -0
- package/dist/src/utils/test-path-fence.d.ts +12 -0
- package/dist/src/utils/test-path-fence.js +31 -0
- package/dist/src/utils/test-path-fence.js.map +1 -0
- package/dist/vitest.config.d.ts +2 -0
- package/dist/vitest.config.js +16 -0
- package/dist/vitest.config.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,766 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import { promises as nodeFs } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import fs from 'fs-extra';
|
|
5
|
+
export const SKILL_OWNER_MARKER = '.agent-workflows-owner.json';
|
|
6
|
+
export const OWNED_TEXT_HEADER_PREFIX = '# agent-workflows-owner: ';
|
|
7
|
+
export const SHARED_OWNER_TOKEN_PREFIX = 'aw-owner-v2:';
|
|
8
|
+
export function createSharedOwnerToken(identity) {
|
|
9
|
+
validateOwnerIdentity(identity);
|
|
10
|
+
if (!identity.sourceId)
|
|
11
|
+
return identity.plugin;
|
|
12
|
+
return `${SHARED_OWNER_TOKEN_PREFIX}${Buffer.from(createSkillOwnerMarkerContent(identity)).toString('base64url')}`;
|
|
13
|
+
}
|
|
14
|
+
export function parseSharedOwnerToken(value) {
|
|
15
|
+
if (!value.startsWith(SHARED_OWNER_TOKEN_PREFIX))
|
|
16
|
+
return null;
|
|
17
|
+
let parsed;
|
|
18
|
+
try {
|
|
19
|
+
parsed = JSON.parse(Buffer.from(value.slice(SHARED_OWNER_TOKEN_PREFIX.length), 'base64url').toString('utf8'));
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
throw new Error('Shared owner token is invalid.');
|
|
23
|
+
}
|
|
24
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)
|
|
25
|
+
|| parsed.schemaVersion !== 2) {
|
|
26
|
+
throw new Error('Shared owner token must contain schema 2 identity.');
|
|
27
|
+
}
|
|
28
|
+
return parseOwnerIdentity(parsed, 'Shared owner token');
|
|
29
|
+
}
|
|
30
|
+
class OwnershipSymlinkError extends Error {
|
|
31
|
+
}
|
|
32
|
+
let atomicReplaceBeforeRenameHookForTests;
|
|
33
|
+
export function setAtomicReplaceBeforeRenameHookForTests(hook) {
|
|
34
|
+
atomicReplaceBeforeRenameHookForTests = hook;
|
|
35
|
+
}
|
|
36
|
+
function isMissing(error) {
|
|
37
|
+
const code = error.code;
|
|
38
|
+
return code === 'ENOENT' || code === 'ENOTDIR';
|
|
39
|
+
}
|
|
40
|
+
function errorMessage(error) {
|
|
41
|
+
return error instanceof Error ? error.message : String(error);
|
|
42
|
+
}
|
|
43
|
+
export function assertSafeOwnershipSegment(value, label) {
|
|
44
|
+
if (typeof value !== 'string' ||
|
|
45
|
+
value === '.' ||
|
|
46
|
+
value === '..' ||
|
|
47
|
+
value.endsWith('.') ||
|
|
48
|
+
!/^[A-Za-z0-9][A-Za-z0-9._-]*$/u.test(value)) {
|
|
49
|
+
throw new Error(`${label} 必须是安全的单一路径 segment:${JSON.stringify(value)}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export function validateOwnerIdentity(identity) {
|
|
53
|
+
if (identity.owner !== 'agent-workflows') {
|
|
54
|
+
throw new Error('Owner identity.owner 必须是 "agent-workflows"。');
|
|
55
|
+
}
|
|
56
|
+
assertSafeOwnershipSegment(identity.plugin, 'Owner identity.plugin');
|
|
57
|
+
assertSafeOwnershipSegment(identity.artifactKey, 'Owner identity.artifactKey');
|
|
58
|
+
const sourceFields = [identity.sourceId, identity.sourceIdentity, identity.pluginId];
|
|
59
|
+
if (sourceFields.some((value) => value !== undefined)) {
|
|
60
|
+
if (sourceFields.some((value) => typeof value !== 'string' || value.length === 0)) {
|
|
61
|
+
throw new Error('Owner identity source fields must be present together.');
|
|
62
|
+
}
|
|
63
|
+
assertSafeOwnershipSegment(identity.sourceId, 'Owner identity.sourceId');
|
|
64
|
+
if (!/^sha256:[0-9a-f]{64}$/u.test(identity.sourceIdentity)) {
|
|
65
|
+
throw new Error('Owner identity.sourceIdentity must be a SHA-256 digest.');
|
|
66
|
+
}
|
|
67
|
+
if (identity.pluginId !== `${identity.sourceId}/${identity.plugin}`) {
|
|
68
|
+
throw new Error('Owner identity.pluginId must be the canonical sourceId/plugin name.');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (identity.platform !== 'codex' && identity.platform !== 'claude') {
|
|
72
|
+
throw new Error(`Owner identity.platform 无效:${String(identity.platform)}`);
|
|
73
|
+
}
|
|
74
|
+
if (identity.scope !== 'user' && identity.scope !== 'project') {
|
|
75
|
+
throw new Error(`Owner identity.scope 无效:${String(identity.scope)}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function identitiesEqual(left, right) {
|
|
79
|
+
return left.owner === right.owner &&
|
|
80
|
+
left.sourceId === right.sourceId &&
|
|
81
|
+
left.sourceIdentity === right.sourceIdentity &&
|
|
82
|
+
left.pluginId === right.pluginId &&
|
|
83
|
+
left.plugin === right.plugin &&
|
|
84
|
+
left.artifactKey === right.artifactKey &&
|
|
85
|
+
left.platform === right.platform &&
|
|
86
|
+
left.scope === right.scope;
|
|
87
|
+
}
|
|
88
|
+
function markerFromIdentity(identity) {
|
|
89
|
+
validateOwnerIdentity(identity);
|
|
90
|
+
const namespaced = identity.sourceId !== undefined;
|
|
91
|
+
return {
|
|
92
|
+
schemaVersion: namespaced ? 2 : 1,
|
|
93
|
+
owner: identity.owner,
|
|
94
|
+
...(namespaced ? {
|
|
95
|
+
sourceId: identity.sourceId,
|
|
96
|
+
sourceIdentity: identity.sourceIdentity,
|
|
97
|
+
pluginId: identity.pluginId,
|
|
98
|
+
} : {}),
|
|
99
|
+
plugin: identity.plugin,
|
|
100
|
+
artifactKey: identity.artifactKey,
|
|
101
|
+
platform: identity.platform,
|
|
102
|
+
scope: identity.scope,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function parseOwnerIdentity(value, label) {
|
|
106
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
107
|
+
throw new Error(`${label} 必须是 object。`);
|
|
108
|
+
}
|
|
109
|
+
const record = value;
|
|
110
|
+
const allowedKeys = new Set([
|
|
111
|
+
'schemaVersion',
|
|
112
|
+
'owner',
|
|
113
|
+
'sourceId',
|
|
114
|
+
'sourceIdentity',
|
|
115
|
+
'pluginId',
|
|
116
|
+
'plugin',
|
|
117
|
+
'artifactKey',
|
|
118
|
+
'platform',
|
|
119
|
+
'scope',
|
|
120
|
+
]);
|
|
121
|
+
if (Object.keys(record).some((key) => !allowedKeys.has(key))) {
|
|
122
|
+
throw new Error(`${label} 包含未知字段。`);
|
|
123
|
+
}
|
|
124
|
+
if (record.schemaVersion !== 1 && record.schemaVersion !== 2) {
|
|
125
|
+
throw new Error(`${label}.schemaVersion 不受支持。`);
|
|
126
|
+
}
|
|
127
|
+
if (record.schemaVersion === 2 && (typeof record.sourceId !== 'string'
|
|
128
|
+
|| typeof record.sourceIdentity !== 'string'
|
|
129
|
+
|| typeof record.pluginId !== 'string')) {
|
|
130
|
+
throw new Error(`${label}.schemaVersion 必须是 1,或提供完整 schema 2 source identity。`);
|
|
131
|
+
}
|
|
132
|
+
const identity = {
|
|
133
|
+
owner: record.owner,
|
|
134
|
+
...(record.schemaVersion === 2 ? {
|
|
135
|
+
sourceId: record.sourceId,
|
|
136
|
+
sourceIdentity: record.sourceIdentity,
|
|
137
|
+
pluginId: record.pluginId,
|
|
138
|
+
} : {}),
|
|
139
|
+
plugin: record.plugin,
|
|
140
|
+
artifactKey: record.artifactKey,
|
|
141
|
+
platform: record.platform,
|
|
142
|
+
scope: record.scope,
|
|
143
|
+
};
|
|
144
|
+
validateOwnerIdentity(identity);
|
|
145
|
+
return identity;
|
|
146
|
+
}
|
|
147
|
+
export function createSkillOwnerMarkerContent(identity) {
|
|
148
|
+
return `${JSON.stringify(markerFromIdentity(identity), null, 2)}\n`;
|
|
149
|
+
}
|
|
150
|
+
function assertPathBoundary(allowedRoot, candidatePath) {
|
|
151
|
+
const root = path.resolve(allowedRoot);
|
|
152
|
+
const candidate = path.resolve(candidatePath);
|
|
153
|
+
const relative = path.relative(root, candidate);
|
|
154
|
+
if (relative === '' || relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
|
|
155
|
+
throw new Error(`Ownership 路径越界:${candidate} 不在 ${root} 的子路径中。`);
|
|
156
|
+
}
|
|
157
|
+
return { root, candidate };
|
|
158
|
+
}
|
|
159
|
+
async function assertNoSymlinkInPath(allowedRoot, candidatePath) {
|
|
160
|
+
const { root, candidate } = assertPathBoundary(allowedRoot, candidatePath);
|
|
161
|
+
const relativeSegments = path.relative(root, candidate).split(path.sep);
|
|
162
|
+
const paths = [root];
|
|
163
|
+
let current = root;
|
|
164
|
+
for (const segment of relativeSegments) {
|
|
165
|
+
current = path.join(current, segment);
|
|
166
|
+
paths.push(current);
|
|
167
|
+
}
|
|
168
|
+
for (const currentPath of paths) {
|
|
169
|
+
const stats = await fs.lstat(currentPath).catch((error) => {
|
|
170
|
+
if (isMissing(error))
|
|
171
|
+
return null;
|
|
172
|
+
throw error;
|
|
173
|
+
});
|
|
174
|
+
if (stats?.isSymbolicLink()) {
|
|
175
|
+
throw new OwnershipSymlinkError(`Ownership 路径不能包含符号链接:${currentPath}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
async function readDirectoryIdentity(directoryPath) {
|
|
180
|
+
const stats = await fs.lstat(directoryPath);
|
|
181
|
+
if (stats.isSymbolicLink() || !stats.isDirectory()) {
|
|
182
|
+
throw new OwnershipSymlinkError(`Ownership 稳定目录必须是真实目录:${directoryPath}`);
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
dev: stats.dev,
|
|
186
|
+
ino: stats.ino,
|
|
187
|
+
realPath: await fs.realpath(directoryPath),
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function assertStableDirectory(label, before, after) {
|
|
191
|
+
if (before.dev !== after.dev || before.ino !== after.ino || before.realPath !== after.realPath) {
|
|
192
|
+
throw new Error(`${label} identity 在 atomic rename 前发生变化。`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
function assertRealDirectoryBoundary(root, parent) {
|
|
196
|
+
const relative = path.relative(root.realPath, parent.realPath);
|
|
197
|
+
if (relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
|
|
198
|
+
throw new Error('Ownership parent realpath 不在 allowedRoot realpath 内。');
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
async function atomicReplaceFile(options) {
|
|
202
|
+
await assertNoSymlinkInPath(options.allowedRoot, options.path);
|
|
203
|
+
await fs.ensureDir(path.dirname(options.path));
|
|
204
|
+
await assertNoSymlinkInPath(options.allowedRoot, options.path);
|
|
205
|
+
const rootIdentity = await readDirectoryIdentity(path.resolve(options.allowedRoot));
|
|
206
|
+
const parentIdentity = await readDirectoryIdentity(path.dirname(path.resolve(options.path)));
|
|
207
|
+
assertRealDirectoryBoundary(rootIdentity, parentIdentity);
|
|
208
|
+
const temporaryPath = path.join(path.dirname(options.path), `.${path.basename(options.path)}.owner-${process.pid}-${crypto.randomUUID()}`);
|
|
209
|
+
assertPathBoundary(options.allowedRoot, temporaryPath);
|
|
210
|
+
let handle;
|
|
211
|
+
try {
|
|
212
|
+
handle = await nodeFs.open(temporaryPath, 'wx', 0o666);
|
|
213
|
+
await handle.writeFile(options.content, 'utf8');
|
|
214
|
+
await handle.close();
|
|
215
|
+
handle = undefined;
|
|
216
|
+
await atomicReplaceBeforeRenameHookForTests?.();
|
|
217
|
+
// Threat model: this blocks pre-existing symlinks/hardlinks, traversal, and callers that use
|
|
218
|
+
// this API concurrently. Node has no portable dirfd/openat/renameat2 sequence, so this does not
|
|
219
|
+
// claim to stop a process with the same file permissions from swapping a directory after this
|
|
220
|
+
// final check and before rename; that process can already edit or delete the user's files.
|
|
221
|
+
await assertNoSymlinkInPath(options.allowedRoot, options.path);
|
|
222
|
+
const currentRootIdentity = await readDirectoryIdentity(path.resolve(options.allowedRoot));
|
|
223
|
+
const currentParentIdentity = await readDirectoryIdentity(path.dirname(path.resolve(options.path)));
|
|
224
|
+
assertRealDirectoryBoundary(currentRootIdentity, currentParentIdentity);
|
|
225
|
+
assertStableDirectory('allowedRoot', rootIdentity, currentRootIdentity);
|
|
226
|
+
assertStableDirectory('parent', parentIdentity, currentParentIdentity);
|
|
227
|
+
await nodeFs.rename(temporaryPath, options.path);
|
|
228
|
+
}
|
|
229
|
+
finally {
|
|
230
|
+
await handle?.close().catch(() => undefined);
|
|
231
|
+
await nodeFs.rm(temporaryPath, { force: true }).catch(() => undefined);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
export async function assertOwnedSkillPath(options) {
|
|
235
|
+
validateOwnerIdentity(options.identity);
|
|
236
|
+
assertSafeOwnershipSegment(path.basename(options.skillRoot), 'Skill 目录名');
|
|
237
|
+
if (path.basename(options.skillRoot) !== options.identity.artifactKey) {
|
|
238
|
+
throw new Error('Skill 目录名必须与 owner artifactKey 一致。');
|
|
239
|
+
}
|
|
240
|
+
await assertNoSymlinkInPath(options.allowedRoot, options.skillRoot);
|
|
241
|
+
}
|
|
242
|
+
export async function writeSkillOwnerMarker(options) {
|
|
243
|
+
await assertOwnedSkillPath(options);
|
|
244
|
+
const stats = await fs.lstat(options.skillRoot).catch((error) => {
|
|
245
|
+
if (isMissing(error))
|
|
246
|
+
return null;
|
|
247
|
+
throw error;
|
|
248
|
+
});
|
|
249
|
+
if (!stats?.isDirectory()) {
|
|
250
|
+
throw new Error(`Skill owner marker 目标必须是真实目录:${options.skillRoot}`);
|
|
251
|
+
}
|
|
252
|
+
const markerPath = path.join(options.skillRoot, SKILL_OWNER_MARKER);
|
|
253
|
+
await atomicReplaceFile({
|
|
254
|
+
path: markerPath,
|
|
255
|
+
allowedRoot: options.allowedRoot,
|
|
256
|
+
content: createSkillOwnerMarkerContent(options.identity),
|
|
257
|
+
});
|
|
258
|
+
return markerPath;
|
|
259
|
+
}
|
|
260
|
+
async function readMarkerAt(markerPath) {
|
|
261
|
+
let raw;
|
|
262
|
+
try {
|
|
263
|
+
raw = await fs.readFile(markerPath, 'utf8');
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
if (isMissing(error))
|
|
267
|
+
return null;
|
|
268
|
+
throw error;
|
|
269
|
+
}
|
|
270
|
+
let parsed;
|
|
271
|
+
try {
|
|
272
|
+
parsed = JSON.parse(raw);
|
|
273
|
+
}
|
|
274
|
+
catch {
|
|
275
|
+
throw new Error(`Skill owner marker 不是有效 JSON:${markerPath}`);
|
|
276
|
+
}
|
|
277
|
+
return markerFromIdentity(parseOwnerIdentity(parsed, 'Skill owner marker'));
|
|
278
|
+
}
|
|
279
|
+
export async function readSkillOwnerMarker(options) {
|
|
280
|
+
if (options.expectedIdentity) {
|
|
281
|
+
await assertOwnedSkillPath({
|
|
282
|
+
skillRoot: options.skillRoot,
|
|
283
|
+
allowedRoot: options.allowedRoot,
|
|
284
|
+
identity: options.expectedIdentity,
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
assertSafeOwnershipSegment(path.basename(options.skillRoot), 'Skill 目录名');
|
|
289
|
+
await assertNoSymlinkInPath(options.allowedRoot, options.skillRoot);
|
|
290
|
+
}
|
|
291
|
+
const markerPath = path.join(options.skillRoot, SKILL_OWNER_MARKER);
|
|
292
|
+
await assertNoSymlinkInPath(options.allowedRoot, markerPath);
|
|
293
|
+
const marker = await readMarkerAt(markerPath);
|
|
294
|
+
if (!marker)
|
|
295
|
+
return null;
|
|
296
|
+
if (marker.artifactKey !== path.basename(options.skillRoot)) {
|
|
297
|
+
throw new Error('Skill owner marker artifactKey 与目录名不一致。');
|
|
298
|
+
}
|
|
299
|
+
if (options.expectedIdentity?.sourceId !== undefined && marker.schemaVersion === 1) {
|
|
300
|
+
throw new Error('legacyStateUnsupported: schema 1 owner marker is not supported.');
|
|
301
|
+
}
|
|
302
|
+
if (options.expectedIdentity?.sourceId !== undefined
|
|
303
|
+
&& marker.sourceId === options.expectedIdentity.sourceId
|
|
304
|
+
&& marker.sourceIdentity !== options.expectedIdentity.sourceIdentity) {
|
|
305
|
+
throw new Error('sourceChanged: owner source identity does not match the configured source.');
|
|
306
|
+
}
|
|
307
|
+
if (options.expectedIdentity && !identitiesEqual(marker, options.expectedIdentity)) {
|
|
308
|
+
throw new Error('Skill owner marker identity 与目标 identity 不匹配。');
|
|
309
|
+
}
|
|
310
|
+
return marker;
|
|
311
|
+
}
|
|
312
|
+
function ownerHeader(identity) {
|
|
313
|
+
return `${OWNED_TEXT_HEADER_PREFIX}${JSON.stringify(markerFromIdentity(identity))}`;
|
|
314
|
+
}
|
|
315
|
+
function frontmatterHeaderIndex(content) {
|
|
316
|
+
if (!content.startsWith('---\n'))
|
|
317
|
+
return 0;
|
|
318
|
+
const end = content.indexOf('\n---\n', 4);
|
|
319
|
+
if (end === -1) {
|
|
320
|
+
throw new Error('Owner header 目标包含未闭合的 YAML frontmatter。');
|
|
321
|
+
}
|
|
322
|
+
return end + '\n---\n'.length;
|
|
323
|
+
}
|
|
324
|
+
export function renderOwnedTextFile(content, identity) {
|
|
325
|
+
validateOwnerIdentity(identity);
|
|
326
|
+
const normalized = content.replace(/\r\n/gu, '\n');
|
|
327
|
+
const index = frontmatterHeaderIndex(normalized);
|
|
328
|
+
return `${normalized.slice(0, index)}${ownerHeader(identity)}\n${normalized.slice(index)}`;
|
|
329
|
+
}
|
|
330
|
+
export function parseOwnedTextHeader(content, expectedIdentity) {
|
|
331
|
+
const normalized = content.replace(/\r\n/gu, '\n');
|
|
332
|
+
const index = frontmatterHeaderIndex(normalized);
|
|
333
|
+
const lineEnd = normalized.indexOf('\n', index);
|
|
334
|
+
const headerLine = normalized.slice(index, lineEnd === -1 ? normalized.length : lineEnd);
|
|
335
|
+
const occurrences = normalized.split('\n').filter((line) => line.startsWith(OWNED_TEXT_HEADER_PREFIX));
|
|
336
|
+
if (!headerLine.startsWith(OWNED_TEXT_HEADER_PREFIX)) {
|
|
337
|
+
if (occurrences.length > 0)
|
|
338
|
+
throw new Error('Owner header 不在允许的位置。');
|
|
339
|
+
return null;
|
|
340
|
+
}
|
|
341
|
+
if (occurrences.length !== 1)
|
|
342
|
+
throw new Error('Owner header 必须且只能出现一次。');
|
|
343
|
+
let parsed;
|
|
344
|
+
try {
|
|
345
|
+
parsed = JSON.parse(headerLine.slice(OWNED_TEXT_HEADER_PREFIX.length));
|
|
346
|
+
}
|
|
347
|
+
catch {
|
|
348
|
+
throw new Error('Owner header 不是有效 JSON。');
|
|
349
|
+
}
|
|
350
|
+
const identity = parseOwnerIdentity(parsed, 'Owner header');
|
|
351
|
+
if (expectedIdentity?.sourceId !== undefined && identity.sourceId === undefined) {
|
|
352
|
+
throw new Error('legacyStateUnsupported: schema 1 owner header is not supported.');
|
|
353
|
+
}
|
|
354
|
+
if (expectedIdentity?.sourceId !== undefined
|
|
355
|
+
&& identity.sourceId === expectedIdentity.sourceId
|
|
356
|
+
&& identity.sourceIdentity !== expectedIdentity.sourceIdentity) {
|
|
357
|
+
throw new Error('sourceChanged: owner source identity does not match the configured source.');
|
|
358
|
+
}
|
|
359
|
+
if (expectedIdentity && !identitiesEqual(identity, expectedIdentity)) {
|
|
360
|
+
throw new Error('Owner header identity 与目标 identity 不匹配。');
|
|
361
|
+
}
|
|
362
|
+
const contentStart = lineEnd === -1 ? normalized.length : lineEnd + 1;
|
|
363
|
+
return {
|
|
364
|
+
identity,
|
|
365
|
+
content: normalized.slice(0, index) + normalized.slice(contentStart),
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
export async function writeOwnedTextFile(options) {
|
|
369
|
+
validateOwnerIdentity(options.identity);
|
|
370
|
+
await atomicReplaceFile({
|
|
371
|
+
path: options.path,
|
|
372
|
+
allowedRoot: options.allowedRoot,
|
|
373
|
+
content: renderOwnedTextFile(options.content, options.identity),
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
async function inspectPathAt(component, actualPath, canonicalPath) {
|
|
377
|
+
try {
|
|
378
|
+
await assertNoSymlinkInPath(component.allowedRoot, actualPath);
|
|
379
|
+
}
|
|
380
|
+
catch (error) {
|
|
381
|
+
if (error instanceof OwnershipSymlinkError)
|
|
382
|
+
return 'foreign';
|
|
383
|
+
throw error;
|
|
384
|
+
}
|
|
385
|
+
const stats = await fs.lstat(actualPath).catch((error) => {
|
|
386
|
+
if (isMissing(error))
|
|
387
|
+
return null;
|
|
388
|
+
throw error;
|
|
389
|
+
});
|
|
390
|
+
if (!stats)
|
|
391
|
+
return 'absent';
|
|
392
|
+
if (component.kind === 'skill-directory') {
|
|
393
|
+
if (!stats.isDirectory())
|
|
394
|
+
return 'foreign';
|
|
395
|
+
const markerPath = path.join(actualPath, SKILL_OWNER_MARKER);
|
|
396
|
+
try {
|
|
397
|
+
await assertNoSymlinkInPath(component.allowedRoot, markerPath);
|
|
398
|
+
}
|
|
399
|
+
catch (error) {
|
|
400
|
+
if (error instanceof OwnershipSymlinkError)
|
|
401
|
+
return 'foreign';
|
|
402
|
+
throw error;
|
|
403
|
+
}
|
|
404
|
+
let marker;
|
|
405
|
+
try {
|
|
406
|
+
marker = await readMarkerAt(markerPath);
|
|
407
|
+
}
|
|
408
|
+
catch (error) {
|
|
409
|
+
if (error.code)
|
|
410
|
+
throw error;
|
|
411
|
+
return 'foreign';
|
|
412
|
+
}
|
|
413
|
+
if (!marker) {
|
|
414
|
+
return await component.unownedIsPristine?.(actualPath) ? 'absent' : 'foreign';
|
|
415
|
+
}
|
|
416
|
+
if (!identitiesEqual(marker, component.identity))
|
|
417
|
+
return 'foreign';
|
|
418
|
+
if (canonicalPath && path.basename(actualPath) !== component.identity.artifactKey)
|
|
419
|
+
return 'foreign';
|
|
420
|
+
return 'present';
|
|
421
|
+
}
|
|
422
|
+
if (!stats.isFile())
|
|
423
|
+
return 'foreign';
|
|
424
|
+
let raw;
|
|
425
|
+
try {
|
|
426
|
+
raw = await fs.readFile(actualPath, 'utf8');
|
|
427
|
+
}
|
|
428
|
+
catch (error) {
|
|
429
|
+
if (isMissing(error))
|
|
430
|
+
return 'absent';
|
|
431
|
+
throw error;
|
|
432
|
+
}
|
|
433
|
+
try {
|
|
434
|
+
return parseOwnedTextHeader(raw, component.identity) ? 'present' : 'foreign';
|
|
435
|
+
}
|
|
436
|
+
catch {
|
|
437
|
+
return 'foreign';
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
function componentLabel(component) {
|
|
441
|
+
if ('path' in component)
|
|
442
|
+
return component.path;
|
|
443
|
+
if (component.kind === 'native-plugin')
|
|
444
|
+
return component.pluginId;
|
|
445
|
+
return component.label;
|
|
446
|
+
}
|
|
447
|
+
function validateNativePlugin(component) {
|
|
448
|
+
validateOwnerIdentity(component.identity);
|
|
449
|
+
const prefix = `${component.identity.plugin}@aw`;
|
|
450
|
+
if (component.pluginId !== prefix
|
|
451
|
+
&& (!component.pluginId.startsWith(`${prefix}-`)
|
|
452
|
+
|| !/^[a-z0-9]+(?:-[a-z0-9]+)*$/u.test(component.pluginId.slice(`${prefix}-`.length)))) {
|
|
453
|
+
throw new Error(`Native plugin identity 必须使用 ${prefix} marketplace namespace。`);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
async function inspectComponent(component, nativeProbe) {
|
|
457
|
+
validateOwnerIdentity(component.identity);
|
|
458
|
+
if ('path' in component)
|
|
459
|
+
return inspectPathAt(component, component.path, true);
|
|
460
|
+
if (component.kind === 'native-plugin') {
|
|
461
|
+
validateNativePlugin(component);
|
|
462
|
+
if (!nativeProbe)
|
|
463
|
+
throw new Error('Native ownership inspection 缺少 nativeProbe。');
|
|
464
|
+
return nativeProbe(component);
|
|
465
|
+
}
|
|
466
|
+
return component.inspect();
|
|
467
|
+
}
|
|
468
|
+
export async function inspectOwnedComponents(options) {
|
|
469
|
+
const components = [];
|
|
470
|
+
const errors = [];
|
|
471
|
+
for (const component of options.components) {
|
|
472
|
+
const label = componentLabel(component);
|
|
473
|
+
try {
|
|
474
|
+
let probe = await inspectComponent(component, options.nativeProbe);
|
|
475
|
+
let healthDiagnostic;
|
|
476
|
+
if (options.verifyHealth
|
|
477
|
+
&& probe === 'present'
|
|
478
|
+
&& component.kind === 'skill-directory'
|
|
479
|
+
&& component.validateHealth) {
|
|
480
|
+
try {
|
|
481
|
+
await component.validateHealth();
|
|
482
|
+
}
|
|
483
|
+
catch (error) {
|
|
484
|
+
probe = 'partial';
|
|
485
|
+
healthDiagnostic = errorMessage(error);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
components.push({
|
|
489
|
+
component,
|
|
490
|
+
state: probe === 'foreign' ? 'partial' : probe,
|
|
491
|
+
...(probe === 'foreign'
|
|
492
|
+
? { diagnostic: `存在 foreign collision:${label}` }
|
|
493
|
+
: healthDiagnostic
|
|
494
|
+
? { diagnostic: healthDiagnostic }
|
|
495
|
+
: probe === 'partial'
|
|
496
|
+
? { diagnostic: `组件归属有效但内容或启用状态不完整:${label}` }
|
|
497
|
+
: {}),
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
catch (error) {
|
|
501
|
+
const message = errorMessage(error);
|
|
502
|
+
components.push({ component, state: 'error', diagnostic: message });
|
|
503
|
+
errors.push({ label, message });
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
const state = errors.length > 0
|
|
507
|
+
? 'error'
|
|
508
|
+
: components.length === 0 || components.every((entry) => entry.state === 'absent')
|
|
509
|
+
? 'absent'
|
|
510
|
+
: components.every((entry) => entry.state === 'present')
|
|
511
|
+
? 'present'
|
|
512
|
+
: 'partial';
|
|
513
|
+
return { state, components, errors };
|
|
514
|
+
}
|
|
515
|
+
function pushUnique(values, value) {
|
|
516
|
+
if (!values.includes(value))
|
|
517
|
+
values.push(value);
|
|
518
|
+
}
|
|
519
|
+
async function cleanupPathComponent(options) {
|
|
520
|
+
const { component, result } = options;
|
|
521
|
+
const label = componentLabel(component);
|
|
522
|
+
const quarantinePath = path.join(path.resolve(component.allowedRoot), `.agent-workflows-quarantine-${process.pid}-${crypto.randomUUID()}`);
|
|
523
|
+
try {
|
|
524
|
+
await assertNoSymlinkInPath(component.allowedRoot, component.path);
|
|
525
|
+
assertPathBoundary(component.allowedRoot, quarantinePath);
|
|
526
|
+
await nodeFs.rename(component.path, quarantinePath);
|
|
527
|
+
}
|
|
528
|
+
catch (error) {
|
|
529
|
+
result.failures.push({ label, phase: 'mutation', message: errorMessage(error) });
|
|
530
|
+
pushUnique(result.residual, label);
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
try {
|
|
534
|
+
await options.afterQuarantine?.(component, quarantinePath);
|
|
535
|
+
}
|
|
536
|
+
catch (error) {
|
|
537
|
+
result.failures.push({
|
|
538
|
+
label,
|
|
539
|
+
phase: 'verify',
|
|
540
|
+
message: errorMessage(error),
|
|
541
|
+
quarantinePath,
|
|
542
|
+
});
|
|
543
|
+
pushUnique(result.quarantined, quarantinePath);
|
|
544
|
+
pushUnique(result.residual, label);
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
let verified;
|
|
548
|
+
try {
|
|
549
|
+
verified = await inspectPathAt(component, quarantinePath, false);
|
|
550
|
+
}
|
|
551
|
+
catch (error) {
|
|
552
|
+
result.failures.push({
|
|
553
|
+
label,
|
|
554
|
+
phase: 'verify',
|
|
555
|
+
message: errorMessage(error),
|
|
556
|
+
quarantinePath,
|
|
557
|
+
});
|
|
558
|
+
// Never restore automatically after verification starts. The canonical path can now belong to
|
|
559
|
+
// a concurrent foreign writer; the exact quarantine path is returned for manual recovery.
|
|
560
|
+
pushUnique(result.quarantined, quarantinePath);
|
|
561
|
+
pushUnique(result.residual, label);
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
if (verified !== 'present') {
|
|
565
|
+
result.failures.push({
|
|
566
|
+
label,
|
|
567
|
+
phase: 'verify',
|
|
568
|
+
message: 'Quarantine 对象的 type/owner 与目标 identity 不匹配。',
|
|
569
|
+
quarantinePath,
|
|
570
|
+
});
|
|
571
|
+
pushUnique(result.quarantined, quarantinePath);
|
|
572
|
+
pushUnique(result.residual, label);
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
// A matching marker/header is deletion authorization. Content drift is intentionally out of scope.
|
|
576
|
+
try {
|
|
577
|
+
await fs.remove(quarantinePath);
|
|
578
|
+
}
|
|
579
|
+
catch (error) {
|
|
580
|
+
result.failures.push({
|
|
581
|
+
label,
|
|
582
|
+
phase: 'remove',
|
|
583
|
+
message: errorMessage(error),
|
|
584
|
+
quarantinePath,
|
|
585
|
+
});
|
|
586
|
+
if (await fs.pathExists(quarantinePath))
|
|
587
|
+
pushUnique(result.quarantined, quarantinePath);
|
|
588
|
+
pushUnique(result.residual, label);
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
try {
|
|
592
|
+
const after = await inspectComponent(component);
|
|
593
|
+
if (after === 'absent')
|
|
594
|
+
pushUnique(result.removed, label);
|
|
595
|
+
else
|
|
596
|
+
pushUnique(result.residual, label);
|
|
597
|
+
}
|
|
598
|
+
catch (error) {
|
|
599
|
+
result.failures.push({ label, phase: 'post-probe', message: errorMessage(error) });
|
|
600
|
+
pushUnique(result.residual, label);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
export async function cleanupOwnedComponents(options) {
|
|
604
|
+
const result = {
|
|
605
|
+
removed: [],
|
|
606
|
+
absent: [],
|
|
607
|
+
residual: [],
|
|
608
|
+
quarantined: [],
|
|
609
|
+
failures: [],
|
|
610
|
+
};
|
|
611
|
+
const probes = new Map();
|
|
612
|
+
for (const component of options.components) {
|
|
613
|
+
const label = componentLabel(component);
|
|
614
|
+
try {
|
|
615
|
+
const probe = await inspectComponent(component, options.nativeProbe);
|
|
616
|
+
probes.set(component, probe);
|
|
617
|
+
if (probe === 'absent')
|
|
618
|
+
pushUnique(result.absent, label);
|
|
619
|
+
if (probe === 'foreign' || probe === 'partial')
|
|
620
|
+
pushUnique(result.residual, label);
|
|
621
|
+
}
|
|
622
|
+
catch (error) {
|
|
623
|
+
result.failures.push({ label, phase: 'probe', message: errorMessage(error) });
|
|
624
|
+
pushUnique(result.residual, label);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
for (const component of options.components) {
|
|
628
|
+
if (probes.get(component) !== 'present')
|
|
629
|
+
continue;
|
|
630
|
+
const label = componentLabel(component);
|
|
631
|
+
try {
|
|
632
|
+
await options.beforeMutation?.(component);
|
|
633
|
+
}
|
|
634
|
+
catch (error) {
|
|
635
|
+
result.failures.push({ label, phase: 'mutation', message: errorMessage(error) });
|
|
636
|
+
pushUnique(result.residual, label);
|
|
637
|
+
continue;
|
|
638
|
+
}
|
|
639
|
+
if ('path' in component) {
|
|
640
|
+
await cleanupPathComponent({
|
|
641
|
+
component,
|
|
642
|
+
result,
|
|
643
|
+
afterQuarantine: options.afterQuarantine,
|
|
644
|
+
});
|
|
645
|
+
continue;
|
|
646
|
+
}
|
|
647
|
+
try {
|
|
648
|
+
if (component.kind === 'native-plugin') {
|
|
649
|
+
validateNativePlugin(component);
|
|
650
|
+
if (!options.nativeRemove || !options.nativeProbe) {
|
|
651
|
+
throw new Error('Native ownership cleanup 缺少 nativeProbe/nativeRemove。');
|
|
652
|
+
}
|
|
653
|
+
await options.nativeRemove(component);
|
|
654
|
+
}
|
|
655
|
+
else {
|
|
656
|
+
await component.remove();
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
catch (error) {
|
|
660
|
+
result.failures.push({ label, phase: 'remove', message: errorMessage(error) });
|
|
661
|
+
pushUnique(result.residual, label);
|
|
662
|
+
continue;
|
|
663
|
+
}
|
|
664
|
+
try {
|
|
665
|
+
const after = await inspectComponent(component, options.nativeProbe);
|
|
666
|
+
if (after === 'absent')
|
|
667
|
+
pushUnique(result.removed, label);
|
|
668
|
+
else
|
|
669
|
+
pushUnique(result.residual, label);
|
|
670
|
+
}
|
|
671
|
+
catch (error) {
|
|
672
|
+
result.failures.push({ label, phase: 'post-probe', message: errorMessage(error) });
|
|
673
|
+
pushUnique(result.residual, label);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
return result;
|
|
677
|
+
}
|
|
678
|
+
export async function cleanupCorruptExclusivePluginDirectory(options) {
|
|
679
|
+
const markerPath = path.join(options.directory, SKILL_OWNER_MARKER);
|
|
680
|
+
let raw = null;
|
|
681
|
+
try {
|
|
682
|
+
const [directoryStats, markerStats] = await Promise.all([
|
|
683
|
+
nodeFs.lstat(options.directory),
|
|
684
|
+
nodeFs.lstat(markerPath),
|
|
685
|
+
]);
|
|
686
|
+
if (!directoryStats.isDirectory() || directoryStats.isSymbolicLink()
|
|
687
|
+
|| !markerStats.isFile() || markerStats.isSymbolicLink())
|
|
688
|
+
return null;
|
|
689
|
+
await assertNoSymlinkInPath(options.allowedRoot, markerPath);
|
|
690
|
+
raw = await fs.readJson(markerPath);
|
|
691
|
+
}
|
|
692
|
+
catch {
|
|
693
|
+
return null;
|
|
694
|
+
}
|
|
695
|
+
if (!raw
|
|
696
|
+
|| raw.schemaVersion !== 2
|
|
697
|
+
|| raw.owner !== 'agent-workflows'
|
|
698
|
+
|| raw.sourceId !== options.sourceId
|
|
699
|
+
|| raw.plugin !== options.pluginName
|
|
700
|
+
|| raw.pluginId !== `${options.sourceId}/${options.pluginName}`
|
|
701
|
+
|| raw.platform !== options.platform
|
|
702
|
+
|| raw.scope !== options.scope)
|
|
703
|
+
return null;
|
|
704
|
+
assertSafeOwnershipSegment(path.basename(options.directory), 'Exclusive plugin directory');
|
|
705
|
+
const quarantinePath = path.join(path.resolve(options.allowedRoot), `.agent-workflows-quarantine-${process.pid}-${crypto.randomUUID()}`);
|
|
706
|
+
assertPathBoundary(options.allowedRoot, quarantinePath);
|
|
707
|
+
try {
|
|
708
|
+
await (options.rename ?? nodeFs.rename)(options.directory, quarantinePath);
|
|
709
|
+
}
|
|
710
|
+
catch (error) {
|
|
711
|
+
const [canonicalExists, quarantineExists] = await Promise.all([
|
|
712
|
+
fs.pathExists(options.directory),
|
|
713
|
+
fs.pathExists(quarantinePath),
|
|
714
|
+
]);
|
|
715
|
+
if (!canonicalExists && !quarantineExists) {
|
|
716
|
+
return {
|
|
717
|
+
removed: [options.directory], absent: [], residual: [], quarantined: [], failures: [],
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
return {
|
|
721
|
+
removed: [], absent: [],
|
|
722
|
+
residual: [quarantineExists ? quarantinePath : options.directory],
|
|
723
|
+
quarantined: quarantineExists ? [quarantinePath] : [],
|
|
724
|
+
failures: [{
|
|
725
|
+
label: options.directory,
|
|
726
|
+
phase: 'mutation',
|
|
727
|
+
message: errorMessage(error),
|
|
728
|
+
...(quarantineExists ? { quarantinePath } : {}),
|
|
729
|
+
}],
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
try {
|
|
733
|
+
await (options.remove ?? fs.remove)(quarantinePath);
|
|
734
|
+
}
|
|
735
|
+
catch (error) {
|
|
736
|
+
if (!await fs.pathExists(quarantinePath)) {
|
|
737
|
+
return {
|
|
738
|
+
removed: [options.directory], absent: [], residual: [], quarantined: [], failures: [],
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
return {
|
|
742
|
+
removed: [], absent: [], residual: [quarantinePath], quarantined: [quarantinePath],
|
|
743
|
+
failures: [{
|
|
744
|
+
label: options.directory,
|
|
745
|
+
phase: 'remove',
|
|
746
|
+
message: errorMessage(error),
|
|
747
|
+
quarantinePath,
|
|
748
|
+
}],
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
if (await fs.pathExists(quarantinePath)) {
|
|
752
|
+
return {
|
|
753
|
+
removed: [], absent: [], residual: [quarantinePath], quarantined: [quarantinePath],
|
|
754
|
+
failures: [{
|
|
755
|
+
label: options.directory,
|
|
756
|
+
phase: 'verify',
|
|
757
|
+
message: 'Exclusive plugin quarantine remained after removal.',
|
|
758
|
+
quarantinePath,
|
|
759
|
+
}],
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
return {
|
|
763
|
+
removed: [options.directory], absent: [], residual: [], quarantined: [], failures: [],
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
//# sourceMappingURL=ownership.js.map
|