@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,1462 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Artifact Index CLI Commands
|
|
3
|
+
*
|
|
4
|
+
* Provides CLI interface for artifact index operations:
|
|
5
|
+
* - build: Build/rebuild the artifact index
|
|
6
|
+
* - query: Search artifacts by keyword, type, phase, tags
|
|
7
|
+
* - deps: Show artifact dependency graph
|
|
8
|
+
* - stats: Show index statistics
|
|
9
|
+
*
|
|
10
|
+
* Supports multi-graph architecture via --graph flag:
|
|
11
|
+
* - framework: AIWG framework source (shared, built during `aiwg use`)
|
|
12
|
+
* - project: SDLC artifacts in .aiwg/ (per-project)
|
|
13
|
+
* - codebase: Source code, tests, configs (per-project)
|
|
14
|
+
*
|
|
15
|
+
* @implements #420 #421
|
|
16
|
+
* @source @src/cli/handlers/subcommands.ts
|
|
17
|
+
* @tests @test/unit/artifacts/cli.test.ts
|
|
18
|
+
*/
|
|
19
|
+
import path from 'node:path';
|
|
20
|
+
import { GRAPH_CONFIGS, OPERATIONAL_DISCOVERY_TYPES, OPERATIONAL_SHOW_TYPES, isOperationalShowType, loadUserGraphConfigs, loadGlobalGraphConfigs, orderedGraphEntries, } from './types.js';
|
|
21
|
+
import { SUPPORTED_VIEWS } from './corpus-views/renderers.js';
|
|
22
|
+
import { parseResourceSelector, readVerifiedRegularFile, } from '../resources/web-release.js';
|
|
23
|
+
const MAX_RESOURCE_TRUST_ROOT_BYTES = 64 * 1024;
|
|
24
|
+
function webReleaseOptionsFromEnvironment() {
|
|
25
|
+
const baseUrl = process.env.AIWG_RESOURCE_BASE_URL;
|
|
26
|
+
const cacheRoot = process.env.AIWG_RESOURCE_CACHE_ROOT;
|
|
27
|
+
const trustRootFile = process.env.AIWG_RESOURCE_TRUST_ROOT_FILE;
|
|
28
|
+
let publicKeyPem;
|
|
29
|
+
if (trustRootFile !== undefined) {
|
|
30
|
+
if (trustRootFile.trim().length === 0) {
|
|
31
|
+
throw new Error('AIWG_RESOURCE_TRUST_ROOT_FILE must name a non-empty public PEM file');
|
|
32
|
+
}
|
|
33
|
+
publicKeyPem = readVerifiedRegularFile(path.resolve(trustRootFile), {
|
|
34
|
+
label: 'AIWG_RESOURCE_TRUST_ROOT_FILE public PEM',
|
|
35
|
+
maxBytes: MAX_RESOURCE_TRUST_ROOT_BYTES,
|
|
36
|
+
});
|
|
37
|
+
if (publicKeyPem.toString('utf8').trim().length === 0) {
|
|
38
|
+
throw new Error('AIWG_RESOURCE_TRUST_ROOT_FILE public PEM is empty');
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
...(baseUrl === undefined ? {} : { baseUrl }),
|
|
43
|
+
...(cacheRoot === undefined ? {} : { cacheRoot }),
|
|
44
|
+
...(publicKeyPem === undefined ? {} : { publicKeyPem }),
|
|
45
|
+
...(process.env.AIWG_RESOURCE_ALLOW_INSECURE_LOOPBACK_HTTP === '1'
|
|
46
|
+
? { allowInsecureLoopbackHttp: true }
|
|
47
|
+
: {}),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/** Parse --graph flag from args, returns undefined for "all graphs" */
|
|
51
|
+
function parseGraphFlag(args) {
|
|
52
|
+
const idx = args.indexOf('--graph');
|
|
53
|
+
if (idx === -1)
|
|
54
|
+
return undefined;
|
|
55
|
+
if (idx + 1 >= args.length || args[idx + 1].startsWith('--')) {
|
|
56
|
+
console.error('Error: --graph requires a graph name');
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
const val = args[idx + 1];
|
|
60
|
+
// Load user-defined graphs so validation is complete
|
|
61
|
+
loadUserGraphConfigs(process.cwd());
|
|
62
|
+
loadGlobalGraphConfigs();
|
|
63
|
+
if (val in GRAPH_CONFIGS)
|
|
64
|
+
return val;
|
|
65
|
+
// Corpus markdown views (#1490) are valid --graph targets for `index build`.
|
|
66
|
+
if (SUPPORTED_VIEWS.includes(val))
|
|
67
|
+
return val;
|
|
68
|
+
const validNames = [...Object.keys(GRAPH_CONFIGS), ...SUPPORTED_VIEWS].join(', ');
|
|
69
|
+
console.error(`Error: Invalid graph type '${val}'. Valid: ${validNames}`);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
function parseBackendFlag(args) {
|
|
73
|
+
const idx = args.indexOf('--backend');
|
|
74
|
+
if (idx === -1)
|
|
75
|
+
return undefined;
|
|
76
|
+
const value = args[idx + 1];
|
|
77
|
+
if (value === 'local' || value === 'fortemi-core')
|
|
78
|
+
return value;
|
|
79
|
+
console.error('Error: --backend must be local or fortemi-core');
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
function parseSearchBackendFlag(args) {
|
|
83
|
+
return parseBackendFlag(args) ?? 'fortemi-core';
|
|
84
|
+
}
|
|
85
|
+
function parseResourceSourceFlag(args) {
|
|
86
|
+
const indices = args
|
|
87
|
+
.map((arg, index) => arg === '--resource-source' ? index : -1)
|
|
88
|
+
.filter((index) => index >= 0);
|
|
89
|
+
if (indices.length > 1) {
|
|
90
|
+
console.error('Error: --resource-source may be specified only once');
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
if (indices.length === 0)
|
|
94
|
+
return 'local';
|
|
95
|
+
const value = args[indices[0] + 1];
|
|
96
|
+
if (value === 'local' || value === 'web' || value === 'auto')
|
|
97
|
+
return value;
|
|
98
|
+
console.error('Error: --resource-source must be local, web, or auto');
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
function parseAiwgVersionFlag(args) {
|
|
102
|
+
const indices = args
|
|
103
|
+
.map((arg, index) => arg === '--aiwg-version' ? index : -1)
|
|
104
|
+
.filter((index) => index >= 0);
|
|
105
|
+
if (indices.length > 1) {
|
|
106
|
+
console.error('Error: --aiwg-version may be specified only once');
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
if (indices.length === 0)
|
|
110
|
+
return undefined;
|
|
111
|
+
const value = args[indices[0] + 1];
|
|
112
|
+
if (!value || value.startsWith('--')) {
|
|
113
|
+
console.error('Error: --aiwg-version requires an exact calendar-semver version or channel name');
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
parseResourceSelector(value);
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
return value;
|
|
124
|
+
}
|
|
125
|
+
function firstPositionalArg(args, valueFlags) {
|
|
126
|
+
const skip = new Set();
|
|
127
|
+
for (let i = 0; i < args.length; i++) {
|
|
128
|
+
if (valueFlags.includes(args[i]) && i + 1 < args.length)
|
|
129
|
+
skip.add(i + 1);
|
|
130
|
+
}
|
|
131
|
+
return args.find((arg, index) => !arg.startsWith('--') && !skip.has(index));
|
|
132
|
+
}
|
|
133
|
+
function parseDirectionFlag(args, allowed, defaultValue, label) {
|
|
134
|
+
const idx = args.indexOf('--direction');
|
|
135
|
+
if (idx === -1)
|
|
136
|
+
return defaultValue;
|
|
137
|
+
const value = args[idx + 1];
|
|
138
|
+
if (allowed.includes(value))
|
|
139
|
+
return value;
|
|
140
|
+
console.error(`Error: --direction must be ${label}`);
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
function parseFlagValue(args, flag, errorMessage) {
|
|
144
|
+
const idx = args.indexOf(flag);
|
|
145
|
+
if (idx === -1)
|
|
146
|
+
return undefined;
|
|
147
|
+
const value = args[idx + 1];
|
|
148
|
+
if (!value || value.startsWith('--')) {
|
|
149
|
+
console.error(errorMessage);
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
return value;
|
|
153
|
+
}
|
|
154
|
+
function parsePositiveIntegerFlag(args, flag, defaultValue, errorMessage) {
|
|
155
|
+
const value = parseFlagValue(args, flag, errorMessage);
|
|
156
|
+
if (value === undefined)
|
|
157
|
+
return defaultValue;
|
|
158
|
+
const parsed = Number.parseInt(value, 10);
|
|
159
|
+
if (!Number.isInteger(parsed) || parsed < 1 || String(parsed) !== value) {
|
|
160
|
+
console.error(errorMessage);
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
return parsed;
|
|
164
|
+
}
|
|
165
|
+
function parseOptionalPositiveIntegerFlag(args, flag, errorMessage) {
|
|
166
|
+
const value = parseFlagValue(args, flag, errorMessage);
|
|
167
|
+
if (value === undefined)
|
|
168
|
+
return undefined;
|
|
169
|
+
const parsed = Number.parseInt(value, 10);
|
|
170
|
+
if (!Number.isInteger(parsed) || parsed < 1 || String(parsed) !== value) {
|
|
171
|
+
console.error(errorMessage);
|
|
172
|
+
process.exit(1);
|
|
173
|
+
}
|
|
174
|
+
return parsed;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Main index command router
|
|
178
|
+
*/
|
|
179
|
+
export async function main(args) {
|
|
180
|
+
const subcommand = args[0];
|
|
181
|
+
const subcommandArgs = args.slice(1);
|
|
182
|
+
// #1231 — intercept --help/-h before subcommand dispatch. Print the
|
|
183
|
+
// same usage block as the no-args case, but framed as help (exit 0)
|
|
184
|
+
// rather than as an unknown-subcommand error (exit 1).
|
|
185
|
+
if (subcommand === '--help' || subcommand === '-h') {
|
|
186
|
+
printIndexUsage();
|
|
187
|
+
process.exit(0);
|
|
188
|
+
}
|
|
189
|
+
switch (subcommand) {
|
|
190
|
+
case 'build':
|
|
191
|
+
await handleBuild(subcommandArgs);
|
|
192
|
+
break;
|
|
193
|
+
case 'query':
|
|
194
|
+
await handleQuery(subcommandArgs);
|
|
195
|
+
break;
|
|
196
|
+
case 'discover':
|
|
197
|
+
await handleDiscover(subcommandArgs);
|
|
198
|
+
break;
|
|
199
|
+
case 'show':
|
|
200
|
+
await handleShow(subcommandArgs);
|
|
201
|
+
break;
|
|
202
|
+
case 'export':
|
|
203
|
+
await handleExport(subcommandArgs);
|
|
204
|
+
break;
|
|
205
|
+
case 'sync':
|
|
206
|
+
await handleSync(subcommandArgs);
|
|
207
|
+
break;
|
|
208
|
+
case 'migrate-legacy':
|
|
209
|
+
await handleMigrateLegacy(subcommandArgs);
|
|
210
|
+
break;
|
|
211
|
+
case 'deps':
|
|
212
|
+
await handleDeps(subcommandArgs);
|
|
213
|
+
break;
|
|
214
|
+
case 'stats':
|
|
215
|
+
await handleStats(subcommandArgs);
|
|
216
|
+
break;
|
|
217
|
+
case 'status':
|
|
218
|
+
case 'list':
|
|
219
|
+
await handleStatus(subcommandArgs);
|
|
220
|
+
break;
|
|
221
|
+
case 'neighbors':
|
|
222
|
+
await handleNeighbors(subcommandArgs);
|
|
223
|
+
break;
|
|
224
|
+
case 'set':
|
|
225
|
+
await handleSetQuery(subcommandArgs);
|
|
226
|
+
break;
|
|
227
|
+
case 'embed':
|
|
228
|
+
await handleEmbed(subcommandArgs);
|
|
229
|
+
break;
|
|
230
|
+
case 'similar':
|
|
231
|
+
await handleSimilar(subcommandArgs);
|
|
232
|
+
break;
|
|
233
|
+
case 'dedup-report':
|
|
234
|
+
await handleDedup(subcommandArgs);
|
|
235
|
+
break;
|
|
236
|
+
case 'watch':
|
|
237
|
+
await handleWatch(subcommandArgs);
|
|
238
|
+
break;
|
|
239
|
+
case 'views': {
|
|
240
|
+
const { main: viewsMain } = await import('./views/cli.js');
|
|
241
|
+
await viewsMain(subcommandArgs);
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
case 'enrich': {
|
|
245
|
+
const { main: enrichMain } = await import('./enrichment/cli.js');
|
|
246
|
+
await enrichMain(subcommandArgs);
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
case 'doctor': {
|
|
250
|
+
const { main: doctorMain } = await import('./audit/cli.js');
|
|
251
|
+
await doctorMain(subcommandArgs);
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
case undefined:
|
|
255
|
+
console.error('Error: Index subcommand required');
|
|
256
|
+
console.log('');
|
|
257
|
+
printIndexUsage();
|
|
258
|
+
process.exit(1);
|
|
259
|
+
break;
|
|
260
|
+
default:
|
|
261
|
+
console.error(`Error: Unknown index subcommand '${subcommand}'`);
|
|
262
|
+
console.log('Available: build, query, discover, show, export, sync, migrate-legacy, deps, stats, status, list, neighbors, set, embed, similar, dedup-report, watch');
|
|
263
|
+
process.exit(1);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
function printIndexUsage() {
|
|
267
|
+
console.log('Usage: aiwg index <subcommand> [options]');
|
|
268
|
+
console.log('');
|
|
269
|
+
console.log('Available subcommands:');
|
|
270
|
+
console.log(' build Build/rebuild the artifact index');
|
|
271
|
+
console.log(' query Search artifacts by keyword, type, phase, tags');
|
|
272
|
+
console.log(' discover Capability search across operational asset types (#1214)');
|
|
273
|
+
console.log(' show Print the full text of a specific operational asset');
|
|
274
|
+
console.log(' export Export a browser-consumable index contract');
|
|
275
|
+
console.log(' sync Materialize the Fortemi Core static index cache');
|
|
276
|
+
console.log(' migrate-legacy Move legacy root indexes into graph sidecar indexes');
|
|
277
|
+
console.log(' deps Show artifact dependency graph');
|
|
278
|
+
console.log(' stats Show index statistics');
|
|
279
|
+
console.log(' status Enumerate the index-graph registry (freshness + drift); alias: list');
|
|
280
|
+
console.log(' neighbors Get neighbors of a node in a graph');
|
|
281
|
+
console.log(' set Set operations (intersection, union, difference) on neighbor sets');
|
|
282
|
+
console.log(' embed Build the semantic embedding index for a graph (opt-in deps)');
|
|
283
|
+
console.log(' similar Semantic neighbors of a node (requires embed)');
|
|
284
|
+
console.log(' dedup-report Near-duplicate node pairs above a similarity threshold');
|
|
285
|
+
console.log(' watch Start a filesystem watcher for automatic incremental index updates');
|
|
286
|
+
console.log('');
|
|
287
|
+
console.log('Options:');
|
|
288
|
+
console.log(' --graph <name> Target a specific graph (framework, project, codebase, source, user, or user-defined)');
|
|
289
|
+
console.log(' --all Build all known graphs (including user-defined)');
|
|
290
|
+
console.log('');
|
|
291
|
+
console.log('Examples:');
|
|
292
|
+
console.log(' aiwg index build');
|
|
293
|
+
console.log(' aiwg index build --all');
|
|
294
|
+
console.log(' aiwg index build --graph codebase --force');
|
|
295
|
+
console.log(' aiwg index discover "create intake"');
|
|
296
|
+
console.log(' aiwg index discover "deploy production" --limit 5 --json');
|
|
297
|
+
console.log(' aiwg index discover "audit security" --type skill');
|
|
298
|
+
console.log(' aiwg index show skill intake-wizard');
|
|
299
|
+
console.log(' aiwg index show skill flow-deploy-to-production --json');
|
|
300
|
+
console.log(' aiwg index show metadata aiwg:skill:4840fa441622f676 --json');
|
|
301
|
+
console.log(' aiwg index show agent aiwg-steward');
|
|
302
|
+
console.log(' aiwg index export --format fortemi --graph project --out aiwg-fortemi-index.json');
|
|
303
|
+
console.log(' aiwg index migrate-legacy --scope project --dry-run');
|
|
304
|
+
console.log(' aiwg index query "authentication" --type use-case');
|
|
305
|
+
console.log(' aiwg index query "security rules" --graph framework --json');
|
|
306
|
+
console.log(' aiwg index query "mixture of experts" --fulltext --graph papers # body text, BM25');
|
|
307
|
+
console.log(' aiwg index embed --graph papers --embed-body # body-granularity vectors');
|
|
308
|
+
console.log(' aiwg index deps .aiwg/requirements/UC-001.md');
|
|
309
|
+
console.log(' aiwg index stats --json');
|
|
310
|
+
console.log(' aiwg index stats --graph project');
|
|
311
|
+
console.log(' aiwg index neighbors --graph citation-network --node REF-008 --direction in --edge-type cites');
|
|
312
|
+
console.log(' aiwg index set --graph citation-network --op intersection --node-a REF-008 --node-b REF-016 --direction in');
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Handle 'index watch' command — filesystem watcher daemon for auto-index updates.
|
|
316
|
+
*
|
|
317
|
+
* Modes:
|
|
318
|
+
* aiwg index watch — start watcher (foreground)
|
|
319
|
+
* aiwg index watch --stop — stop a running watcher
|
|
320
|
+
* aiwg index watch --status — check watcher status
|
|
321
|
+
*
|
|
322
|
+
* @implements #795
|
|
323
|
+
*/
|
|
324
|
+
async function handleWatch(args) {
|
|
325
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
326
|
+
console.log('Usage: aiwg index watch [options]');
|
|
327
|
+
console.log('');
|
|
328
|
+
console.log('Start a filesystem watcher that triggers incremental index rebuilds');
|
|
329
|
+
console.log('when .aiwg/ files change. Uses the checksum manifest (#794) for fast');
|
|
330
|
+
console.log('change detection.');
|
|
331
|
+
console.log('');
|
|
332
|
+
console.log('Options:');
|
|
333
|
+
console.log(' --stop Stop a running watcher for this project');
|
|
334
|
+
console.log(' --status Show whether a watcher is running');
|
|
335
|
+
console.log(' --debounce <ms> Debounce window for batched updates (default: 500)');
|
|
336
|
+
console.log(' --graph <name> Graph to rebuild (default: project)');
|
|
337
|
+
console.log(' --verbose Log every detected change');
|
|
338
|
+
console.log('');
|
|
339
|
+
console.log('Examples:');
|
|
340
|
+
console.log(' aiwg index watch');
|
|
341
|
+
console.log(' aiwg index watch --verbose --debounce 1000');
|
|
342
|
+
console.log(' aiwg index watch --stop');
|
|
343
|
+
console.log(' aiwg index watch --status');
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
const cwd = process.cwd();
|
|
347
|
+
const { startWatcher, stopWatcher, getRunningPid } = await import('./watcher.js');
|
|
348
|
+
// --status: check if a watcher is running
|
|
349
|
+
if (args.includes('--status')) {
|
|
350
|
+
const pid = getRunningPid(cwd);
|
|
351
|
+
if (pid) {
|
|
352
|
+
console.log(`Watcher running: PID ${pid}`);
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
console.log('No watcher running for this project');
|
|
356
|
+
}
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
// --stop: terminate a running watcher
|
|
360
|
+
if (args.includes('--stop')) {
|
|
361
|
+
const stopped = stopWatcher(cwd);
|
|
362
|
+
if (stopped) {
|
|
363
|
+
console.log('Watcher stopped');
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
console.log('No watcher running for this project');
|
|
367
|
+
}
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
// --debounce <ms>
|
|
371
|
+
let debounceMs = 500;
|
|
372
|
+
const debounceIdx = args.indexOf('--debounce');
|
|
373
|
+
if (debounceIdx !== -1 && debounceIdx + 1 < args.length) {
|
|
374
|
+
const parsed = parseInt(args[debounceIdx + 1], 10);
|
|
375
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
376
|
+
debounceMs = parsed;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
// --graph <name>
|
|
380
|
+
const graph = parseGraphFlag(args);
|
|
381
|
+
const verbose = args.includes('--verbose');
|
|
382
|
+
try {
|
|
383
|
+
startWatcher({
|
|
384
|
+
cwd,
|
|
385
|
+
debounceMs,
|
|
386
|
+
verbose,
|
|
387
|
+
graph,
|
|
388
|
+
});
|
|
389
|
+
// startWatcher registers SIGINT/SIGTERM handlers; block the main thread
|
|
390
|
+
// until one of them fires. setInterval keeps Node alive indefinitely.
|
|
391
|
+
setInterval(() => { }, 1 << 30);
|
|
392
|
+
}
|
|
393
|
+
catch (err) {
|
|
394
|
+
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
395
|
+
process.exit(1);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Handle 'index build' command
|
|
400
|
+
*/
|
|
401
|
+
async function handleBuild(args) {
|
|
402
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
403
|
+
console.log('Usage: aiwg index build [options]');
|
|
404
|
+
console.log('');
|
|
405
|
+
console.log('Options:');
|
|
406
|
+
console.log(' --force Full rebuild (ignore checksums, re-index everything)');
|
|
407
|
+
console.log(' --verbose Show detailed progress during indexing');
|
|
408
|
+
console.log(' --all Build all known graphs (including user-defined)');
|
|
409
|
+
console.log(' --scope <dir> Limit scan to a specific subdirectory');
|
|
410
|
+
console.log(' --graph <name> Build a specific graph only (built-in or user-defined)');
|
|
411
|
+
console.log('');
|
|
412
|
+
console.log('Built-in graph names: project, codebase, source, user, framework');
|
|
413
|
+
console.log('User-defined graphs: configure under index.graphs in .aiwg/aiwg.config');
|
|
414
|
+
console.log('');
|
|
415
|
+
console.log('Default behavior (no --graph): builds all graphs with defaultBuild: true');
|
|
416
|
+
console.log('Multi-graph builds run by buildOrder/buildTier (refs → citations → bibliography before heavy graphs)');
|
|
417
|
+
console.log(' Built-in defaults: project (always), codebase (skipped if src/test/tools absent)');
|
|
418
|
+
console.log('');
|
|
419
|
+
console.log('Examples:');
|
|
420
|
+
console.log(' aiwg index build');
|
|
421
|
+
console.log(' aiwg index build --force');
|
|
422
|
+
console.log(' aiwg index build --graph codebase --force');
|
|
423
|
+
console.log(' aiwg index build --graph source --force');
|
|
424
|
+
console.log(' aiwg index build --graph user --force');
|
|
425
|
+
console.log(' aiwg index build --graph references # user-defined graph');
|
|
426
|
+
console.log(' aiwg index build --scope documentation/references');
|
|
427
|
+
console.log(' aiwg index build --all');
|
|
428
|
+
console.log(' aiwg index sync --all');
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
// Dynamic import to keep the CLI router lightweight
|
|
432
|
+
const { buildIndex } = await import('./index-builder.js');
|
|
433
|
+
const cwd = process.cwd();
|
|
434
|
+
// Validate the index config at build time (#1491) — fail fast on malformed graph defs.
|
|
435
|
+
await validateIndexConfigOrExit(cwd);
|
|
436
|
+
const force = args.includes('--force');
|
|
437
|
+
const verbose = args.includes('--verbose');
|
|
438
|
+
const all = args.includes('--all');
|
|
439
|
+
const graph = parseGraphFlag(args);
|
|
440
|
+
let scope;
|
|
441
|
+
const scopeIdx = args.indexOf('--scope');
|
|
442
|
+
if (scopeIdx !== -1 && scopeIdx + 1 < args.length) {
|
|
443
|
+
scope = args[scopeIdx + 1];
|
|
444
|
+
}
|
|
445
|
+
// Load user-defined graphs
|
|
446
|
+
loadUserGraphConfigs(cwd);
|
|
447
|
+
loadGlobalGraphConfigs();
|
|
448
|
+
let jsonBuilt = false;
|
|
449
|
+
let projectGraphBuilt = false;
|
|
450
|
+
if (graph) {
|
|
451
|
+
// --graph X: build the JSON graph if X is one; otherwise X may be a
|
|
452
|
+
// research-corpus markdown view, rendered below.
|
|
453
|
+
if (graph in GRAPH_CONFIGS) {
|
|
454
|
+
await buildIndex(cwd, { force, verbose, scope, graph, explicit: true });
|
|
455
|
+
jsonBuilt = true;
|
|
456
|
+
projectGraphBuilt = graph === 'project';
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
else if (all) {
|
|
460
|
+
// Build all known graphs — user asked for everything, but don't hard-error on missing dirs
|
|
461
|
+
for (const [name] of orderedGraphEntries(Object.entries(GRAPH_CONFIGS))) {
|
|
462
|
+
await buildIndex(cwd, { force, verbose, graph: name, explicit: false });
|
|
463
|
+
if (name === 'project')
|
|
464
|
+
projectGraphBuilt = true;
|
|
465
|
+
}
|
|
466
|
+
jsonBuilt = true;
|
|
467
|
+
}
|
|
468
|
+
else {
|
|
469
|
+
// Default: build graphs with defaultBuild=true; skip gracefully if their dirs don't exist
|
|
470
|
+
for (const [name, config] of orderedGraphEntries(Object.entries(GRAPH_CONFIGS))) {
|
|
471
|
+
if (config.defaultBuild) {
|
|
472
|
+
await buildIndex(cwd, { force, verbose, scope: name === Object.keys(GRAPH_CONFIGS)[0] ? scope : undefined, graph: name, explicit: false });
|
|
473
|
+
if (name === 'project')
|
|
474
|
+
projectGraphBuilt = true;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
jsonBuilt = true;
|
|
478
|
+
}
|
|
479
|
+
// Render research-corpus markdown views in the same process (#1490, Full A —
|
|
480
|
+
// the native replacement for the retired corpus-index-build/build.py).
|
|
481
|
+
// No-op when the project has no documentation/references/ corpus.
|
|
482
|
+
const { buildCorpusViews } = await import('./corpus-views/build.js');
|
|
483
|
+
const viewResults = await buildCorpusViews(cwd, { force, only: graph });
|
|
484
|
+
if (viewResults.length > 0) {
|
|
485
|
+
const built = viewResults.filter((r) => r.status === 'built').length;
|
|
486
|
+
const skipped = viewResults.filter((r) => r.status === 'skipped').length;
|
|
487
|
+
const unsupported = viewResults.filter((r) => r.status === 'unsupported').length;
|
|
488
|
+
console.log('');
|
|
489
|
+
console.log(`Markdown views: ${built} built, ${skipped} up to date${unsupported ? `, ${unsupported} unsupported` : ''} → indices/`);
|
|
490
|
+
if (verbose || unsupported) {
|
|
491
|
+
for (const r of viewResults) {
|
|
492
|
+
const extra = r.status === 'unsupported' ? ` (${r.error})` : '';
|
|
493
|
+
console.log(` ${r.graph}: ${r.status} → ${r.output}${extra}`);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
// A --graph that matched neither a JSON graph nor a rendered view is unknown.
|
|
498
|
+
if (graph && !jsonBuilt && viewResults.length === 0) {
|
|
499
|
+
console.error(`Unknown graph: ${graph}`);
|
|
500
|
+
process.exit(1);
|
|
501
|
+
}
|
|
502
|
+
// Mirror build.py: an unsupported view name in the manifest fails the build.
|
|
503
|
+
if (viewResults.some((r) => r.status === 'unsupported')) {
|
|
504
|
+
process.exit(1);
|
|
505
|
+
}
|
|
506
|
+
if (projectGraphBuilt) {
|
|
507
|
+
await syncProjectFortemiCoreCacheAfterBuild(cwd, verbose);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
async function syncProjectFortemiCoreCacheAfterBuild(cwd, verbose) {
|
|
511
|
+
try {
|
|
512
|
+
const { syncFortemiCoreIndex } = await import('./fortemi-core-sync.js');
|
|
513
|
+
const manifest = syncFortemiCoreIndex(cwd, { graph: 'project' });
|
|
514
|
+
if (verbose) {
|
|
515
|
+
console.log(`Fortemi Core project sync: ${manifest.status}, ${manifest.item_count} item(s) → ${manifest.export_path}`);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
catch (err) {
|
|
519
|
+
console.error(`Warning: Fortemi Core project sync failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
520
|
+
console.error('Run `aiwg index sync --graph project` before using Fortemi-backed `aiwg discover` or `aiwg show` for project-local artifacts.');
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Validate the project's index config (#1491) before building. Reads the
|
|
525
|
+
* canonical `.aiwg/aiwg.config` index block (config.yaml fallback) and rejects
|
|
526
|
+
* malformed graph defs at validate time with actionable messages.
|
|
527
|
+
*/
|
|
528
|
+
async function validateIndexConfigOrExit(cwd) {
|
|
529
|
+
const { readIndexConfig, validateIndexConfig } = await import('../config/aiwg-config.js');
|
|
530
|
+
const { index } = await readIndexConfig(cwd);
|
|
531
|
+
if (!index)
|
|
532
|
+
return;
|
|
533
|
+
const errors = validateIndexConfig(index);
|
|
534
|
+
if (errors.length > 0) {
|
|
535
|
+
console.error('✗ Invalid index config (#1491):');
|
|
536
|
+
for (const e of errors)
|
|
537
|
+
console.error(` - ${e}`);
|
|
538
|
+
console.error('Fix the errors above in .aiwg/aiwg.config (or legacy .aiwg/config.yaml) and re-run.');
|
|
539
|
+
process.exit(1);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Handle 'index query' command
|
|
544
|
+
*
|
|
545
|
+
* Stub — full implementation in #416
|
|
546
|
+
*/
|
|
547
|
+
async function handleQuery(args) {
|
|
548
|
+
const { queryIndex } = await import('./query-engine.js');
|
|
549
|
+
const cwd = process.cwd();
|
|
550
|
+
// Parse query text (positional args before any -- flags)
|
|
551
|
+
const textParts = [];
|
|
552
|
+
const flags = [];
|
|
553
|
+
let inFlags = false;
|
|
554
|
+
for (const arg of args) {
|
|
555
|
+
if (arg.startsWith('--')) {
|
|
556
|
+
inFlags = true;
|
|
557
|
+
}
|
|
558
|
+
if (inFlags) {
|
|
559
|
+
flags.push(arg);
|
|
560
|
+
}
|
|
561
|
+
else {
|
|
562
|
+
textParts.push(arg);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
const text = textParts.join(' ') || undefined;
|
|
566
|
+
const json = flags.includes('--json');
|
|
567
|
+
const fulltext = flags.includes('--fulltext');
|
|
568
|
+
const type = parseFlagValue(flags, '--type', 'Error: --type requires a value');
|
|
569
|
+
const phase = parseFlagValue(flags, '--phase', 'Error: --phase requires a value');
|
|
570
|
+
const tags = parseFlagValue(flags, '--tags', 'Error: --tags requires a value');
|
|
571
|
+
const updatedAfter = parseFlagValue(flags, '--updated-after', 'Error: --updated-after requires a value');
|
|
572
|
+
const limit = parseOptionalPositiveIntegerFlag(flags, '--limit', 'Error: --limit must be a positive integer');
|
|
573
|
+
const pathPattern = parseFlagValue(flags, '--path', 'Error: --path requires a value');
|
|
574
|
+
const graph = parseGraphFlag(flags);
|
|
575
|
+
const backend = parseSearchBackendFlag(flags);
|
|
576
|
+
// --semantic (#1493): conceptual similarity via the embedding index.
|
|
577
|
+
if (flags.includes('--semantic')) {
|
|
578
|
+
if (!text) {
|
|
579
|
+
console.error('Error: --semantic requires a query string.');
|
|
580
|
+
process.exit(1);
|
|
581
|
+
}
|
|
582
|
+
await runSemanticQuery(cwd, text, graph, limit ?? 10, json, backend);
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
if (flags.includes('--hybrid')) {
|
|
586
|
+
if (!text) {
|
|
587
|
+
console.error('Error: --hybrid requires a query string.');
|
|
588
|
+
process.exit(1);
|
|
589
|
+
}
|
|
590
|
+
await runHybridQuery(cwd, {
|
|
591
|
+
text,
|
|
592
|
+
graph,
|
|
593
|
+
limit: limit ?? 10,
|
|
594
|
+
path: pathPattern,
|
|
595
|
+
type,
|
|
596
|
+
phase,
|
|
597
|
+
tags: tags?.split(','),
|
|
598
|
+
}, json, backend);
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
await queryIndex(cwd, {
|
|
602
|
+
text,
|
|
603
|
+
type,
|
|
604
|
+
phase,
|
|
605
|
+
tags: tags?.split(','),
|
|
606
|
+
updatedAfter,
|
|
607
|
+
limit,
|
|
608
|
+
path: pathPattern,
|
|
609
|
+
fulltext,
|
|
610
|
+
}, { json, graph, backend });
|
|
611
|
+
}
|
|
612
|
+
/** Resolve the embedding index dir for a graph, or null if deps/index absent (with guidance printed). */
|
|
613
|
+
async function requireEmbeddingIndex(cwd, graph) {
|
|
614
|
+
const { checkEmbeddingDeps, loadEmbeddingManifest } = await import('./embedding-index.js');
|
|
615
|
+
const { resolveIndexDir } = await import('./index-reader.js');
|
|
616
|
+
const deps = await checkEmbeddingDeps();
|
|
617
|
+
if (!deps.available) {
|
|
618
|
+
console.error(`Error: semantic search needs optional dependencies: ${deps.missing.join(', ')}`);
|
|
619
|
+
console.error('Install them to enable semantic features:');
|
|
620
|
+
console.error(' npm install @xenova/transformers hnswlib-node');
|
|
621
|
+
return null;
|
|
622
|
+
}
|
|
623
|
+
const dir = resolveIndexDir(cwd, graph);
|
|
624
|
+
if (!loadEmbeddingManifest(dir)) {
|
|
625
|
+
console.error(`Error: no embedding index for graph '${graph ?? 'default'}'.`);
|
|
626
|
+
console.error(`Build one first: aiwg index embed${graph ? ` --graph ${graph}` : ''}`);
|
|
627
|
+
return null;
|
|
628
|
+
}
|
|
629
|
+
return dir;
|
|
630
|
+
}
|
|
631
|
+
/** `aiwg index query "..." --semantic` — ranked semantic results, mapped back to index metadata. */
|
|
632
|
+
async function runSemanticQuery(cwd, text, graph, topK, json, backend) {
|
|
633
|
+
if (backend === 'fortemi-core') {
|
|
634
|
+
const { queryFortemiCoreStaticSemanticIndex } = await import('./fortemi-core-query-adapter.js');
|
|
635
|
+
const queried = queryFortemiCoreStaticSemanticIndex(cwd, {
|
|
636
|
+
graph,
|
|
637
|
+
text,
|
|
638
|
+
limit: topK,
|
|
639
|
+
});
|
|
640
|
+
if (queried.reason) {
|
|
641
|
+
if (json) {
|
|
642
|
+
console.log(JSON.stringify({
|
|
643
|
+
query: { text, backend: 'fortemi-core' },
|
|
644
|
+
mode: 'semantic',
|
|
645
|
+
graph: graph ?? null,
|
|
646
|
+
results: [],
|
|
647
|
+
total: 0,
|
|
648
|
+
hint: queried.reason,
|
|
649
|
+
}, null, 2));
|
|
650
|
+
}
|
|
651
|
+
else {
|
|
652
|
+
console.error(`Error: ${queried.reason}`);
|
|
653
|
+
}
|
|
654
|
+
process.exit(1);
|
|
655
|
+
}
|
|
656
|
+
if (json) {
|
|
657
|
+
console.log(JSON.stringify({
|
|
658
|
+
query: { text, backend: 'fortemi-core' },
|
|
659
|
+
mode: 'semantic',
|
|
660
|
+
graph: graph ?? null,
|
|
661
|
+
results: queried.results,
|
|
662
|
+
total: queried.results.length,
|
|
663
|
+
}, null, 2));
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
console.log(`Fortemi Core static semantic results for "${text}" (${queried.results.length}):`);
|
|
667
|
+
console.log('');
|
|
668
|
+
for (let i = 0; i < queried.results.length; i++) {
|
|
669
|
+
const r = queried.results[i];
|
|
670
|
+
console.log(` ${String(i + 1).padStart(3)} ${r.score.toFixed(3)} ${r.path} ${r.title}`);
|
|
671
|
+
}
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
const dir = await requireEmbeddingIndex(cwd, graph);
|
|
675
|
+
if (!dir)
|
|
676
|
+
process.exit(1);
|
|
677
|
+
const { semanticQuery, loadEmbeddingManifest } = await import('./embedding-index.js');
|
|
678
|
+
const { loadGraphIndexFile } = await import('./index-reader.js');
|
|
679
|
+
const index = loadGraphIndexFile(cwd, 'metadata.json', graph);
|
|
680
|
+
const manifest = loadEmbeddingManifest(dir);
|
|
681
|
+
const results = await semanticQuery(text, dir, topK);
|
|
682
|
+
if (json) {
|
|
683
|
+
console.log(JSON.stringify({
|
|
684
|
+
query: { text },
|
|
685
|
+
mode: 'semantic',
|
|
686
|
+
graph: graph ?? null,
|
|
687
|
+
embedding: {
|
|
688
|
+
granularity: manifest?.granularity ?? 'title-summary',
|
|
689
|
+
model: manifest?.model ?? null,
|
|
690
|
+
},
|
|
691
|
+
results: results.map((r) => ({
|
|
692
|
+
path: r.nodeId,
|
|
693
|
+
score: Math.round(r.score * 100) / 100,
|
|
694
|
+
title: index?.entries[r.nodeId]?.title,
|
|
695
|
+
summary: index?.entries[r.nodeId]?.summary,
|
|
696
|
+
})),
|
|
697
|
+
total: results.length,
|
|
698
|
+
}, null, 2));
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
console.log(`Semantic results for "${text}" (${results.length}, granularity: ${manifest?.granularity ?? 'title-summary'}):`);
|
|
702
|
+
console.log('');
|
|
703
|
+
for (let i = 0; i < results.length; i++) {
|
|
704
|
+
const r = results[i];
|
|
705
|
+
const title = index?.entries[r.nodeId]?.title ?? '';
|
|
706
|
+
console.log(` ${String(i + 1).padStart(3)} ${r.score.toFixed(3)} ${r.nodeId}${title ? ` ${title}` : ''}`);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
/** `aiwg index query "..." --hybrid` — static semantic scoring plus filters/facets. */
|
|
710
|
+
async function runHybridQuery(cwd, options, json, backend) {
|
|
711
|
+
if (backend !== 'fortemi-core') {
|
|
712
|
+
console.error('Error: --hybrid uses the Fortemi Core static contract by default. Remove --backend local or use local semantic/fulltext modes separately.');
|
|
713
|
+
process.exit(1);
|
|
714
|
+
}
|
|
715
|
+
const { queryFortemiCoreStaticHybridIndex } = await import('./fortemi-core-query-adapter.js');
|
|
716
|
+
const queried = queryFortemiCoreStaticHybridIndex(cwd, options);
|
|
717
|
+
if (queried.reason) {
|
|
718
|
+
if (json) {
|
|
719
|
+
console.log(JSON.stringify({
|
|
720
|
+
query: { text: options.text, backend: 'fortemi-core' },
|
|
721
|
+
mode: 'hybrid',
|
|
722
|
+
graph: options.graph ?? null,
|
|
723
|
+
results: [],
|
|
724
|
+
total: 0,
|
|
725
|
+
hint: queried.reason,
|
|
726
|
+
}, null, 2));
|
|
727
|
+
}
|
|
728
|
+
else {
|
|
729
|
+
console.error(`Error: ${queried.reason}`);
|
|
730
|
+
}
|
|
731
|
+
process.exit(1);
|
|
732
|
+
}
|
|
733
|
+
if (json) {
|
|
734
|
+
console.log(JSON.stringify({
|
|
735
|
+
query: { text: options.text, backend: 'fortemi-core' },
|
|
736
|
+
mode: 'hybrid',
|
|
737
|
+
graph: options.graph ?? null,
|
|
738
|
+
results: queried.results,
|
|
739
|
+
total: queried.results.length,
|
|
740
|
+
}, null, 2));
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
console.log(`Fortemi Core static hybrid results for "${options.text}" (${queried.results.length}):`);
|
|
744
|
+
console.log('');
|
|
745
|
+
for (let i = 0; i < queried.results.length; i++) {
|
|
746
|
+
const r = queried.results[i];
|
|
747
|
+
console.log(` ${String(i + 1).padStart(3)} ${r.score.toFixed(3)} ${r.path} ${r.title}`);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
/** `aiwg index embed [--graph X] [--model M] [--granularity title-summary|body]` — build the embedding index. */
|
|
751
|
+
async function handleEmbed(args) {
|
|
752
|
+
const cwd = process.cwd();
|
|
753
|
+
const graph = parseGraphFlag(args);
|
|
754
|
+
const model = args.indexOf('--model') !== -1 ? args[args.indexOf('--model') + 1] : undefined;
|
|
755
|
+
const requestedGranularity = args.includes('--embed-body')
|
|
756
|
+
? 'body'
|
|
757
|
+
: parseFlagValue(args, '--granularity', 'Error: --granularity requires title-summary, metadata, or body') ?? 'title-summary';
|
|
758
|
+
if (!['title-summary', 'metadata', 'body'].includes(requestedGranularity)) {
|
|
759
|
+
console.error('Error: --granularity must be title-summary, metadata, or body');
|
|
760
|
+
process.exit(1);
|
|
761
|
+
}
|
|
762
|
+
const granularity = requestedGranularity === 'metadata' ? 'title-summary' : requestedGranularity;
|
|
763
|
+
const { checkEmbeddingDeps, buildEmbeddingIndex, DEFAULT_EMBEDDING_MODEL } = await import('./embedding-index.js');
|
|
764
|
+
const { resolveIndexDir, loadGraphIndexFile } = await import('./index-reader.js');
|
|
765
|
+
const deps = await checkEmbeddingDeps();
|
|
766
|
+
if (!deps.available) {
|
|
767
|
+
console.error(`Error: embedding needs optional dependencies: ${deps.missing.join(', ')}`);
|
|
768
|
+
console.error(' npm install @xenova/transformers hnswlib-node');
|
|
769
|
+
process.exit(1);
|
|
770
|
+
}
|
|
771
|
+
const index = loadGraphIndexFile(cwd, 'metadata.json', graph);
|
|
772
|
+
if (!index || Object.keys(index.entries).length === 0) {
|
|
773
|
+
console.error(`Error: no metadata index for graph '${graph ?? 'default'}'. Run 'aiwg index build${graph ? ` --graph ${graph}` : ''}' first.`);
|
|
774
|
+
process.exit(1);
|
|
775
|
+
}
|
|
776
|
+
const dir = resolveIndexDir(cwd, graph);
|
|
777
|
+
console.log(`Embedding ${Object.keys(index.entries).length} nodes (model: ${model ?? DEFAULT_EMBEDDING_MODEL}, granularity: ${granularity})…`);
|
|
778
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
779
|
+
const n = await buildEmbeddingIndex(index.entries, dir, model, {
|
|
780
|
+
granularity: granularity,
|
|
781
|
+
cwd,
|
|
782
|
+
});
|
|
783
|
+
console.log(`Embedded ${n} nodes → ${dir}/embeddings/`);
|
|
784
|
+
}
|
|
785
|
+
/** `aiwg index similar --node X [--graph X] [--top K]` — semantic neighbors of a node. */
|
|
786
|
+
async function handleSimilar(args) {
|
|
787
|
+
const cwd = process.cwd();
|
|
788
|
+
const graph = parseGraphFlag(args);
|
|
789
|
+
const node = args.indexOf('--node') !== -1 ? args[args.indexOf('--node') + 1] : undefined;
|
|
790
|
+
const top = args.indexOf('--top') !== -1 ? parseInt(args[args.indexOf('--top') + 1], 10) : 10;
|
|
791
|
+
const json = args.includes('--json');
|
|
792
|
+
if (!node) {
|
|
793
|
+
console.error('Error: similar requires --node <id>.');
|
|
794
|
+
process.exit(1);
|
|
795
|
+
}
|
|
796
|
+
const dir = await requireEmbeddingIndex(cwd, graph);
|
|
797
|
+
if (!dir)
|
|
798
|
+
process.exit(1);
|
|
799
|
+
const { semanticNeighbors } = await import('./embedding-index.js');
|
|
800
|
+
const { loadGraphIndexFile } = await import('./index-reader.js');
|
|
801
|
+
const index = loadGraphIndexFile(cwd, 'metadata.json', graph);
|
|
802
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
803
|
+
const results = await semanticNeighbors(node, (index?.entries ?? {}), dir, top);
|
|
804
|
+
if (json) {
|
|
805
|
+
console.log(JSON.stringify({ node, graph: graph ?? null, results: results.map((r) => ({ path: r.nodeId, score: Math.round(r.score * 100) / 100, title: index?.entries[r.nodeId]?.title })) }, null, 2));
|
|
806
|
+
return;
|
|
807
|
+
}
|
|
808
|
+
console.log(`Similar to ${node} (${results.length}):`);
|
|
809
|
+
for (const r of results)
|
|
810
|
+
console.log(` ${r.score.toFixed(3)} ${r.nodeId}${index?.entries[r.nodeId]?.title ? ` ${index.entries[r.nodeId].title}` : ''}`);
|
|
811
|
+
}
|
|
812
|
+
/** `aiwg index dedup-report [--graph X] [--threshold T]` — near-duplicate node pairs. */
|
|
813
|
+
async function handleDedup(args) {
|
|
814
|
+
const cwd = process.cwd();
|
|
815
|
+
const graph = parseGraphFlag(args);
|
|
816
|
+
const threshold = args.indexOf('--threshold') !== -1 ? parseFloat(args[args.indexOf('--threshold') + 1]) : 0.92;
|
|
817
|
+
const json = args.includes('--json');
|
|
818
|
+
const dir = await requireEmbeddingIndex(cwd, graph);
|
|
819
|
+
if (!dir)
|
|
820
|
+
process.exit(1);
|
|
821
|
+
const { dedupReport, loadEmbeddingManifest } = await import('./embedding-index.js');
|
|
822
|
+
const { loadGraphIndexFile } = await import('./index-reader.js');
|
|
823
|
+
const index = loadGraphIndexFile(cwd, 'metadata.json', graph);
|
|
824
|
+
const manifest = loadEmbeddingManifest(dir);
|
|
825
|
+
const pairs = await dedupReport(dir, threshold);
|
|
826
|
+
if (json) {
|
|
827
|
+
console.log(JSON.stringify({
|
|
828
|
+
graph: graph ?? null,
|
|
829
|
+
threshold,
|
|
830
|
+
embedding: {
|
|
831
|
+
granularity: manifest?.granularity ?? 'title-summary',
|
|
832
|
+
model: manifest?.model ?? null,
|
|
833
|
+
},
|
|
834
|
+
pairs: pairs.map((p) => ({ ...p, score: Math.round(p.score * 1000) / 1000 })),
|
|
835
|
+
}, null, 2));
|
|
836
|
+
return;
|
|
837
|
+
}
|
|
838
|
+
console.log(`Near-duplicate pairs (cosine ≥ ${threshold}, granularity: ${manifest?.granularity ?? 'title-summary'}): ${pairs.length}`);
|
|
839
|
+
console.log('');
|
|
840
|
+
for (const p of pairs) {
|
|
841
|
+
const ta = index?.entries[p.a]?.title ?? '';
|
|
842
|
+
const tb = index?.entries[p.b]?.title ?? '';
|
|
843
|
+
console.log(` ${p.score.toFixed(3)} ${p.a} ↔ ${p.b}`);
|
|
844
|
+
if (ta || tb)
|
|
845
|
+
console.log(` ${ta} | ${tb}`);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
/**
|
|
849
|
+
* Handle 'index export' command
|
|
850
|
+
*/
|
|
851
|
+
async function handleExport(args) {
|
|
852
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
853
|
+
console.log('Usage: aiwg index export --format fortemi|fortemi-shard [options]');
|
|
854
|
+
console.log('');
|
|
855
|
+
console.log('Options:');
|
|
856
|
+
console.log(' --format fortemi Export the AIWG/Fortemi browser contract (required)');
|
|
857
|
+
console.log(' --format fortemi-shard Export a portable Fortemi Knowledge Shard');
|
|
858
|
+
console.log(' --graph <name> Graph to export (default: project)');
|
|
859
|
+
console.log(' --out <path> Write JSON or .shard output to a file');
|
|
860
|
+
console.log(' --repo <name> Source repository label (default: cwd basename)');
|
|
861
|
+
console.log(' --privacy <level> private, sanitized, or public (default: private)');
|
|
862
|
+
console.log(' --schema-version <v> Export contract version: v1 or v2 (default: v1)');
|
|
863
|
+
console.log(' --generated-at <iso> Override generated timestamp for deterministic fixtures');
|
|
864
|
+
console.log('');
|
|
865
|
+
console.log('Examples:');
|
|
866
|
+
console.log(' aiwg index export --format fortemi --graph project --out aiwg-fortemi-index.json');
|
|
867
|
+
console.log(' aiwg index export --format fortemi-shard --graph project --out aiwg-index.shard');
|
|
868
|
+
console.log(' aiwg index export --format fortemi --privacy sanitized --generated-at 2026-01-01T00:00:00.000Z');
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
const format = parseFlagValue(args, '--format', 'Error: index export requires --format fortemi or fortemi-shard');
|
|
872
|
+
if (format !== 'fortemi' && format !== 'fortemi-shard') {
|
|
873
|
+
console.error('Error: index export requires --format fortemi or fortemi-shard');
|
|
874
|
+
process.exit(1);
|
|
875
|
+
}
|
|
876
|
+
const graph = parseGraphFlag(args);
|
|
877
|
+
const out = parseFlagValue(args, '--out', 'Error: --out requires a file path');
|
|
878
|
+
const repo = parseFlagValue(args, '--repo', 'Error: --repo requires a value');
|
|
879
|
+
const privacy = parseFlagValue(args, '--privacy', 'Error: --privacy must be private, sanitized, or public');
|
|
880
|
+
if (privacy && !['private', 'sanitized', 'public'].includes(privacy)) {
|
|
881
|
+
console.error('Error: --privacy must be private, sanitized, or public');
|
|
882
|
+
process.exit(1);
|
|
883
|
+
}
|
|
884
|
+
const generatedAt = parseFlagValue(args, '--generated-at', 'Error: --generated-at requires an ISO timestamp value');
|
|
885
|
+
const schemaVersion = parseFlagValue(args, '--schema-version', 'Error: --schema-version must be v1 or v2');
|
|
886
|
+
if (schemaVersion && !['v1', 'v2'].includes(schemaVersion)) {
|
|
887
|
+
console.error('Error: --schema-version must be v1 or v2');
|
|
888
|
+
process.exit(1);
|
|
889
|
+
}
|
|
890
|
+
if (format === 'fortemi-shard' && schemaVersion && schemaVersion !== 'v2') {
|
|
891
|
+
console.error('Error: --format fortemi-shard requires --schema-version v2');
|
|
892
|
+
process.exit(1);
|
|
893
|
+
}
|
|
894
|
+
if (format === 'fortemi-shard' && !out) {
|
|
895
|
+
console.error('Error: --format fortemi-shard requires --out <path>');
|
|
896
|
+
process.exit(1);
|
|
897
|
+
}
|
|
898
|
+
try {
|
|
899
|
+
if (format === 'fortemi-shard') {
|
|
900
|
+
const { writeAiwgFortemiKnowledgeShard } = await import('./fortemi-shard-export.js');
|
|
901
|
+
const result = await writeAiwgFortemiKnowledgeShard(process.cwd(), out, {
|
|
902
|
+
graph,
|
|
903
|
+
repo,
|
|
904
|
+
privacy: privacy,
|
|
905
|
+
generatedAt,
|
|
906
|
+
});
|
|
907
|
+
console.log(`Exported ${result.items} AIWG records to ${result.outPath} (${result.bytes} bytes)`);
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
const { buildAiwgFortemiIndexExport, writeAiwgFortemiIndexExport } = await import('./browser-export.js');
|
|
911
|
+
const exported = buildAiwgFortemiIndexExport(process.cwd(), {
|
|
912
|
+
graph,
|
|
913
|
+
repo,
|
|
914
|
+
privacy: privacy,
|
|
915
|
+
generatedAt,
|
|
916
|
+
schemaVersion: schemaVersion,
|
|
917
|
+
});
|
|
918
|
+
writeAiwgFortemiIndexExport(exported, out);
|
|
919
|
+
}
|
|
920
|
+
catch (err) {
|
|
921
|
+
console.error('Error: ' + (err instanceof Error ? err.message : String(err)));
|
|
922
|
+
process.exit(1);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
/**
|
|
926
|
+
* Handle 'index sync' command
|
|
927
|
+
*/
|
|
928
|
+
async function handleSync(args) {
|
|
929
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
930
|
+
console.log('Usage: aiwg index sync [--backend fortemi-core] [options]');
|
|
931
|
+
console.log('');
|
|
932
|
+
console.log('Options:');
|
|
933
|
+
console.log(' --backend fortemi-core Materialize the Fortemi Core static index cache (default)');
|
|
934
|
+
console.log(' --graph <name> Graph to sync (default: project)');
|
|
935
|
+
console.log(' --all Sync all built graph caches in build-order');
|
|
936
|
+
console.log(' --repo <name> Source repository label (default: cwd basename)');
|
|
937
|
+
console.log(' --privacy <level> private, sanitized, or public (default: private)');
|
|
938
|
+
console.log(' --generated-at <iso> Override generated timestamp for deterministic fixtures');
|
|
939
|
+
console.log(' --json Print the sync manifest as JSON');
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
const backend = parseSearchBackendFlag(args);
|
|
943
|
+
if (backend !== 'fortemi-core') {
|
|
944
|
+
console.error('Error: index sync only supports the fortemi-core backend; omit --backend or pass --backend fortemi-core');
|
|
945
|
+
process.exit(1);
|
|
946
|
+
}
|
|
947
|
+
const graph = parseGraphFlag(args);
|
|
948
|
+
const all = args.includes('--all');
|
|
949
|
+
if (graph && all) {
|
|
950
|
+
console.error('Error: pass either --graph or --all, not both');
|
|
951
|
+
process.exit(1);
|
|
952
|
+
}
|
|
953
|
+
const repo = parseFlagValue(args, '--repo', 'Error: --repo requires a value');
|
|
954
|
+
const privacy = parseFlagValue(args, '--privacy', 'Error: --privacy must be private, sanitized, or public');
|
|
955
|
+
if (privacy && !['private', 'sanitized', 'public'].includes(privacy)) {
|
|
956
|
+
console.error('Error: --privacy must be private, sanitized, or public');
|
|
957
|
+
process.exit(1);
|
|
958
|
+
}
|
|
959
|
+
const generatedAt = parseFlagValue(args, '--generated-at', 'Error: --generated-at requires an ISO timestamp value');
|
|
960
|
+
const json = args.includes('--json');
|
|
961
|
+
const { syncFortemiCoreIndex } = await import('./fortemi-core-sync.js');
|
|
962
|
+
try {
|
|
963
|
+
const cwd = process.cwd();
|
|
964
|
+
loadUserGraphConfigs(cwd);
|
|
965
|
+
loadGlobalGraphConfigs();
|
|
966
|
+
const options = {
|
|
967
|
+
repo,
|
|
968
|
+
privacy: privacy,
|
|
969
|
+
generatedAt,
|
|
970
|
+
};
|
|
971
|
+
if (all) {
|
|
972
|
+
const { loadGraphIndexFile } = await import('./index-reader.js');
|
|
973
|
+
const manifests = [];
|
|
974
|
+
for (const [name] of orderedGraphEntries(Object.entries(GRAPH_CONFIGS))) {
|
|
975
|
+
if (!loadGraphIndexFile(cwd, 'metadata.json', name))
|
|
976
|
+
continue;
|
|
977
|
+
manifests.push(syncFortemiCoreIndex(cwd, { ...options, graph: name }));
|
|
978
|
+
}
|
|
979
|
+
if (json) {
|
|
980
|
+
console.log(JSON.stringify({ manifests }, null, 2));
|
|
981
|
+
return;
|
|
982
|
+
}
|
|
983
|
+
console.log(`Fortemi Core sync: ${manifests.length} graph(s)`);
|
|
984
|
+
for (const manifest of manifests) {
|
|
985
|
+
console.log(` ${manifest.graph}: ${manifest.status}, ${manifest.item_count} item(s) → ${manifest.export_path}`);
|
|
986
|
+
}
|
|
987
|
+
return;
|
|
988
|
+
}
|
|
989
|
+
const manifest = syncFortemiCoreIndex(cwd, {
|
|
990
|
+
...options,
|
|
991
|
+
graph,
|
|
992
|
+
});
|
|
993
|
+
if (json) {
|
|
994
|
+
console.log(JSON.stringify(manifest, null, 2));
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
console.log(`Fortemi Core ${manifest.status}: ${manifest.item_count} item(s) → ${manifest.export_path}`);
|
|
998
|
+
}
|
|
999
|
+
catch (err) {
|
|
1000
|
+
console.error('Error: ' + (err instanceof Error ? err.message : String(err)));
|
|
1001
|
+
process.exit(1);
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
/**
|
|
1005
|
+
* Handle 'index migrate-legacy' command.
|
|
1006
|
+
*/
|
|
1007
|
+
async function handleMigrateLegacy(args) {
|
|
1008
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
1009
|
+
console.log('Usage: aiwg index migrate-legacy [--scope project|user|global | --all] [options]');
|
|
1010
|
+
console.log('');
|
|
1011
|
+
console.log('Migrates compatible legacy root index files into graph sidecar index');
|
|
1012
|
+
console.log('directories. Project scope moves .aiwg/.index/*.json to');
|
|
1013
|
+
console.log('.aiwg/.index/project/*.json and refreshes the Fortemi Core static');
|
|
1014
|
+
console.log('cache. User/global scopes report or migrate their corresponding');
|
|
1015
|
+
console.log('sidecar locations without modifying packaged/prebuilt AIWG indexes.');
|
|
1016
|
+
console.log('');
|
|
1017
|
+
console.log('Options:');
|
|
1018
|
+
console.log(' --scope <name> Scope to migrate: project, user, or global (default: project)');
|
|
1019
|
+
console.log(' --all Migrate project, user, and global scopes');
|
|
1020
|
+
console.log(' --dry-run Print planned changes without writing files');
|
|
1021
|
+
console.log(' --no-fortemi-sync Do not refresh the project Fortemi Core static cache');
|
|
1022
|
+
console.log(' --generated-at <iso> Override generated timestamp for deterministic fixtures');
|
|
1023
|
+
console.log(' --json Print the migration report as JSON');
|
|
1024
|
+
console.log('');
|
|
1025
|
+
console.log('Examples:');
|
|
1026
|
+
console.log(' aiwg index migrate-legacy --scope project --dry-run');
|
|
1027
|
+
console.log(' aiwg index migrate-legacy --all --json');
|
|
1028
|
+
return;
|
|
1029
|
+
}
|
|
1030
|
+
const all = args.includes('--all');
|
|
1031
|
+
const scopeValue = parseFlagValue(args, '--scope', 'Error: --scope requires project, user, or global');
|
|
1032
|
+
if (all && scopeValue) {
|
|
1033
|
+
console.error('Error: pass either --all or --scope, not both');
|
|
1034
|
+
process.exit(1);
|
|
1035
|
+
}
|
|
1036
|
+
const allowedScopes = ['project', 'user', 'global'];
|
|
1037
|
+
const scopes = all
|
|
1038
|
+
? [...allowedScopes]
|
|
1039
|
+
: scopeValue
|
|
1040
|
+
? [scopeValue]
|
|
1041
|
+
: ['project'];
|
|
1042
|
+
const invalidScope = scopes.find((scope) => !allowedScopes.includes(scope));
|
|
1043
|
+
if (invalidScope) {
|
|
1044
|
+
console.error('Error: --scope must be project, user, or global');
|
|
1045
|
+
process.exit(1);
|
|
1046
|
+
}
|
|
1047
|
+
const generatedAt = parseFlagValue(args, '--generated-at', 'Error: --generated-at requires an ISO timestamp value');
|
|
1048
|
+
const { migrateLegacyIndex } = await import('./legacy-index-migration.js');
|
|
1049
|
+
try {
|
|
1050
|
+
const report = migrateLegacyIndex(process.cwd(), {
|
|
1051
|
+
scopes: scopes,
|
|
1052
|
+
dryRun: args.includes('--dry-run'),
|
|
1053
|
+
syncFortemi: !args.includes('--no-fortemi-sync'),
|
|
1054
|
+
generatedAt,
|
|
1055
|
+
});
|
|
1056
|
+
if (args.includes('--json')) {
|
|
1057
|
+
console.log(JSON.stringify(report, null, 2));
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
console.log(`Legacy index migration ${report.dryRun ? '(DRY RUN)' : 'complete'}`);
|
|
1061
|
+
for (const result of report.results) {
|
|
1062
|
+
const entries = result.entries === null ? 'unknown' : String(result.entries);
|
|
1063
|
+
const detail = result.reason ? ` — ${result.reason}` : '';
|
|
1064
|
+
console.log(` ${result.scope}: ${result.status} (${entries} entries)${detail}`);
|
|
1065
|
+
for (const file of result.files) {
|
|
1066
|
+
console.log(` ${file.name}: ${file.status}`);
|
|
1067
|
+
}
|
|
1068
|
+
if (result.fortemiCore) {
|
|
1069
|
+
console.log(` fortemi-core: ${result.fortemiCore.status} (${result.fortemiCore.itemCount} item(s)) → ${result.fortemiCore.exportPath}`);
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
if (report.reportPath) {
|
|
1073
|
+
console.log(` report: ${report.reportPath}`);
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
catch (err) {
|
|
1077
|
+
console.error('Error: ' + (err instanceof Error ? err.message : String(err)));
|
|
1078
|
+
process.exit(1);
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
/**
|
|
1082
|
+
* Handle 'index deps' command
|
|
1083
|
+
*
|
|
1084
|
+
* Stub — full implementation in #417
|
|
1085
|
+
*/
|
|
1086
|
+
async function handleDeps(args) {
|
|
1087
|
+
const { showDeps } = await import('./dep-graph.js');
|
|
1088
|
+
const cwd = process.cwd();
|
|
1089
|
+
// First non-flag arg is the artifact path
|
|
1090
|
+
const artifactPath = firstPositionalArg(args, ['--backend', '--direction', '--depth', '--edge-type', '--graph']);
|
|
1091
|
+
if (!artifactPath) {
|
|
1092
|
+
console.error('Error: Artifact path required');
|
|
1093
|
+
console.log('Usage: aiwg index deps <path> [--direction upstream|downstream|both] [--depth N] [--json] [--backend fortemi-core|local]');
|
|
1094
|
+
process.exit(1);
|
|
1095
|
+
}
|
|
1096
|
+
const json = args.includes('--json');
|
|
1097
|
+
const direction = parseDirectionFlag(args, ['upstream', 'downstream', 'both'], 'both', 'upstream, downstream, or both');
|
|
1098
|
+
const depth = parsePositiveIntegerFlag(args, '--depth', 3, 'Error: --depth must be a positive integer');
|
|
1099
|
+
const edgeType = parseFlagValue(args, '--edge-type', 'Error: --edge-type requires a value');
|
|
1100
|
+
const graph = parseGraphFlag(args);
|
|
1101
|
+
const backend = parseBackendFlag(args) ?? 'fortemi-core';
|
|
1102
|
+
await showDeps(cwd, artifactPath, {
|
|
1103
|
+
direction,
|
|
1104
|
+
depth,
|
|
1105
|
+
json,
|
|
1106
|
+
graph,
|
|
1107
|
+
edgeType,
|
|
1108
|
+
backend,
|
|
1109
|
+
});
|
|
1110
|
+
}
|
|
1111
|
+
/**
|
|
1112
|
+
* Handle 'index stats' command
|
|
1113
|
+
*
|
|
1114
|
+
* Stub — full implementation in #418
|
|
1115
|
+
*/
|
|
1116
|
+
async function handleStats(args) {
|
|
1117
|
+
const { showStats } = await import('./stats.js');
|
|
1118
|
+
const cwd = process.cwd();
|
|
1119
|
+
const json = args.includes('--json');
|
|
1120
|
+
const graph = parseGraphFlag(args);
|
|
1121
|
+
await showStats(cwd, { json, graph });
|
|
1122
|
+
}
|
|
1123
|
+
/**
|
|
1124
|
+
* Handle 'index status' / 'index list' — enumerate the durable index-graph
|
|
1125
|
+
* registry with build state, freshness, and drift (#1624).
|
|
1126
|
+
*/
|
|
1127
|
+
async function handleStatus(args) {
|
|
1128
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
1129
|
+
console.log('Usage: aiwg index status [--json]');
|
|
1130
|
+
console.log(' aiwg index list [--json] (alias)');
|
|
1131
|
+
console.log('');
|
|
1132
|
+
console.log('Enumerate every registered index graph (built-in + module + operator)');
|
|
1133
|
+
console.log('with its build state, freshness, and drift. Surfaces durable indices that');
|
|
1134
|
+
console.log('are registered but never built, on-disk index dirs that match no graph,');
|
|
1135
|
+
console.log('and graph-config defs that previously failed to load silently (#1624).');
|
|
1136
|
+
console.log('');
|
|
1137
|
+
console.log('Examples:');
|
|
1138
|
+
console.log(' aiwg index status');
|
|
1139
|
+
console.log(' aiwg index status --json');
|
|
1140
|
+
return;
|
|
1141
|
+
}
|
|
1142
|
+
const { showIndexStatus } = await import('./index-status.js');
|
|
1143
|
+
await showIndexStatus(process.cwd(), { json: args.includes('--json') });
|
|
1144
|
+
}
|
|
1145
|
+
/**
|
|
1146
|
+
* Handle 'index neighbors' command
|
|
1147
|
+
*
|
|
1148
|
+
* @implements #725
|
|
1149
|
+
*/
|
|
1150
|
+
async function handleNeighbors(args) {
|
|
1151
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
1152
|
+
console.log('Usage: aiwg index neighbors --graph <name> --node <id> [options]');
|
|
1153
|
+
console.log('');
|
|
1154
|
+
console.log('Options:');
|
|
1155
|
+
console.log(' --graph <name> Graph to query (required)');
|
|
1156
|
+
console.log(' --node <id> Node path or REF-XXX identifier (required)');
|
|
1157
|
+
console.log(' --direction <dir> in (upstream), out (downstream), or both (default: both)');
|
|
1158
|
+
console.log(' --edge-type <type> Filter by edge type (e.g., "cites", "depends-on")');
|
|
1159
|
+
console.log(' --backend <name> fortemi-core or local legacy fallback (default: fortemi-core)');
|
|
1160
|
+
console.log(' --json Output as JSON');
|
|
1161
|
+
console.log('');
|
|
1162
|
+
console.log('Examples:');
|
|
1163
|
+
console.log(' aiwg index neighbors --graph citation-network --node REF-008 --direction in --edge-type cites');
|
|
1164
|
+
console.log(' aiwg index neighbors --graph project --node .aiwg/requirements/UC-001.md --json');
|
|
1165
|
+
return;
|
|
1166
|
+
}
|
|
1167
|
+
const { showNeighbors } = await import('./graph-query.js');
|
|
1168
|
+
const cwd = process.cwd();
|
|
1169
|
+
const graph = parseGraphFlag(args);
|
|
1170
|
+
if (!graph) {
|
|
1171
|
+
console.error('Error: --graph is required for neighbors command');
|
|
1172
|
+
process.exit(1);
|
|
1173
|
+
}
|
|
1174
|
+
let node = parseFlagValue(args, '--node', 'Error: --node is required for neighbors command');
|
|
1175
|
+
if (!node) {
|
|
1176
|
+
// Try first positional arg
|
|
1177
|
+
node = firstPositionalArg(args, ['--backend', '--direction', '--edge-type', '--graph', '--node']);
|
|
1178
|
+
}
|
|
1179
|
+
if (!node) {
|
|
1180
|
+
console.error('Error: --node is required for neighbors command');
|
|
1181
|
+
process.exit(1);
|
|
1182
|
+
}
|
|
1183
|
+
const direction = parseDirectionFlag(args, ['in', 'out', 'both'], 'both', 'in, out, or both');
|
|
1184
|
+
const edgeType = parseFlagValue(args, '--edge-type', 'Error: --edge-type requires a value');
|
|
1185
|
+
const json = args.includes('--json');
|
|
1186
|
+
const backend = parseSearchBackendFlag(args);
|
|
1187
|
+
await showNeighbors(cwd, { graph, node, direction, edgeType, json, backend });
|
|
1188
|
+
}
|
|
1189
|
+
/**
|
|
1190
|
+
* Handle 'index set' command
|
|
1191
|
+
*
|
|
1192
|
+
* @implements #725
|
|
1193
|
+
*/
|
|
1194
|
+
async function handleSetQuery(args) {
|
|
1195
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
1196
|
+
console.log('Usage: aiwg index set --graph <name> --op <operation> --node-a <id> --node-b <id> [options]');
|
|
1197
|
+
console.log('');
|
|
1198
|
+
console.log('Operations:');
|
|
1199
|
+
console.log(' intersection Nodes in both neighbor sets');
|
|
1200
|
+
console.log(' union Nodes in either neighbor set');
|
|
1201
|
+
console.log(' difference Nodes in A but not in B');
|
|
1202
|
+
console.log('');
|
|
1203
|
+
console.log('Options:');
|
|
1204
|
+
console.log(' --graph <name> Graph to query (required)');
|
|
1205
|
+
console.log(' --op <operation> Set operation (required)');
|
|
1206
|
+
console.log(' --node-a <id> First node (required)');
|
|
1207
|
+
console.log(' --node-b <id> Second node (required)');
|
|
1208
|
+
console.log(' --direction <dir> in (upstream) or out (downstream) (default: in)');
|
|
1209
|
+
console.log(' --edge-type <type> Filter by edge type');
|
|
1210
|
+
console.log(' --backend <name> fortemi-core or local legacy fallback (default: fortemi-core)');
|
|
1211
|
+
console.log(' --json Output as JSON');
|
|
1212
|
+
console.log('');
|
|
1213
|
+
console.log('Examples:');
|
|
1214
|
+
console.log(' # Papers that cited both REF-008 and REF-016');
|
|
1215
|
+
console.log(' aiwg index set --graph citation-network --op intersection --node-a REF-008 --node-b REF-016 --direction in');
|
|
1216
|
+
console.log('');
|
|
1217
|
+
console.log(' # Papers cited by REF-004 but not cited by REF-001');
|
|
1218
|
+
console.log(' aiwg index set --graph citation-network --op difference --node-a REF-004 --node-b REF-001 --direction out');
|
|
1219
|
+
return;
|
|
1220
|
+
}
|
|
1221
|
+
const { executeSetQuery } = await import('./graph-query.js');
|
|
1222
|
+
const cwd = process.cwd();
|
|
1223
|
+
const graph = parseGraphFlag(args);
|
|
1224
|
+
if (!graph) {
|
|
1225
|
+
console.error('Error: --graph is required for set command');
|
|
1226
|
+
process.exit(1);
|
|
1227
|
+
}
|
|
1228
|
+
const op = parseFlagValue(args, '--op', 'Error: --op is required (intersection, union, difference)');
|
|
1229
|
+
if (!op || !['intersection', 'union', 'difference'].includes(op)) {
|
|
1230
|
+
console.error('Error: --op is required (intersection, union, difference)');
|
|
1231
|
+
process.exit(1);
|
|
1232
|
+
}
|
|
1233
|
+
const nodeA = parseFlagValue(args, '--node-a', 'Error: --node-a and --node-b are required');
|
|
1234
|
+
const nodeB = parseFlagValue(args, '--node-b', 'Error: --node-a and --node-b are required');
|
|
1235
|
+
if (!nodeA || !nodeB) {
|
|
1236
|
+
console.error('Error: --node-a and --node-b are required');
|
|
1237
|
+
process.exit(1);
|
|
1238
|
+
}
|
|
1239
|
+
const direction = parseDirectionFlag(args, ['in', 'out'], 'in', 'in or out');
|
|
1240
|
+
const edgeType = parseFlagValue(args, '--edge-type', 'Error: --edge-type requires a value');
|
|
1241
|
+
const json = args.includes('--json');
|
|
1242
|
+
const backend = parseSearchBackendFlag(args);
|
|
1243
|
+
await executeSetQuery(cwd, {
|
|
1244
|
+
graph,
|
|
1245
|
+
op: op,
|
|
1246
|
+
nodeA,
|
|
1247
|
+
nodeB,
|
|
1248
|
+
direction,
|
|
1249
|
+
edgeType,
|
|
1250
|
+
json,
|
|
1251
|
+
backend,
|
|
1252
|
+
});
|
|
1253
|
+
}
|
|
1254
|
+
/**
|
|
1255
|
+
* Handle 'index discover' command — capability-search for AIWG operational
|
|
1256
|
+
* assets.
|
|
1257
|
+
*
|
|
1258
|
+
* Like `query` but tuned for capability lookups: ranks by trigger
|
|
1259
|
+
* phrase + capability description first, falls back to title/tag/path
|
|
1260
|
+
* matches. Defaults to the operational discovery surface,
|
|
1261
|
+
* narrowable via `--type`.
|
|
1262
|
+
*
|
|
1263
|
+
* Returns a token-tight format intended for in-context agent
|
|
1264
|
+
* consumption — path, score, type, top trigger, capability snippet.
|
|
1265
|
+
*
|
|
1266
|
+
* @implements #1214
|
|
1267
|
+
*/
|
|
1268
|
+
async function handleDiscover(args) {
|
|
1269
|
+
const { discoverCapability } = await import('./query-engine.js');
|
|
1270
|
+
const cwd = process.cwd();
|
|
1271
|
+
// Parse positional phrase (everything before flags)
|
|
1272
|
+
const textParts = [];
|
|
1273
|
+
const flags = [];
|
|
1274
|
+
let inFlags = false;
|
|
1275
|
+
for (const arg of args) {
|
|
1276
|
+
if (arg.startsWith('--'))
|
|
1277
|
+
inFlags = true;
|
|
1278
|
+
if (inFlags)
|
|
1279
|
+
flags.push(arg);
|
|
1280
|
+
else
|
|
1281
|
+
textParts.push(arg);
|
|
1282
|
+
}
|
|
1283
|
+
const phrase = textParts.join(' ').trim();
|
|
1284
|
+
if (!phrase) {
|
|
1285
|
+
console.error('Error: aiwg index discover requires a search phrase');
|
|
1286
|
+
console.log('');
|
|
1287
|
+
console.log('Usage: aiwg index discover "<phrase>" [--type <kinds>] [--limit N] [--json|--format json|text] [--pretty|--compact] [--graph <name>] [--backend local|fortemi-core] [--resource-source local|web|auto] [--aiwg-version <exact-or-channel>] [--offline]');
|
|
1288
|
+
console.log('');
|
|
1289
|
+
console.log('Examples:');
|
|
1290
|
+
console.log(' aiwg index discover "create intake"');
|
|
1291
|
+
console.log(' aiwg index discover "deploy production" --limit 5');
|
|
1292
|
+
console.log(` aiwg index discover "audit security" --type ${OPERATIONAL_DISCOVERY_TYPES.join(',')}`);
|
|
1293
|
+
console.log(' aiwg index discover "intake" --format json --pretty');
|
|
1294
|
+
console.log(' aiwg discover "intake" --resource-source web --aiwg-version stable');
|
|
1295
|
+
process.exit(1);
|
|
1296
|
+
}
|
|
1297
|
+
const typeValue = parseFlagValue(flags, '--type', 'Error: --type requires a value');
|
|
1298
|
+
const typeFilter = typeValue
|
|
1299
|
+
?.split(',')
|
|
1300
|
+
.map((s) => s.trim())
|
|
1301
|
+
.filter(Boolean);
|
|
1302
|
+
// K=5 default — see query-engine.ts comment (#1218 Wave A).
|
|
1303
|
+
const limit = parsePositiveIntegerFlag(flags, '--limit', 5, 'Error: --limit must be a positive integer');
|
|
1304
|
+
const format = parseFlagValue(flags, '--format', 'Error: --format requires text or json') ?? 'text';
|
|
1305
|
+
if (format !== 'text' && format !== 'json') {
|
|
1306
|
+
console.error('Error: --format must be text or json');
|
|
1307
|
+
process.exit(1);
|
|
1308
|
+
}
|
|
1309
|
+
const json = flags.includes('--json') || format === 'json';
|
|
1310
|
+
if (flags.includes('--pretty') && flags.includes('--compact')) {
|
|
1311
|
+
console.error('Error: --pretty and --compact cannot be used together');
|
|
1312
|
+
process.exit(1);
|
|
1313
|
+
}
|
|
1314
|
+
const jsonPretty = !flags.includes('--compact');
|
|
1315
|
+
const graph = parseGraphFlag(flags);
|
|
1316
|
+
const backend = parseSearchBackendFlag(flags);
|
|
1317
|
+
const resourceSource = parseResourceSourceFlag(flags);
|
|
1318
|
+
const aiwgVersion = parseAiwgVersionFlag(flags);
|
|
1319
|
+
const offline = flags.includes('--offline');
|
|
1320
|
+
const webReleaseOptions = resourceSource === 'local'
|
|
1321
|
+
? undefined
|
|
1322
|
+
: webReleaseOptionsFromEnvironment();
|
|
1323
|
+
await discoverCapability(cwd, {
|
|
1324
|
+
phrase,
|
|
1325
|
+
typeFilter,
|
|
1326
|
+
limit,
|
|
1327
|
+
json,
|
|
1328
|
+
jsonPretty,
|
|
1329
|
+
graph,
|
|
1330
|
+
backend,
|
|
1331
|
+
resourceSource,
|
|
1332
|
+
aiwgVersion,
|
|
1333
|
+
offline,
|
|
1334
|
+
webReleaseOptions,
|
|
1335
|
+
includePaths: false,
|
|
1336
|
+
});
|
|
1337
|
+
}
|
|
1338
|
+
/**
|
|
1339
|
+
* Handle 'index show' command — print the full text of a specific
|
|
1340
|
+
* artifact by type and name.
|
|
1341
|
+
*
|
|
1342
|
+
* Shape (#1218):
|
|
1343
|
+
* aiwg show <type> <name> [--json] [--first] [--graph <name>] [--backend local|fortemi-core]
|
|
1344
|
+
*
|
|
1345
|
+
* Type is positional (not a flag) so the verb reads as
|
|
1346
|
+
* "show <kind> <name>". `<type>` is one of the operational show types.
|
|
1347
|
+
*
|
|
1348
|
+
* Companion to `discover`: where discover ranks candidates, show fetches
|
|
1349
|
+
* the artifact body so consumers don't need to navigate the filesystem.
|
|
1350
|
+
*/
|
|
1351
|
+
async function handleShow(args) {
|
|
1352
|
+
const { showArtifact, showMetadata } = await import('./query-engine.js');
|
|
1353
|
+
const cwd = process.cwd();
|
|
1354
|
+
const positional = [];
|
|
1355
|
+
const flags = [];
|
|
1356
|
+
let inFlags = false;
|
|
1357
|
+
for (const arg of args) {
|
|
1358
|
+
if (arg.startsWith('--'))
|
|
1359
|
+
inFlags = true;
|
|
1360
|
+
if (inFlags)
|
|
1361
|
+
flags.push(arg);
|
|
1362
|
+
else
|
|
1363
|
+
positional.push(arg);
|
|
1364
|
+
}
|
|
1365
|
+
const HELP_TEXT = [
|
|
1366
|
+
'',
|
|
1367
|
+
'Usage: aiwg show <type> <name> [--json] [--first] [--graph <name>] [--backend local|fortemi-core] [--resource-source local|web|auto] [--aiwg-version <exact-or-channel>] [--offline]',
|
|
1368
|
+
' aiwg show metadata <id-or-name-or-path> [--json] [--first] [--graph <name>] [--backend local|fortemi-core] [--resource-source local|web|auto] [--aiwg-version <exact-or-channel>] [--offline]',
|
|
1369
|
+
' aiwg index show <type> <name> ...',
|
|
1370
|
+
'',
|
|
1371
|
+
`Types: ${OPERATIONAL_SHOW_TYPES.join(' | ')}`,
|
|
1372
|
+
'',
|
|
1373
|
+
'Examples:',
|
|
1374
|
+
' aiwg show skill intake-wizard',
|
|
1375
|
+
' aiwg show skill flow-deploy-to-production --json',
|
|
1376
|
+
' aiwg show flow flow-release --json',
|
|
1377
|
+
' aiwg show behavior quiet-bot --json',
|
|
1378
|
+
' aiwg show template config.toml --json',
|
|
1379
|
+
' aiwg show metadata aiwg:skill:4840fa441622f676 --json',
|
|
1380
|
+
' aiwg show agent aiwg-steward',
|
|
1381
|
+
' aiwg show command discover',
|
|
1382
|
+
' aiwg show skill intake-wizard --resource-source web --aiwg-version stable',
|
|
1383
|
+
'',
|
|
1384
|
+
'Tip: use `aiwg discover "<phrase>" --json` first to find the stable id.',
|
|
1385
|
+
].join('\n');
|
|
1386
|
+
if (positional.length === 0) {
|
|
1387
|
+
console.error('Error: aiwg show requires a type and name');
|
|
1388
|
+
console.error(HELP_TEXT);
|
|
1389
|
+
process.exit(1);
|
|
1390
|
+
}
|
|
1391
|
+
const firstLower = positional[0].toLowerCase();
|
|
1392
|
+
const metadataMode = firstLower === 'metadata';
|
|
1393
|
+
if (metadataMode) {
|
|
1394
|
+
positional.shift();
|
|
1395
|
+
}
|
|
1396
|
+
// Wave A (#1218): if the first positional is a known type, treat it
|
|
1397
|
+
// as the type. If it's NOT a known type, fall through to single-name
|
|
1398
|
+
// mode — `aiwg show intake-wizard` works as long as the name is
|
|
1399
|
+
// unambiguous across artifact types. Multi-type matches still error
|
|
1400
|
+
// with the disambiguation list (existing behavior in showArtifact).
|
|
1401
|
+
let type = null;
|
|
1402
|
+
let name;
|
|
1403
|
+
if (metadataMode) {
|
|
1404
|
+
name = positional.join(' ').trim();
|
|
1405
|
+
if (!name) {
|
|
1406
|
+
console.error('Error: aiwg show metadata requires an id, name, or path');
|
|
1407
|
+
console.error(HELP_TEXT);
|
|
1408
|
+
process.exit(1);
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
else if (isOperationalShowType(firstLower)) {
|
|
1412
|
+
type = firstLower;
|
|
1413
|
+
name = positional.slice(1).join(' ').trim();
|
|
1414
|
+
if (!name) {
|
|
1415
|
+
console.error(`Error: aiwg show ${type} requires a name`);
|
|
1416
|
+
console.error(HELP_TEXT);
|
|
1417
|
+
process.exit(1);
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
else {
|
|
1421
|
+
// Single-name fallback. Pass to showArtifact without a type filter
|
|
1422
|
+
// so its existing ambiguity logic kicks in: unique match → succeed,
|
|
1423
|
+
// multiple matches → list candidates and exit 2 (or pick first
|
|
1424
|
+
// with `--first`).
|
|
1425
|
+
name = positional.join(' ').trim();
|
|
1426
|
+
}
|
|
1427
|
+
let json = false;
|
|
1428
|
+
let first = false;
|
|
1429
|
+
for (let i = 0; i < flags.length; i++) {
|
|
1430
|
+
if (flags[i] === '--json') {
|
|
1431
|
+
json = true;
|
|
1432
|
+
}
|
|
1433
|
+
else if (flags[i] === '--first') {
|
|
1434
|
+
first = true;
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
const graph = parseGraphFlag(flags);
|
|
1438
|
+
const backend = parseSearchBackendFlag(flags);
|
|
1439
|
+
const resourceSource = parseResourceSourceFlag(flags);
|
|
1440
|
+
const aiwgVersion = parseAiwgVersionFlag(flags);
|
|
1441
|
+
const offline = flags.includes('--offline');
|
|
1442
|
+
const webReleaseOptions = resourceSource === 'local'
|
|
1443
|
+
? undefined
|
|
1444
|
+
: webReleaseOptionsFromEnvironment();
|
|
1445
|
+
const params = {
|
|
1446
|
+
name,
|
|
1447
|
+
typeFilter: type ? [type] : undefined,
|
|
1448
|
+
json,
|
|
1449
|
+
first,
|
|
1450
|
+
graph,
|
|
1451
|
+
backend,
|
|
1452
|
+
resourceSource,
|
|
1453
|
+
aiwgVersion,
|
|
1454
|
+
offline,
|
|
1455
|
+
webReleaseOptions,
|
|
1456
|
+
};
|
|
1457
|
+
if (metadataMode)
|
|
1458
|
+
await showMetadata(cwd, params);
|
|
1459
|
+
else
|
|
1460
|
+
await showArtifact(cwd, params);
|
|
1461
|
+
}
|
|
1462
|
+
//# sourceMappingURL=cli.js.map
|