@aiwg/cli 0.0.0-bootstrap.0 → 2026.7.17
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 +21 -1
- package/bin/aiwg.mjs +349 -0
- package/dist/src/a2a/agent-card.js +145 -0
- package/dist/src/a2a/client.js +411 -0
- package/dist/src/a2a/hitl-cli.js +171 -0
- package/dist/src/a2a/hitl-driver.js +370 -0
- package/dist/src/a2a/hitl.js +181 -0
- package/dist/src/a2a/http.js +193 -0
- package/dist/src/a2a/jcs.js +128 -0
- package/dist/src/a2a/jws.js +187 -0
- package/dist/src/a2a/types.js +24 -0
- package/dist/src/a2a/webhook.js +240 -0
- package/dist/src/activity-log/cli.js +348 -0
- package/dist/src/activity-log/parser.js +81 -0
- package/dist/src/activity-log/types.js +50 -0
- package/dist/src/agents/agent-deployer.js +367 -0
- package/dist/src/agents/agent-packager.js +271 -0
- package/dist/src/agents/agent-validator.js +271 -0
- package/dist/src/agents/grounding/knowledge-base.js +161 -0
- package/dist/src/agents/grounding/types.js +12 -0
- package/dist/src/agents/index.js +10 -0
- package/dist/src/agents/packaged-agent-inventory.js +75 -0
- package/dist/src/agents/types.js +7 -0
- package/dist/src/api/index.d.ts +10 -0
- package/dist/src/api/index.js +10 -0
- package/dist/src/artifacts/address-parser.js +73 -0
- package/dist/src/artifacts/audit/cli.js +183 -0
- package/dist/src/artifacts/audit/drift.js +122 -0
- package/dist/src/artifacts/audit/types.js +12 -0
- package/dist/src/artifacts/backends/graphology-backend.js +160 -0
- package/dist/src/artifacts/backends/json-backend.js +129 -0
- package/dist/src/artifacts/backends/sqlite-backend.js +199 -0
- package/dist/src/artifacts/browser-export.js +622 -0
- package/dist/src/artifacts/capability-resolver.js +94 -0
- package/dist/src/artifacts/checksum-manifest.js +91 -0
- package/dist/src/artifacts/citation-parser.js +162 -0
- package/dist/src/artifacts/cli.js +1462 -0
- package/dist/src/artifacts/corpus-tools/citation-densify.js +311 -0
- package/dist/src/artifacts/corpus-tools/cli.js +393 -0
- package/dist/src/artifacts/corpus-tools/corpus-graph.js +225 -0
- package/dist/src/artifacts/corpus-tools/curator.js +186 -0
- package/dist/src/artifacts/corpus-tools/discovery-log.js +70 -0
- package/dist/src/artifacts/corpus-tools/funder-network.js +141 -0
- package/dist/src/artifacts/corpus-tools/induction-audit.js +233 -0
- package/dist/src/artifacts/corpus-tools/integrity-scan.js +202 -0
- package/dist/src/artifacts/corpus-tools/profile-communities.js +166 -0
- package/dist/src/artifacts/corpus-tools/profile-edges.js +72 -0
- package/dist/src/artifacts/corpus-tools/profile-embed.js +113 -0
- package/dist/src/artifacts/corpus-tools/profile-generate-fm.js +167 -0
- package/dist/src/artifacts/corpus-tools/profile-generate.js +181 -0
- package/dist/src/artifacts/corpus-tools/profile-metrics.js +98 -0
- package/dist/src/artifacts/corpus-tools/profile-status.js +86 -0
- package/dist/src/artifacts/corpus-tools/profile-temporal.js +139 -0
- package/dist/src/artifacts/corpus-tools/radar-init.js +93 -0
- package/dist/src/artifacts/corpus-tools/radar-report.js +118 -0
- package/dist/src/artifacts/corpus-tools/radar-shared.js +189 -0
- package/dist/src/artifacts/corpus-tools/radar-status.js +68 -0
- package/dist/src/artifacts/corpus-tools/sidecar-lint.js +233 -0
- package/dist/src/artifacts/corpus-tools/sidecar-repair.js +277 -0
- package/dist/src/artifacts/corpus-tools/snapshot.js +591 -0
- package/dist/src/artifacts/corpus-tools/source-types.js +164 -0
- package/dist/src/artifacts/corpus-tools/vision-extract.js +243 -0
- package/dist/src/artifacts/corpus-views/build.js +126 -0
- package/dist/src/artifacts/corpus-views/corpus-config.js +124 -0
- package/dist/src/artifacts/corpus-views/ref-parser.js +437 -0
- package/dist/src/artifacts/corpus-views/renderers.js +353 -0
- package/dist/src/artifacts/corpus-views/taxonomies.js +131 -0
- package/dist/src/artifacts/dep-graph.js +173 -0
- package/dist/src/artifacts/discover-facets.js +375 -0
- package/dist/src/artifacts/embedding-index.js +354 -0
- package/dist/src/artifacts/enrichment/cli.js +240 -0
- package/dist/src/artifacts/enrichment/prompt.js +47 -0
- package/dist/src/artifacts/enrichment/store.js +90 -0
- package/dist/src/artifacts/enrichment/types.js +12 -0
- package/dist/src/artifacts/fortemi-core-query-adapter.js +475 -0
- package/dist/src/artifacts/fortemi-core-sync.js +251 -0
- package/dist/src/artifacts/fortemi-shard-export.js +44 -0
- package/dist/src/artifacts/fulltext.js +108 -0
- package/dist/src/artifacts/graph-backend.js +51 -0
- package/dist/src/artifacts/graph-query.js +247 -0
- package/dist/src/artifacts/hybrid-query.js +225 -0
- package/dist/src/artifacts/index-builder.js +1089 -0
- package/dist/src/artifacts/index-reader.js +112 -0
- package/dist/src/artifacts/index-status.js +193 -0
- package/dist/src/artifacts/legacy-index-migration.js +169 -0
- package/dist/src/artifacts/move.js +154 -0
- package/dist/src/artifacts/operational-state.js +239 -0
- package/dist/src/artifacts/prebuilt-build-lock.js +49 -0
- package/dist/src/artifacts/query-engine.js +1955 -0
- package/dist/src/artifacts/source-graph.js +529 -0
- package/dist/src/artifacts/stats.js +169 -0
- package/dist/src/artifacts/types.js +606 -0
- package/dist/src/artifacts/views/cli.js +293 -0
- package/dist/src/artifacts/views/definition.js +170 -0
- package/dist/src/artifacts/views/store.js +149 -0
- package/dist/src/artifacts/views/types.js +8 -0
- package/dist/src/artifacts/watcher.js +255 -0
- package/dist/src/catalog/builtin-models.json +636 -0
- package/dist/src/catalog/cli.js +228 -0
- package/dist/src/catalog/cli.mjs +289 -0
- package/dist/src/catalog/index.js +15 -0
- package/dist/src/catalog/loader.js +217 -0
- package/dist/src/catalog/loader.mjs +251 -0
- package/dist/src/catalog/sources.json +41 -0
- package/dist/src/catalog/types.js +8 -0
- package/dist/src/channel/manager.mjs +504 -0
- package/dist/src/cli/agent-spawn.js +178 -0
- package/dist/src/cli/cli-extension-loader.js +245 -0
- package/dist/src/cli/command-log.js +275 -0
- package/dist/src/cli/config-loader.js +232 -0
- package/dist/src/cli/env.js +82 -0
- package/dist/src/cli/errors.js +150 -0
- package/dist/src/cli/find-package-root.js +40 -0
- package/dist/src/cli/git-hooks.js +250 -0
- package/dist/src/cli/handlers/agentcard.js +206 -0
- package/dist/src/cli/handlers/artifacts.js +76 -0
- package/dist/src/cli/handlers/best-practices-audit.js +280 -0
- package/dist/src/cli/handlers/cockpit.js +137 -0
- package/dist/src/cli/handlers/command-log.js +37 -0
- package/dist/src/cli/handlers/daemon.js +59 -0
- package/dist/src/cli/handlers/diagnose.js +300 -0
- package/dist/src/cli/handlers/execution-mode.js +105 -0
- package/dist/src/cli/handlers/feedback.js +341 -0
- package/dist/src/cli/handlers/help.js +147 -0
- package/dist/src/cli/handlers/index.js +302 -0
- package/dist/src/cli/handlers/init.js +179 -0
- package/dist/src/cli/handlers/install.js +129 -0
- package/dist/src/cli/handlers/issues.js +46 -0
- package/dist/src/cli/handlers/lint.js +42 -0
- package/dist/src/cli/handlers/local-executor.js +315 -0
- package/dist/src/cli/handlers/marketplace.js +168 -0
- package/dist/src/cli/handlers/mc.js +1010 -0
- package/dist/src/cli/handlers/models.js +352 -0
- package/dist/src/cli/handlers/packages.js +155 -0
- package/dist/src/cli/handlers/ralph-launcher.js +717 -0
- package/dist/src/cli/handlers/ralph.js +575 -0
- package/dist/src/cli/handlers/refresh.js +432 -0
- package/dist/src/cli/handlers/regenerate.js +336 -0
- package/dist/src/cli/handlers/repo-access.js +109 -0
- package/dist/src/cli/handlers/run.js +165 -0
- package/dist/src/cli/handlers/runtime-info.js +301 -0
- package/dist/src/cli/handlers/sandbox.js +197 -0
- package/dist/src/cli/handlers/scaffolding.js +149 -0
- package/dist/src/cli/handlers/script-runner.js +121 -0
- package/dist/src/cli/handlers/sdlc-accelerate.js +148 -0
- package/dist/src/cli/handlers/serve.js +1835 -0
- package/dist/src/cli/handlers/session.js +348 -0
- package/dist/src/cli/handlers/setup.js +440 -0
- package/dist/src/cli/handlers/skill-lint.js +367 -0
- package/dist/src/cli/handlers/skill-usage.js +74 -0
- package/dist/src/cli/handlers/steward.js +567 -0
- package/dist/src/cli/handlers/subcommands.js +1702 -0
- package/dist/src/cli/handlers/team.js +337 -0
- package/dist/src/cli/handlers/types.js +11 -0
- package/dist/src/cli/handlers/use.js +2772 -0
- package/dist/src/cli/handlers/utilities.js +703 -0
- package/dist/src/cli/handlers/version.js +134 -0
- package/dist/src/cli/handlers/workspace-context.js +93 -0
- package/dist/src/cli/handlers/workspace.js +126 -0
- package/dist/src/cli/help-generator.js +178 -0
- package/dist/src/cli/hooks/builtin/activity-log-hook.js +126 -0
- package/dist/src/cli/hooks/executor.js +96 -0
- package/dist/src/cli/hooks/index.js +15 -0
- package/dist/src/cli/hooks/registry.js +143 -0
- package/dist/src/cli/hooks/types.js +13 -0
- package/dist/src/cli/log.js +492 -0
- package/dist/src/cli/project-isolation/detect.js +70 -0
- package/dist/src/cli/project-isolation/index.js +7 -0
- package/dist/src/cli/project-isolation/signals.js +17 -0
- package/dist/src/cli/project-isolation/warning.js +102 -0
- package/dist/src/cli/prompt-utils.js +155 -0
- package/dist/src/cli/provider-deployment-plan.js +126 -0
- package/dist/src/cli/provider-resolution.js +119 -0
- package/dist/src/cli/router.js +305 -0
- package/dist/src/cli/scope-resolver.js +392 -0
- package/dist/src/cli/skill-usage.js +616 -0
- package/dist/src/cli/ui.js +224 -0
- package/dist/src/cli/watch-service.js +203 -0
- package/dist/src/cli/workflow-orchestrator.js +478 -0
- package/dist/src/cli/workspace-signals.js +321 -0
- package/dist/src/community/footer.js +14 -0
- package/dist/src/community/links.js +123 -0
- package/dist/src/community/milestones.js +46 -0
- package/dist/src/community/nudge-policy.js +93 -0
- package/dist/src/config/aiwg-config.js +883 -0
- package/dist/src/config/cli.js +703 -0
- package/dist/src/config/gitignore.js +156 -0
- package/dist/src/config/project-artifacts.js +76 -0
- package/dist/src/config/user-config.js +428 -0
- package/dist/src/config/user-registry.js +127 -0
- package/dist/src/config/workspace.js +276 -0
- package/dist/src/contributors/detect.js +39 -0
- package/dist/src/contributors/discover.js +172 -0
- package/dist/src/contributors/heuristic.js +186 -0
- package/dist/src/contributors/index.js +11 -0
- package/dist/src/contributors/types.js +13 -0
- package/dist/src/contributors/validation.js +116 -0
- package/dist/src/data/community.schema.json +43 -0
- package/dist/src/data/community.yaml +16 -0
- package/dist/src/extensions/capability-index.js +270 -0
- package/dist/src/extensions/claude-hooks-installer.js +268 -0
- package/dist/src/extensions/commands/definitions.js +3485 -0
- package/dist/src/extensions/deployment-registration.js +463 -0
- package/dist/src/extensions/index.js +22 -0
- package/dist/src/extensions/loader.js +132 -0
- package/dist/src/extensions/managed-marker.js +100 -0
- package/dist/src/extensions/manifest.js +196 -0
- package/dist/src/extensions/project-local-activity.js +114 -0
- package/dist/src/extensions/project-local-discovery.js +261 -0
- package/dist/src/extensions/project-local-doctor.js +281 -0
- package/dist/src/extensions/project-local-gitignore.js +176 -0
- package/dist/src/extensions/project-local-paths.js +121 -0
- package/dist/src/extensions/project-local-promote.js +218 -0
- package/dist/src/extensions/project-local-remove.js +373 -0
- package/dist/src/extensions/project-local-scaffold.js +252 -0
- package/dist/src/extensions/project-quickref.js +291 -0
- package/dist/src/extensions/registry.js +368 -0
- package/dist/src/extensions/shadow-resolver.js +271 -0
- package/dist/src/extensions/types.js +86 -0
- package/dist/src/extensions/upstream-registry.js +195 -0
- package/dist/src/extensions/validation.js +631 -0
- package/dist/src/features/catalog.js +88 -0
- package/dist/src/features/cli.js +197 -0
- package/dist/src/features/installer.js +57 -0
- package/dist/src/features/paths.js +14 -0
- package/dist/src/features/runtime.js +21 -0
- package/dist/src/features/status.js +134 -0
- package/dist/src/hooks/laziness-detection.js +532 -0
- package/dist/src/intake/git-history-analyzer.js +486 -0
- package/dist/src/intake/index.js +9 -0
- package/dist/src/issues/cli.js +327 -0
- package/dist/src/issues/index.js +5 -0
- package/dist/src/issues/live.js +154 -0
- package/dist/src/issues/local.js +666 -0
- package/dist/src/issues/sync.js +143 -0
- package/dist/src/issues/types.js +2 -0
- package/dist/src/issues/workflows.js +164 -0
- package/dist/src/kb/cli.js +173 -0
- package/dist/src/lint/cli.js +171 -0
- package/dist/src/lint/loader.js +225 -0
- package/dist/src/lint/reporters.js +141 -0
- package/dist/src/lint/runner.js +364 -0
- package/dist/src/lint/types.js +10 -0
- package/dist/src/marketplace/cache.js +110 -0
- package/dist/src/marketplace/identifier.js +63 -0
- package/dist/src/marketplace/registry.js +36 -0
- package/dist/src/marketplace/sources/clawhub.js +53 -0
- package/dist/src/marketplace/sources/git.js +45 -0
- package/dist/src/marketplace/types.js +9 -0
- package/dist/src/mcp/adapters/codex-runtime.js +224 -0
- package/dist/src/mcp/cli.mjs +1197 -0
- package/dist/src/mcp/elicitation.mjs +149 -0
- package/dist/src/mcp/helpers.mjs +287 -0
- package/dist/src/mcp/index.mjs +11 -0
- package/dist/src/mcp/profiles.js +263 -0
- package/dist/src/mcp/profiles.mjs +360 -0
- package/dist/src/mcp/registry.js +376 -0
- package/dist/src/mcp/registry.mjs +387 -0
- package/dist/src/mcp/server.mjs +633 -0
- package/dist/src/mcp/test-simple.mjs +271 -0
- package/dist/src/mcp/tools/command-run.mjs +101 -0
- package/dist/src/mcp/tools/discovery.mjs +291 -0
- package/dist/src/mcp/tools/interaction.mjs +87 -0
- package/dist/src/mcp/tools/orchestration.mjs +320 -0
- package/dist/src/mcp/tools/subsystems.mjs +640 -0
- package/dist/src/memory/cli.js +166 -0
- package/dist/src/memory/project-registry.js +282 -0
- package/dist/src/metrics/artifact-metrics.js +184 -0
- package/dist/src/metrics/context-budget.js +174 -0
- package/dist/src/metrics/token-counter.js +133 -0
- package/dist/src/models/config-loader.js +228 -0
- package/dist/src/models/index.js +22 -0
- package/dist/src/models/model-capabilities.v1.json +120 -0
- package/dist/src/models/model-catalog.v1.json +96 -0
- package/dist/src/models/model-discovery.js +521 -0
- package/dist/src/models/provider-models.js +73 -0
- package/dist/src/models/provider-policy.js +273 -0
- package/dist/src/models/resolver.js +245 -0
- package/dist/src/models/router.js +70 -0
- package/dist/src/models/types.js +8 -0
- package/dist/src/models/wrapper-deployment.js +178 -0
- package/dist/src/models/wrapper-route.js +54 -0
- package/dist/src/ops/cli.js +268 -0
- package/dist/src/ops/registry.js +623 -0
- package/dist/src/packages/adapters/clawhub.js +113 -0
- package/dist/src/packages/adapters/git.js +153 -0
- package/dist/src/packages/adapters/gitea.js +93 -0
- package/dist/src/packages/adapters/github.js +69 -0
- package/dist/src/packages/adapters/local-cache.js +89 -0
- package/dist/src/packages/package-registry.js +143 -0
- package/dist/src/packages/registry.js +238 -0
- package/dist/src/packages/types.js +11 -0
- package/dist/src/plugin/cross-framework-ops.js +475 -0
- package/dist/src/plugin/framework-config-loader.js +235 -0
- package/dist/src/plugin/framework-detector.js +186 -0
- package/dist/src/plugin/framework-isolator.js +341 -0
- package/dist/src/plugin/framework-migration.js +371 -0
- package/dist/src/plugin/metadata-validator.js +906 -0
- package/dist/src/plugin/plugin-installer.js +436 -0
- package/dist/src/plugin/plugin-status.js +369 -0
- package/dist/src/plugin/plugin-uninstaller.js +473 -0
- package/dist/src/plugin/registry-validator.js +344 -0
- package/dist/src/plugin/skill-command-translator.js +415 -0
- package/dist/src/plugin/workspace-creator.js +189 -0
- package/dist/src/plugin/workspace-migrator.js +821 -0
- package/dist/src/policy/authorization.js +390 -0
- package/dist/src/policy/repo-access.js +215 -0
- package/dist/src/provenance/cli.js +16 -0
- package/dist/src/providers/capability-matrix.js +300 -0
- package/dist/src/providers/capability-matrix.yaml +514 -0
- package/dist/src/providers/provider-definitions.js +977 -0
- package/dist/src/providers/provider-definitions.mjs +159 -0
- package/dist/src/providers/provider-inventory.js +169 -0
- package/dist/src/quality/feedback-ab.js +174 -0
- package/dist/src/quality/feedback-collector.js +176 -0
- package/dist/src/quality/feedback-tracker.js +123 -0
- package/dist/src/quality/patterns/adr.json +24 -0
- package/dist/src/quality/patterns/sad.json +24 -0
- package/dist/src/quality/patterns/test-plan.json +24 -0
- package/dist/src/quality/patterns/use-case.json +24 -0
- package/dist/src/quality/scoring.js +157 -0
- package/dist/src/reflections/cli.js +15 -0
- package/dist/src/release/plan.js +139 -0
- package/dist/src/research/cache/manager.js +227 -0
- package/dist/src/research/clients/arxiv.js +156 -0
- package/dist/src/research/clients/base.js +197 -0
- package/dist/src/research/clients/crossref.js +112 -0
- package/dist/src/research/clients/semantic-scholar.js +126 -0
- package/dist/src/research/clients/unpaywall.js +87 -0
- package/dist/src/research/index.js +14 -0
- package/dist/src/research/query-cli.js +336 -0
- package/dist/src/research/services/acquisition.js +313 -0
- package/dist/src/research/services/archival.js +225 -0
- package/dist/src/research/services/citation.js +279 -0
- package/dist/src/research/services/discovery.js +243 -0
- package/dist/src/research/services/documentation.js +269 -0
- package/dist/src/research/services/index.js +14 -0
- package/dist/src/research/services/provenance.js +279 -0
- package/dist/src/research/services/quality.js +370 -0
- package/dist/src/research/services/types.js +7 -0
- package/dist/src/research/storage-cli.js +20 -0
- package/dist/src/research/types.js +47 -0
- package/dist/src/resources/index.d.ts +2 -0
- package/dist/src/resources/index.js +2 -0
- package/dist/src/resources/web-release.d.ts +89 -0
- package/dist/src/resources/web-release.js +882 -0
- package/dist/src/rlm/cache/cli.js +162 -0
- package/dist/src/rlm/cache/hash.js +35 -0
- package/dist/src/rlm/cache/store.js +170 -0
- package/dist/src/rlm/cache/types.js +8 -0
- package/dist/src/rlm/cli.js +650 -0
- package/dist/src/serve/a2a-terminal-observer.js +120 -0
- package/dist/src/serve/agent-router.js +205 -0
- package/dist/src/serve/dispatch-router.js +171 -0
- package/dist/src/serve/executor-registry.js +715 -0
- package/dist/src/serve/mission-conductor.js +177 -0
- package/dist/src/serve/orchestrator-adapter.js +113 -0
- package/dist/src/serve/orchestrator-override.js +94 -0
- package/dist/src/serve/orchestrator-pty.js +133 -0
- package/dist/src/serve/pty-bridge.js +799 -0
- package/dist/src/serve/sandbox-registry.js +832 -0
- package/dist/src/serve/screen-reader.js +228 -0
- package/dist/src/serve/stack-adapters.js +68 -0
- package/dist/src/serve/telemetry.js +143 -0
- package/dist/src/skills/adapters/clawhub.js +250 -0
- package/dist/src/skills/adapters/local.js +335 -0
- package/dist/src/skills/adapters/openclaw.js +316 -0
- package/dist/src/skills/cli.js +334 -0
- package/dist/src/skills/registry.js +117 -0
- package/dist/src/skills/run.js +259 -0
- package/dist/src/skills/runtime.js +94 -0
- package/dist/src/skills/types.js +10 -0
- package/dist/src/smiths/agentsmith/demo.js +116 -0
- package/dist/src/smiths/agentsmith/examples.js +300 -0
- package/dist/src/smiths/agentsmith/generator.js +503 -0
- package/dist/src/smiths/agentsmith/index.js +11 -0
- package/dist/src/smiths/agentsmith/types.js +8 -0
- package/dist/src/smiths/commandsmith/example.js +220 -0
- package/dist/src/smiths/commandsmith/generator.js +288 -0
- package/dist/src/smiths/commandsmith/index.js +41 -0
- package/dist/src/smiths/commandsmith/templates.js +296 -0
- package/dist/src/smiths/commandsmith/types.js +7 -0
- package/dist/src/smiths/context-pipeline/aiwg-md.js +104 -0
- package/dist/src/smiths/context-pipeline/allowlist.js +195 -0
- package/dist/src/smiths/context-pipeline/claude-hook.js +127 -0
- package/dist/src/smiths/context-pipeline/discovery.js +187 -0
- package/dist/src/smiths/context-pipeline/external-links-section.js +49 -0
- package/dist/src/smiths/context-pipeline/finalization.js +147 -0
- package/dist/src/smiths/context-pipeline/generator.js +477 -0
- package/dist/src/smiths/context-pipeline/index.js +30 -0
- package/dist/src/smiths/context-pipeline/legacy-inject.js +103 -0
- package/dist/src/smiths/context-pipeline/managed-hook.js +95 -0
- package/dist/src/smiths/context-pipeline/overflow.js +212 -0
- package/dist/src/smiths/context-pipeline/parallelism-section.js +94 -0
- package/dist/src/smiths/context-pipeline/provider-policy.js +64 -0
- package/dist/src/smiths/context-pipeline/sanitizer.js +93 -0
- package/dist/src/smiths/context-pipeline/types.js +23 -0
- package/dist/src/smiths/context-pipeline/workspace-context.js +988 -0
- package/dist/src/smiths/hook-bridge/codex-translator.js +129 -0
- package/dist/src/smiths/hook-bridge/copilot-translator.js +64 -0
- package/dist/src/smiths/hook-bridge/factory-translator.js +43 -0
- package/dist/src/smiths/hook-bridge/hermes-translator.js +88 -0
- package/dist/src/smiths/hook-bridge/index.js +79 -0
- package/dist/src/smiths/hook-bridge/loader.js +116 -0
- package/dist/src/smiths/hook-bridge/shim.js +89 -0
- package/dist/src/smiths/hook-bridge/types.js +31 -0
- package/dist/src/smiths/index.js +39 -0
- package/dist/src/smiths/mcpsmith/analyzers/cli-analyzer.js +390 -0
- package/dist/src/smiths/mcpsmith/example.js +119 -0
- package/dist/src/smiths/mcpsmith/generator.js +236 -0
- package/dist/src/smiths/mcpsmith/index.js +17 -0
- package/dist/src/smiths/mcpsmith/types.js +10 -0
- package/dist/src/smiths/platform-paths.js +101 -0
- package/dist/src/smiths/skillsmith/codex-sidecar.js +85 -0
- package/dist/src/smiths/skillsmith/collision-detector.js +249 -0
- package/dist/src/smiths/skillsmith/demo.js +83 -0
- package/dist/src/smiths/skillsmith/examples.js +161 -0
- package/dist/src/smiths/skillsmith/generator.js +316 -0
- package/dist/src/smiths/skillsmith/index.js +12 -0
- package/dist/src/smiths/skillsmith/namespace-adapter.js +180 -0
- package/dist/src/smiths/skillsmith/platform-resolver.js +157 -0
- package/dist/src/smiths/skillsmith/types.js +9 -0
- package/dist/src/smiths/toolsmith/index.js +10 -0
- package/dist/src/smiths/toolsmith/runtime-discovery.mjs +710 -0
- package/dist/src/smiths/toolsmith/types.js +8 -0
- package/dist/src/storage/backends/fortemi.js +227 -0
- package/dist/src/storage/backends/fs.js +134 -0
- package/dist/src/storage/backends/logseq.js +309 -0
- package/dist/src/storage/backends/obsidian.js +233 -0
- package/dist/src/storage/cli.js +468 -0
- package/dist/src/storage/config.js +272 -0
- package/dist/src/storage/index.js +108 -0
- package/dist/src/storage/subsystem-cli.js +201 -0
- package/dist/src/storage/types.js +33 -0
- package/dist/src/testing/corpus/corpus-builder.js +383 -0
- package/dist/src/testing/corpus/ground-truth-manager.js +460 -0
- package/dist/src/testing/corpus/index.js +10 -0
- package/dist/src/testing/fixtures/index.js +9 -0
- package/dist/src/testing/fixtures/test-data-factory.js +472 -0
- package/dist/src/testing/generators/index.js +11 -0
- package/dist/src/testing/generators/test-case-generator.js +393 -0
- package/dist/src/testing/generators/test-code-generator.js +384 -0
- package/dist/src/testing/generators/use-case-parser.js +325 -0
- package/dist/src/testing/index.js +11 -0
- package/dist/src/tracker/capability-protocol.js +118 -0
- package/dist/src/update/checker.mjs +396 -0
- package/dist/src/update/notifier.mjs +235 -0
- package/dist/src/writing/content-diversifier.js +804 -0
- package/dist/src/writing/example-generator.js +959 -0
- package/dist/src/writing/example-templates.js +99 -0
- package/dist/src/writing/pattern-library.js +486 -0
- package/dist/src/writing/patterns/banned-phrases.json +4413 -0
- package/dist/src/writing/patterns/formulaic-structures.json +1300 -0
- package/dist/src/writing/patterns/generic-adjectives.json +1510 -0
- package/dist/src/writing/patterns/hedging-language.json +2096 -0
- package/dist/src/writing/patterns/transition-words.json +1285 -0
- package/dist/src/writing/patterns/weak-verbs.json +1112 -0
- package/dist/src/writing/prompt-optimizer.js +660 -0
- package/dist/src/writing/prompt-templates.js +583 -0
- package/dist/src/writing/scoring-config-loader.js +168 -0
- package/dist/src/writing/validation-engine.js +595 -0
- package/dist/src/writing/validation-rules.js +380 -0
- package/dist/src/writing/voice-analyzer.js +439 -0
- package/dist/src/writing/voice-calibration.js +661 -0
- package/dist/src/writing/voice-profiles.json +588 -0
- package/package.json +64 -9
|
@@ -0,0 +1,906 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin Metadata Validator
|
|
3
|
+
*
|
|
4
|
+
* Validates plugin manifest YAML files for schema correctness, required fields,
|
|
5
|
+
* version compatibility, and file reference validation.
|
|
6
|
+
*
|
|
7
|
+
* @module src/plugin/metadata-validator
|
|
8
|
+
*/
|
|
9
|
+
import * as fs from 'fs/promises';
|
|
10
|
+
import * as path from 'path';
|
|
11
|
+
import * as yaml from 'js-yaml';
|
|
12
|
+
import semver from 'semver';
|
|
13
|
+
import { validateSkillFrontmatter } from '../extensions/validation.js';
|
|
14
|
+
/**
|
|
15
|
+
* MetadataValidator validates plugin manifest files
|
|
16
|
+
*/
|
|
17
|
+
export class MetadataValidator {
|
|
18
|
+
options;
|
|
19
|
+
constructor(options = {}) {
|
|
20
|
+
this.options = {
|
|
21
|
+
checkFileReferences: true,
|
|
22
|
+
strict: false,
|
|
23
|
+
autoFix: false,
|
|
24
|
+
...options
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Validate a manifest file from the filesystem
|
|
29
|
+
*
|
|
30
|
+
* @param manifestPath - Absolute path to manifest.md or BEHAVIOR.md file
|
|
31
|
+
* @returns Validation result with errors and warnings
|
|
32
|
+
*/
|
|
33
|
+
async validateFile(manifestPath) {
|
|
34
|
+
const result = {
|
|
35
|
+
valid: false,
|
|
36
|
+
errors: [],
|
|
37
|
+
warnings: []
|
|
38
|
+
};
|
|
39
|
+
try {
|
|
40
|
+
// Check file exists
|
|
41
|
+
const stats = await fs.stat(manifestPath);
|
|
42
|
+
if (!stats.isFile()) {
|
|
43
|
+
result.errors.push({
|
|
44
|
+
path: manifestPath,
|
|
45
|
+
message: 'Path is not a file',
|
|
46
|
+
severity: 'error'
|
|
47
|
+
});
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
// Read file content
|
|
51
|
+
const content = await fs.readFile(manifestPath, 'utf-8');
|
|
52
|
+
// Dispatch by filename — each artifact type has its own self-contained
|
|
53
|
+
// validator. Adding a new artifact type means adding a new method, not
|
|
54
|
+
// editing a growing if/else inside validateManifest.
|
|
55
|
+
const filename = path.basename(manifestPath);
|
|
56
|
+
const basePath = path.dirname(manifestPath);
|
|
57
|
+
const contentResult = filename === 'SKILL.md'
|
|
58
|
+
? await this.validateSkillManifest(content, basePath, filename)
|
|
59
|
+
: await this.validateManifest(content, basePath, filename);
|
|
60
|
+
// Merge results
|
|
61
|
+
result.errors = contentResult.errors;
|
|
62
|
+
result.warnings = contentResult.warnings;
|
|
63
|
+
result.manifest = contentResult.manifest;
|
|
64
|
+
result.valid = contentResult.valid;
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
if (error.code === 'ENOENT') {
|
|
69
|
+
result.errors.push({
|
|
70
|
+
path: manifestPath,
|
|
71
|
+
message: 'File not found',
|
|
72
|
+
severity: 'error'
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
result.errors.push({
|
|
77
|
+
path: manifestPath,
|
|
78
|
+
message: `Failed to read file: ${error.message}`,
|
|
79
|
+
severity: 'error'
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Validate manifest content from string
|
|
87
|
+
*
|
|
88
|
+
* @param content - Manifest file content
|
|
89
|
+
* @param basePath - Optional base path for file reference validation
|
|
90
|
+
* @param filename - Optional filename to infer type (e.g., 'BEHAVIOR.md')
|
|
91
|
+
* @returns Validation result
|
|
92
|
+
*/
|
|
93
|
+
async validateManifest(content, basePath, filename) {
|
|
94
|
+
const result = {
|
|
95
|
+
valid: false,
|
|
96
|
+
errors: [],
|
|
97
|
+
warnings: []
|
|
98
|
+
};
|
|
99
|
+
// Parse YAML frontmatter
|
|
100
|
+
const manifest = this.parseFrontmatter(content, result);
|
|
101
|
+
if (!manifest) {
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
// Infer type from filename for BEHAVIOR.md files that omit `type`
|
|
105
|
+
const manifestRec = manifest;
|
|
106
|
+
const isBehaviorFile = filename === 'BEHAVIOR.md' ||
|
|
107
|
+
(basePath && !('type' in manifestRec) &&
|
|
108
|
+
('triggers' in manifestRec || 'hooks' in manifestRec));
|
|
109
|
+
if (isBehaviorFile && !('type' in manifestRec)) {
|
|
110
|
+
manifestRec.type = 'behavior';
|
|
111
|
+
}
|
|
112
|
+
// Schema validation — use behavior-specific validation for behavior files
|
|
113
|
+
const schemaResult = isBehaviorFile
|
|
114
|
+
? this.validateBehaviorSchema(manifest)
|
|
115
|
+
: this.validateSchema(manifest);
|
|
116
|
+
result.errors.push(...schemaResult.errors);
|
|
117
|
+
result.warnings.push(...schemaResult.warnings);
|
|
118
|
+
if (schemaResult.valid) {
|
|
119
|
+
result.manifest = manifest;
|
|
120
|
+
// Required fields validation
|
|
121
|
+
const requiredErrors = this.validateRequiredFields(manifest);
|
|
122
|
+
result.errors.push(...requiredErrors);
|
|
123
|
+
// Version validation
|
|
124
|
+
const versionErrors = this.validateVersion(manifest.version);
|
|
125
|
+
result.errors.push(...versionErrors);
|
|
126
|
+
// Dependency validation
|
|
127
|
+
if (manifest.dependencies) {
|
|
128
|
+
const depErrors = this.validateDependencies(manifest.dependencies);
|
|
129
|
+
result.errors.push(...depErrors);
|
|
130
|
+
}
|
|
131
|
+
// File reference validation (if basePath provided and option enabled)
|
|
132
|
+
if (basePath && this.options.checkFileReferences && manifest.files) {
|
|
133
|
+
const fileErrors = await this.validateFileReferences(manifest, basePath);
|
|
134
|
+
result.errors.push(...fileErrors);
|
|
135
|
+
}
|
|
136
|
+
// Metadata completeness warnings
|
|
137
|
+
const metadataWarnings = this.checkMetadataCompleteness(manifest);
|
|
138
|
+
result.warnings.push(...metadataWarnings);
|
|
139
|
+
// Memory topology validation (if declared)
|
|
140
|
+
const topologyWarnings = this.validateMemoryTopology(manifest);
|
|
141
|
+
result.warnings.push(...topologyWarnings);
|
|
142
|
+
}
|
|
143
|
+
// Determine if valid (no errors, or warnings only if not strict)
|
|
144
|
+
result.valid = result.errors.length === 0 &&
|
|
145
|
+
(!this.options.strict || result.warnings.length === 0);
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Validate a SKILL.md frontmatter file.
|
|
150
|
+
*
|
|
151
|
+
* SKILL.md is a separate artifact type from manifest.md/BEHAVIOR.md and
|
|
152
|
+
* has its own schema ({@link SkillFrontmatterSchema} in
|
|
153
|
+
* `src/extensions/validation.ts`). It does NOT carry `version`, `type`,
|
|
154
|
+
* `dependencies`, or `files` fields, so we route it through a dedicated
|
|
155
|
+
* validator instead of branching inside {@link validateManifest}.
|
|
156
|
+
*
|
|
157
|
+
* Adding a new artifact type? Add a sibling method here, then dispatch
|
|
158
|
+
* to it from {@link validateFile} based on filename.
|
|
159
|
+
*
|
|
160
|
+
* @param content - Full SKILL.md file contents (frontmatter + body)
|
|
161
|
+
* @param _basePath - Reserved for future cross-file checks
|
|
162
|
+
* @param filename - File basename, used in error.path for diagnostics
|
|
163
|
+
* @returns Validation result
|
|
164
|
+
*/
|
|
165
|
+
async validateSkillManifest(content, _basePath, filename) {
|
|
166
|
+
const result = {
|
|
167
|
+
valid: false,
|
|
168
|
+
errors: [],
|
|
169
|
+
warnings: []
|
|
170
|
+
};
|
|
171
|
+
const manifest = this.parseFrontmatter(content, result);
|
|
172
|
+
if (!manifest) {
|
|
173
|
+
return result;
|
|
174
|
+
}
|
|
175
|
+
const skillResult = validateSkillFrontmatter(manifest);
|
|
176
|
+
if (skillResult.success) {
|
|
177
|
+
result.manifest = manifest;
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
for (const issue of skillResult.errors.errors) {
|
|
181
|
+
result.errors.push({
|
|
182
|
+
path: filename,
|
|
183
|
+
field: issue.path.join('.'),
|
|
184
|
+
message: issue.message,
|
|
185
|
+
severity: 'error',
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
result.valid = result.errors.length === 0 &&
|
|
190
|
+
(!this.options.strict || result.warnings.length === 0);
|
|
191
|
+
return result;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Validate manifest schema structure
|
|
195
|
+
*
|
|
196
|
+
* @param manifest - Parsed manifest object
|
|
197
|
+
* @returns Validation result
|
|
198
|
+
*/
|
|
199
|
+
validateSchema(manifest) {
|
|
200
|
+
const result = {
|
|
201
|
+
valid: true,
|
|
202
|
+
errors: [],
|
|
203
|
+
warnings: []
|
|
204
|
+
};
|
|
205
|
+
if (!manifest || typeof manifest !== 'object') {
|
|
206
|
+
result.valid = false;
|
|
207
|
+
result.errors.push({
|
|
208
|
+
message: 'Manifest must be an object',
|
|
209
|
+
severity: 'error'
|
|
210
|
+
});
|
|
211
|
+
return result;
|
|
212
|
+
}
|
|
213
|
+
const obj = manifest;
|
|
214
|
+
// Check required top-level fields exist
|
|
215
|
+
const requiredFields = ['name', 'version', 'type', 'description'];
|
|
216
|
+
for (const field of requiredFields) {
|
|
217
|
+
if (!(field in obj)) {
|
|
218
|
+
result.valid = false;
|
|
219
|
+
result.errors.push({
|
|
220
|
+
field,
|
|
221
|
+
message: `Missing required field: ${field}`,
|
|
222
|
+
severity: 'error'
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// Type validations
|
|
227
|
+
if ('name' in obj && typeof obj.name !== 'string') {
|
|
228
|
+
result.valid = false;
|
|
229
|
+
result.errors.push({
|
|
230
|
+
field: 'name',
|
|
231
|
+
message: 'Field "name" must be a string',
|
|
232
|
+
severity: 'error'
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
if ('version' in obj && typeof obj.version !== 'string') {
|
|
236
|
+
result.valid = false;
|
|
237
|
+
result.errors.push({
|
|
238
|
+
field: 'version',
|
|
239
|
+
message: 'Field "version" must be a string',
|
|
240
|
+
severity: 'error'
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
if ('type' in obj) {
|
|
244
|
+
const validTypes = ['agent', 'command', 'template', 'flow', 'behavior'];
|
|
245
|
+
if (typeof obj.type !== 'string' || !validTypes.includes(obj.type)) {
|
|
246
|
+
result.valid = false;
|
|
247
|
+
result.errors.push({
|
|
248
|
+
field: 'type',
|
|
249
|
+
message: `Field "type" must be one of: ${validTypes.join(', ')}`,
|
|
250
|
+
severity: 'error'
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if ('description' in obj && typeof obj.description !== 'string') {
|
|
255
|
+
result.valid = false;
|
|
256
|
+
result.errors.push({
|
|
257
|
+
field: 'description',
|
|
258
|
+
message: 'Field "description" must be a string',
|
|
259
|
+
severity: 'error'
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
if ('files' in obj) {
|
|
263
|
+
if (!Array.isArray(obj.files)) {
|
|
264
|
+
result.valid = false;
|
|
265
|
+
result.errors.push({
|
|
266
|
+
field: 'files',
|
|
267
|
+
message: 'Field "files" must be an array',
|
|
268
|
+
severity: 'error'
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
else if (!obj.files.every(f => typeof f === 'string')) {
|
|
272
|
+
result.valid = false;
|
|
273
|
+
result.errors.push({
|
|
274
|
+
field: 'files',
|
|
275
|
+
message: 'All items in "files" must be strings',
|
|
276
|
+
severity: 'error'
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
if ('dependencies' in obj && obj.dependencies !== null) {
|
|
281
|
+
if (typeof obj.dependencies !== 'object' || Array.isArray(obj.dependencies)) {
|
|
282
|
+
result.valid = false;
|
|
283
|
+
result.errors.push({
|
|
284
|
+
field: 'dependencies',
|
|
285
|
+
message: 'Field "dependencies" must be an object',
|
|
286
|
+
severity: 'error'
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if ('metadata' in obj && obj.metadata !== null) {
|
|
291
|
+
if (typeof obj.metadata !== 'object' || Array.isArray(obj.metadata)) {
|
|
292
|
+
result.valid = false;
|
|
293
|
+
result.errors.push({
|
|
294
|
+
field: 'metadata',
|
|
295
|
+
message: 'Field "metadata" must be an object',
|
|
296
|
+
severity: 'error'
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return result;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Validate BEHAVIOR.md schema structure
|
|
304
|
+
*
|
|
305
|
+
* BEHAVIOR.md files use a different schema than manifest.md:
|
|
306
|
+
* - Required: name, version, description, platforms
|
|
307
|
+
* - Optional: triggers, inputs, hooks, scripts, manifest, scope, tone, routing, memory
|
|
308
|
+
*
|
|
309
|
+
* @param manifest - Parsed frontmatter object
|
|
310
|
+
* @returns Validation result
|
|
311
|
+
*/
|
|
312
|
+
validateBehaviorSchema(manifest) {
|
|
313
|
+
const result = {
|
|
314
|
+
valid: true,
|
|
315
|
+
errors: [],
|
|
316
|
+
warnings: []
|
|
317
|
+
};
|
|
318
|
+
if (!manifest || typeof manifest !== 'object') {
|
|
319
|
+
result.valid = false;
|
|
320
|
+
result.errors.push({
|
|
321
|
+
message: 'Behavior manifest must be an object',
|
|
322
|
+
severity: 'error'
|
|
323
|
+
});
|
|
324
|
+
return result;
|
|
325
|
+
}
|
|
326
|
+
const obj = manifest;
|
|
327
|
+
// Required fields for BEHAVIOR.md
|
|
328
|
+
const requiredFields = ['name', 'version', 'description', 'platforms'];
|
|
329
|
+
for (const field of requiredFields) {
|
|
330
|
+
if (!(field in obj)) {
|
|
331
|
+
result.valid = false;
|
|
332
|
+
result.errors.push({
|
|
333
|
+
field,
|
|
334
|
+
message: `Missing required field: ${field}`,
|
|
335
|
+
severity: 'error'
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
// Type validations
|
|
340
|
+
if ('name' in obj && typeof obj.name !== 'string') {
|
|
341
|
+
result.valid = false;
|
|
342
|
+
result.errors.push({
|
|
343
|
+
field: 'name',
|
|
344
|
+
message: 'Field "name" must be a string',
|
|
345
|
+
severity: 'error'
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
if ('version' in obj) {
|
|
349
|
+
const version = obj.version;
|
|
350
|
+
if (typeof version !== 'string' && typeof version !== 'number') {
|
|
351
|
+
result.valid = false;
|
|
352
|
+
result.errors.push({
|
|
353
|
+
field: 'version',
|
|
354
|
+
message: 'Field "version" must be a string or number',
|
|
355
|
+
severity: 'error'
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
if ('description' in obj && typeof obj.description !== 'string') {
|
|
360
|
+
result.valid = false;
|
|
361
|
+
result.errors.push({
|
|
362
|
+
field: 'description',
|
|
363
|
+
message: 'Field "description" must be a string',
|
|
364
|
+
severity: 'error'
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
if ('platforms' in obj && !Array.isArray(obj.platforms)) {
|
|
368
|
+
result.valid = false;
|
|
369
|
+
result.errors.push({
|
|
370
|
+
field: 'platforms',
|
|
371
|
+
message: 'Field "platforms" must be an array',
|
|
372
|
+
severity: 'error'
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
// Optional field type checks
|
|
376
|
+
if ('triggers' in obj && !Array.isArray(obj.triggers)) {
|
|
377
|
+
result.valid = false;
|
|
378
|
+
result.errors.push({
|
|
379
|
+
field: 'triggers',
|
|
380
|
+
message: 'Field "triggers" must be an array of strings',
|
|
381
|
+
severity: 'error'
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
if ('inputs' in obj && !Array.isArray(obj.inputs)) {
|
|
385
|
+
result.valid = false;
|
|
386
|
+
result.errors.push({
|
|
387
|
+
field: 'inputs',
|
|
388
|
+
message: 'Field "inputs" must be an array',
|
|
389
|
+
severity: 'error'
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
if ('hooks' in obj && (typeof obj.hooks !== 'object' || Array.isArray(obj.hooks))) {
|
|
393
|
+
result.valid = false;
|
|
394
|
+
result.errors.push({
|
|
395
|
+
field: 'hooks',
|
|
396
|
+
message: 'Field "hooks" must be an object mapping event names to action arrays',
|
|
397
|
+
severity: 'error'
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
if ('scripts' in obj && (typeof obj.scripts !== 'object' || Array.isArray(obj.scripts))) {
|
|
401
|
+
result.valid = false;
|
|
402
|
+
result.errors.push({
|
|
403
|
+
field: 'scripts',
|
|
404
|
+
message: 'Field "scripts" must be an object mapping names to paths',
|
|
405
|
+
severity: 'error'
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
if ('scope' in obj) {
|
|
409
|
+
const validScopes = ['daemon', 'interactive', 'both'];
|
|
410
|
+
if (typeof obj.scope !== 'string' || !validScopes.includes(obj.scope)) {
|
|
411
|
+
result.valid = false;
|
|
412
|
+
result.errors.push({
|
|
413
|
+
field: 'scope',
|
|
414
|
+
message: `Field "scope" must be one of: ${validScopes.join(', ')}`,
|
|
415
|
+
severity: 'error'
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
// Completeness warnings
|
|
420
|
+
if (!('triggers' in obj) && !('hooks' in obj)) {
|
|
421
|
+
result.warnings.push({
|
|
422
|
+
field: 'triggers/hooks',
|
|
423
|
+
message: 'Behavior has neither triggers nor hooks — it cannot be activated',
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
if ('hooks' in obj && !('scripts' in obj)) {
|
|
427
|
+
result.warnings.push({
|
|
428
|
+
field: 'scripts',
|
|
429
|
+
message: 'Behavior has hooks but no scripts — hooks will have no effect',
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
return result;
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Validate required fields are present and non-empty
|
|
436
|
+
*
|
|
437
|
+
* @param manifest - Validated manifest object
|
|
438
|
+
* @returns Array of validation errors
|
|
439
|
+
*/
|
|
440
|
+
validateRequiredFields(manifest) {
|
|
441
|
+
const errors = [];
|
|
442
|
+
// Name validation
|
|
443
|
+
if (!manifest.name || manifest.name.trim() === '') {
|
|
444
|
+
errors.push({
|
|
445
|
+
field: 'name',
|
|
446
|
+
message: 'Field "name" cannot be empty',
|
|
447
|
+
severity: 'error'
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
// Description validation
|
|
451
|
+
if (!manifest.description || manifest.description.trim() === '') {
|
|
452
|
+
errors.push({
|
|
453
|
+
field: 'description',
|
|
454
|
+
message: 'Field "description" cannot be empty',
|
|
455
|
+
severity: 'error'
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
// Files validation (should have at least one file for agent/command types)
|
|
459
|
+
if (manifest.type === 'agent' || manifest.type === 'command') {
|
|
460
|
+
if (!manifest.files || manifest.files.length === 0) {
|
|
461
|
+
errors.push({
|
|
462
|
+
field: 'files',
|
|
463
|
+
message: `Field "files" is required for type "${manifest.type}"`,
|
|
464
|
+
severity: 'error'
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
// Behavior-specific validation (#609, #1025)
|
|
469
|
+
// Canonical shape per #1025: behavior fields nest under `metadata:`.
|
|
470
|
+
// The daemon loader (tools/daemon/behavior-loader.mjs) reads
|
|
471
|
+
// metadata.scope and metadata.triggers (plural).
|
|
472
|
+
if (manifest.type === 'behavior') {
|
|
473
|
+
const meta = manifest.metadata;
|
|
474
|
+
if (!meta || !('triggers' in meta)) {
|
|
475
|
+
errors.push({
|
|
476
|
+
field: 'metadata.triggers',
|
|
477
|
+
message: 'Behavior must declare a triggers array in metadata',
|
|
478
|
+
severity: 'error'
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
if (!meta?.scope) {
|
|
482
|
+
errors.push({
|
|
483
|
+
field: 'metadata.scope',
|
|
484
|
+
message: 'Behavior should declare scope (daemon, interactive, or both)',
|
|
485
|
+
severity: 'warning'
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
return errors;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Validate version string is valid semver
|
|
493
|
+
*
|
|
494
|
+
* @param version - Version string to validate
|
|
495
|
+
* @returns Array of validation errors
|
|
496
|
+
*/
|
|
497
|
+
validateVersion(version) {
|
|
498
|
+
const errors = [];
|
|
499
|
+
if (!version) {
|
|
500
|
+
errors.push({
|
|
501
|
+
field: 'version',
|
|
502
|
+
message: 'Version is required',
|
|
503
|
+
severity: 'error'
|
|
504
|
+
});
|
|
505
|
+
return errors;
|
|
506
|
+
}
|
|
507
|
+
// Check if valid semver
|
|
508
|
+
const parsed = semver.valid(version);
|
|
509
|
+
if (!parsed) {
|
|
510
|
+
errors.push({
|
|
511
|
+
field: 'version',
|
|
512
|
+
message: `Invalid semantic version: "${version}". Must follow semver format (e.g., 1.0.0)`,
|
|
513
|
+
severity: 'error'
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
return errors;
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Validate file references exist on filesystem
|
|
520
|
+
*
|
|
521
|
+
* @param manifest - Validated manifest object
|
|
522
|
+
* @param basePath - Base directory path for resolving relative file paths
|
|
523
|
+
* @returns Array of validation errors
|
|
524
|
+
*/
|
|
525
|
+
async validateFileReferences(manifest, basePath) {
|
|
526
|
+
const errors = [];
|
|
527
|
+
if (!manifest.files || manifest.files.length === 0) {
|
|
528
|
+
return errors;
|
|
529
|
+
}
|
|
530
|
+
for (const file of manifest.files) {
|
|
531
|
+
const filePath = path.resolve(basePath, file);
|
|
532
|
+
try {
|
|
533
|
+
const stats = await fs.stat(filePath);
|
|
534
|
+
if (!stats.isFile()) {
|
|
535
|
+
errors.push({
|
|
536
|
+
field: 'files',
|
|
537
|
+
path: file,
|
|
538
|
+
message: `Referenced path is not a file: ${file}`,
|
|
539
|
+
severity: 'error'
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
catch (error) {
|
|
544
|
+
if (error.code === 'ENOENT') {
|
|
545
|
+
errors.push({
|
|
546
|
+
field: 'files',
|
|
547
|
+
path: file,
|
|
548
|
+
message: `Referenced file does not exist: ${file}`,
|
|
549
|
+
severity: 'error'
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
else {
|
|
553
|
+
errors.push({
|
|
554
|
+
field: 'files',
|
|
555
|
+
path: file,
|
|
556
|
+
message: `Failed to access file "${file}": ${error.message}`,
|
|
557
|
+
severity: 'error'
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
return errors;
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* Validate dependency version ranges
|
|
566
|
+
*
|
|
567
|
+
* @param dependencies - Dependency map with version ranges
|
|
568
|
+
* @returns Array of validation errors
|
|
569
|
+
*/
|
|
570
|
+
validateDependencies(dependencies) {
|
|
571
|
+
const errors = [];
|
|
572
|
+
for (const [name, versionRange] of Object.entries(dependencies)) {
|
|
573
|
+
if (!name || name.trim() === '') {
|
|
574
|
+
errors.push({
|
|
575
|
+
field: 'dependencies',
|
|
576
|
+
message: 'Dependency name cannot be empty',
|
|
577
|
+
severity: 'error'
|
|
578
|
+
});
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
581
|
+
if (!versionRange || versionRange.trim() === '') {
|
|
582
|
+
errors.push({
|
|
583
|
+
field: 'dependencies',
|
|
584
|
+
path: name,
|
|
585
|
+
message: `Dependency "${name}" has empty version range`,
|
|
586
|
+
severity: 'error'
|
|
587
|
+
});
|
|
588
|
+
continue;
|
|
589
|
+
}
|
|
590
|
+
// Validate semver range
|
|
591
|
+
const validRange = semver.validRange(versionRange);
|
|
592
|
+
if (!validRange) {
|
|
593
|
+
errors.push({
|
|
594
|
+
field: 'dependencies',
|
|
595
|
+
path: name,
|
|
596
|
+
message: `Dependency "${name}" has invalid version range: "${versionRange}"`,
|
|
597
|
+
severity: 'error'
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
return errors;
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Check metadata completeness and provide warnings
|
|
605
|
+
*
|
|
606
|
+
* @param manifest - Validated manifest object
|
|
607
|
+
* @returns Array of warnings
|
|
608
|
+
*/
|
|
609
|
+
checkMetadataCompleteness(manifest) {
|
|
610
|
+
const warnings = [];
|
|
611
|
+
// Agent-specific warnings
|
|
612
|
+
if (manifest.type === 'agent') {
|
|
613
|
+
if (!manifest.model) {
|
|
614
|
+
warnings.push({
|
|
615
|
+
field: 'model',
|
|
616
|
+
message: 'Agent should specify a "model" field (e.g., "sonnet", "gpt-4")'
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
if (!manifest.tools) {
|
|
620
|
+
warnings.push({
|
|
621
|
+
field: 'tools',
|
|
622
|
+
message: 'Agent should specify a "tools" field listing available tools'
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
// Framework recommendation
|
|
627
|
+
if (!manifest.framework) {
|
|
628
|
+
warnings.push({
|
|
629
|
+
field: 'framework',
|
|
630
|
+
message: 'Consider specifying a "framework" field for better organization'
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
// Empty metadata object
|
|
634
|
+
if (manifest.metadata && Object.keys(manifest.metadata).length === 0) {
|
|
635
|
+
warnings.push({
|
|
636
|
+
field: 'metadata',
|
|
637
|
+
message: 'Metadata object is empty, consider removing or populating it'
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
return warnings;
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Validate memory.topology contract if declared
|
|
644
|
+
*
|
|
645
|
+
* Checks that declared paths follow .aiwg/ convention and required fields
|
|
646
|
+
* are present when topology is declared.
|
|
647
|
+
*
|
|
648
|
+
* @see ADR-021 — Semantic memory kernel architecture
|
|
649
|
+
*/
|
|
650
|
+
validateMemoryTopology(manifest) {
|
|
651
|
+
const warnings = [];
|
|
652
|
+
const memory = manifest.memory;
|
|
653
|
+
if (!memory)
|
|
654
|
+
return warnings;
|
|
655
|
+
const topology = memory.topology;
|
|
656
|
+
if (!topology)
|
|
657
|
+
return warnings;
|
|
658
|
+
const VALID_CROSS_REF_STYLES = ['at-mention', 'wikilink', 'markdown-link', 'yaml-ref'];
|
|
659
|
+
// Required topology fields
|
|
660
|
+
const requiredFields = ['namespace', 'rawSources', 'derivedPages', 'index', 'log', 'crossRefStyle'];
|
|
661
|
+
for (const field of requiredFields) {
|
|
662
|
+
if (!(field in topology)) {
|
|
663
|
+
warnings.push({
|
|
664
|
+
field: `memory.topology.${field}`,
|
|
665
|
+
message: `Missing required topology field: ${field}`,
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
// Namespace must start with .aiwg/
|
|
670
|
+
if (typeof topology.namespace === 'string' && !topology.namespace.startsWith('.aiwg/')) {
|
|
671
|
+
warnings.push({
|
|
672
|
+
field: 'memory.topology.namespace',
|
|
673
|
+
message: `Topology namespace should start with ".aiwg/" (got "${topology.namespace}")`,
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
// crossRefStyle must be a valid enum value
|
|
677
|
+
if (typeof topology.crossRefStyle === 'string' && !VALID_CROSS_REF_STYLES.includes(topology.crossRefStyle)) {
|
|
678
|
+
warnings.push({
|
|
679
|
+
field: 'memory.topology.crossRefStyle',
|
|
680
|
+
message: `Invalid crossRefStyle "${topology.crossRefStyle}". Valid: ${VALID_CROSS_REF_STYLES.join(', ')}`,
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
// derivedPages must be a non-empty object
|
|
684
|
+
if (topology.derivedPages) {
|
|
685
|
+
if (typeof topology.derivedPages !== 'object' || Array.isArray(topology.derivedPages)) {
|
|
686
|
+
warnings.push({
|
|
687
|
+
field: 'memory.topology.derivedPages',
|
|
688
|
+
message: 'derivedPages must be an object mapping category names to directory paths',
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
else if (Object.keys(topology.derivedPages).length === 0) {
|
|
692
|
+
warnings.push({
|
|
693
|
+
field: 'memory.topology.derivedPages',
|
|
694
|
+
message: 'derivedPages is empty — at least one page category should be declared',
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
// lintRules should be an array of strings if present
|
|
699
|
+
if ('lintRules' in topology && topology.lintRules !== undefined) {
|
|
700
|
+
if (!Array.isArray(topology.lintRules)) {
|
|
701
|
+
warnings.push({
|
|
702
|
+
field: 'memory.topology.lintRules',
|
|
703
|
+
message: 'lintRules must be an array of rule ID strings',
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
// ingestRequires should be an array of strings if present
|
|
708
|
+
if ('ingestRequires' in topology && topology.ingestRequires !== undefined) {
|
|
709
|
+
if (!Array.isArray(topology.ingestRequires)) {
|
|
710
|
+
warnings.push({
|
|
711
|
+
field: 'memory.topology.ingestRequires',
|
|
712
|
+
message: 'ingestRequires must be an array of capability strings',
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
return warnings;
|
|
717
|
+
}
|
|
718
|
+
/**
|
|
719
|
+
* Validate all manifests in a directory
|
|
720
|
+
*
|
|
721
|
+
* @param dirPath - Directory path to scan
|
|
722
|
+
* @param recursive - Whether to scan subdirectories recursively
|
|
723
|
+
* @returns Map of file paths to validation results
|
|
724
|
+
*/
|
|
725
|
+
async validateDirectory(dirPath, recursive = false) {
|
|
726
|
+
const results = new Map();
|
|
727
|
+
try {
|
|
728
|
+
const manifestFiles = await this.findManifestFiles(dirPath, recursive);
|
|
729
|
+
for (const manifestPath of manifestFiles) {
|
|
730
|
+
const result = await this.validateFile(manifestPath);
|
|
731
|
+
results.set(manifestPath, result);
|
|
732
|
+
}
|
|
733
|
+
return results;
|
|
734
|
+
}
|
|
735
|
+
catch (error) {
|
|
736
|
+
// Return empty results with error for the directory itself
|
|
737
|
+
const errorResult = {
|
|
738
|
+
valid: false,
|
|
739
|
+
errors: [{
|
|
740
|
+
path: dirPath,
|
|
741
|
+
message: `Failed to scan directory: ${error.message}`,
|
|
742
|
+
severity: 'error'
|
|
743
|
+
}],
|
|
744
|
+
warnings: []
|
|
745
|
+
};
|
|
746
|
+
results.set(dirPath, errorResult);
|
|
747
|
+
return results;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
/**
|
|
751
|
+
* Generate validation report in specified format
|
|
752
|
+
*
|
|
753
|
+
* @param results - Batch validation results
|
|
754
|
+
* @param format - Report format (text or json)
|
|
755
|
+
* @returns Formatted report string
|
|
756
|
+
*/
|
|
757
|
+
generateReport(results, format = 'text') {
|
|
758
|
+
if (format === 'json') {
|
|
759
|
+
return this.generateJsonReport(results);
|
|
760
|
+
}
|
|
761
|
+
return this.generateTextReport(results);
|
|
762
|
+
}
|
|
763
|
+
/**
|
|
764
|
+
* Parse YAML frontmatter from manifest content
|
|
765
|
+
*
|
|
766
|
+
* @param content - File content
|
|
767
|
+
* @param result - Validation result to populate with errors
|
|
768
|
+
* @returns Parsed manifest or null if parsing failed
|
|
769
|
+
*/
|
|
770
|
+
parseFrontmatter(content, result) {
|
|
771
|
+
try {
|
|
772
|
+
// Extract YAML frontmatter between --- delimiters
|
|
773
|
+
const frontmatterMatch = content.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
774
|
+
if (!frontmatterMatch) {
|
|
775
|
+
result.errors.push({
|
|
776
|
+
message: 'No YAML frontmatter found. Manifest must start with --- delimiter',
|
|
777
|
+
severity: 'error',
|
|
778
|
+
line: 1
|
|
779
|
+
});
|
|
780
|
+
return null;
|
|
781
|
+
}
|
|
782
|
+
const yamlContent = frontmatterMatch[1];
|
|
783
|
+
const parsed = yaml.load(yamlContent);
|
|
784
|
+
return parsed;
|
|
785
|
+
}
|
|
786
|
+
catch (error) {
|
|
787
|
+
result.errors.push({
|
|
788
|
+
message: `Failed to parse YAML: ${error.message}`,
|
|
789
|
+
severity: 'error',
|
|
790
|
+
line: error.mark?.line
|
|
791
|
+
});
|
|
792
|
+
return null;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
/**
|
|
796
|
+
* Find all manifest.md, BEHAVIOR.md, and SKILL.md files in a directory.
|
|
797
|
+
*
|
|
798
|
+
* Each filename routes to a different schema in {@link validateManifest}:
|
|
799
|
+
* - manifest.md — plugin manifest schema (requires version, type)
|
|
800
|
+
* - BEHAVIOR.md — behavior schema (triggers/hooks)
|
|
801
|
+
* - SKILL.md — skill frontmatter schema (name, description, …)
|
|
802
|
+
*
|
|
803
|
+
* @param dirPath - Directory to search
|
|
804
|
+
* @param recursive - Whether to search subdirectories
|
|
805
|
+
* @returns Array of absolute artifact file paths
|
|
806
|
+
*/
|
|
807
|
+
async findManifestFiles(dirPath, recursive) {
|
|
808
|
+
const manifestFiles = [];
|
|
809
|
+
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
810
|
+
for (const entry of entries) {
|
|
811
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
812
|
+
if (entry.isDirectory() && recursive) {
|
|
813
|
+
const subManifests = await this.findManifestFiles(fullPath, recursive);
|
|
814
|
+
manifestFiles.push(...subManifests);
|
|
815
|
+
}
|
|
816
|
+
else if (entry.isFile() && (entry.name === 'manifest.md' ||
|
|
817
|
+
entry.name === 'BEHAVIOR.md' ||
|
|
818
|
+
entry.name === 'SKILL.md')) {
|
|
819
|
+
manifestFiles.push(fullPath);
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
return manifestFiles;
|
|
823
|
+
}
|
|
824
|
+
/**
|
|
825
|
+
* Generate text format report
|
|
826
|
+
*
|
|
827
|
+
* @param results - Batch validation results
|
|
828
|
+
* @returns Formatted text report
|
|
829
|
+
*/
|
|
830
|
+
generateTextReport(results) {
|
|
831
|
+
const lines = [];
|
|
832
|
+
// Header
|
|
833
|
+
lines.push('Plugin Metadata Validation Report');
|
|
834
|
+
lines.push('='.repeat(50));
|
|
835
|
+
lines.push('');
|
|
836
|
+
// Summary statistics
|
|
837
|
+
const total = results.size;
|
|
838
|
+
const passed = Array.from(results.values()).filter(r => r.valid).length;
|
|
839
|
+
const failed = total - passed;
|
|
840
|
+
const totalErrors = Array.from(results.values()).reduce((sum, r) => sum + r.errors.length, 0);
|
|
841
|
+
const totalWarnings = Array.from(results.values()).reduce((sum, r) => sum + r.warnings.length, 0);
|
|
842
|
+
lines.push('Summary:');
|
|
843
|
+
lines.push(` Total Manifests: ${total}`);
|
|
844
|
+
lines.push(` Passed: ${passed}`);
|
|
845
|
+
lines.push(` Failed: ${failed}`);
|
|
846
|
+
lines.push(` Total Errors: ${totalErrors}`);
|
|
847
|
+
lines.push(` Total Warnings: ${totalWarnings}`);
|
|
848
|
+
lines.push('');
|
|
849
|
+
// Individual results
|
|
850
|
+
lines.push('Results:');
|
|
851
|
+
lines.push('-'.repeat(50));
|
|
852
|
+
for (const [filePath, result] of results) {
|
|
853
|
+
const status = result.valid ? '✓ PASS' : '✗ FAIL';
|
|
854
|
+
lines.push(`\n${status} ${filePath}`);
|
|
855
|
+
if (result.manifest) {
|
|
856
|
+
lines.push(` Name: ${result.manifest.name}`);
|
|
857
|
+
lines.push(` Version: ${result.manifest.version}`);
|
|
858
|
+
lines.push(` Type: ${result.manifest.type}`);
|
|
859
|
+
}
|
|
860
|
+
if (result.errors.length > 0) {
|
|
861
|
+
lines.push(' Errors:');
|
|
862
|
+
for (const error of result.errors) {
|
|
863
|
+
const location = error.field ? `[${error.field}]` : '';
|
|
864
|
+
const line = error.line ? `:${error.line}` : '';
|
|
865
|
+
lines.push(` ✗ ${location}${line} ${error.message}`);
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
if (result.warnings.length > 0) {
|
|
869
|
+
lines.push(' Warnings:');
|
|
870
|
+
for (const warning of result.warnings) {
|
|
871
|
+
const location = warning.field ? `[${warning.field}]` : '';
|
|
872
|
+
lines.push(` ⚠ ${location} ${warning.message}`);
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
lines.push('');
|
|
877
|
+
lines.push('='.repeat(50));
|
|
878
|
+
return lines.join('\n');
|
|
879
|
+
}
|
|
880
|
+
/**
|
|
881
|
+
* Generate JSON format report
|
|
882
|
+
*
|
|
883
|
+
* @param results - Batch validation results
|
|
884
|
+
* @returns JSON string
|
|
885
|
+
*/
|
|
886
|
+
generateJsonReport(results) {
|
|
887
|
+
const data = {
|
|
888
|
+
summary: {
|
|
889
|
+
total: results.size,
|
|
890
|
+
passed: Array.from(results.values()).filter(r => r.valid).length,
|
|
891
|
+
failed: Array.from(results.values()).filter(r => !r.valid).length,
|
|
892
|
+
totalErrors: Array.from(results.values()).reduce((sum, r) => sum + r.errors.length, 0),
|
|
893
|
+
totalWarnings: Array.from(results.values()).reduce((sum, r) => sum + r.warnings.length, 0)
|
|
894
|
+
},
|
|
895
|
+
results: Array.from(results.entries()).map(([path, result]) => ({
|
|
896
|
+
path,
|
|
897
|
+
valid: result.valid,
|
|
898
|
+
manifest: result.manifest,
|
|
899
|
+
errors: result.errors,
|
|
900
|
+
warnings: result.warnings
|
|
901
|
+
}))
|
|
902
|
+
};
|
|
903
|
+
return JSON.stringify(data, null, 2);
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
//# sourceMappingURL=metadata-validator.js.map
|