@aiwg/cli 2026.10.1 → 2026.10.4
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 +2 -2
- package/agentic/code/providers/capability-matrix.yaml +270 -0
- package/agentic/code/providers/model-capabilities.v1.json +3183 -24
- package/bin/aiwg.mjs +135 -47
- package/dist/src/a2a/codecs.js +9 -0
- package/dist/src/agents/grounding/knowledge-base.js +54 -6
- package/dist/src/artifacts/browser-export.js +6 -0
- package/dist/src/artifacts/checksum-manifest.js +1 -0
- package/dist/src/artifacts/citation-parser.js +173 -92
- package/dist/src/artifacts/citation-table-schema.js +59 -0
- package/dist/src/artifacts/cli.js +57 -18
- package/dist/src/artifacts/corpus-tools/snapshot.js +1 -1
- package/dist/src/artifacts/corpus-tools/vision-extract.js +107 -15
- package/dist/src/artifacts/corpus-views/ref-parser.js +3 -1
- package/dist/src/artifacts/corpus-views/renderers.js +3 -3
- package/dist/src/artifacts/discovery-eval.js +6 -4
- package/dist/src/artifacts/fortemi-core-query-adapter.js +36 -3
- package/dist/src/artifacts/fortemi-core-sync.js +166 -40
- package/dist/src/artifacts/framework-capabilities.js +171 -0
- package/dist/src/artifacts/framework-index-paths.js +73 -0
- package/dist/src/artifacts/framework-source-digest.js +75 -0
- package/dist/src/artifacts/index-builder.js +285 -131
- package/dist/src/artifacts/index-files.js +132 -18
- package/dist/src/artifacts/index-preparation.js +65 -0
- package/dist/src/artifacts/index-refresh.js +576 -0
- package/dist/src/artifacts/index-worker.mjs +9 -0
- package/dist/src/artifacts/prebuilt-build-lock.js +47 -4
- package/dist/src/artifacts/prebuilt-deployment.js +46 -0
- package/dist/src/artifacts/prebuilt-relations.js +80 -0
- package/dist/src/artifacts/query-engine.js +410 -88
- package/dist/src/artifacts/relations-builder.js +168 -0
- package/dist/src/artifacts/relations.js +148 -0
- package/dist/src/artifacts/repair.js +9 -4
- package/dist/src/artifacts/stats.js +5 -2
- package/dist/src/artifacts/types.js +30 -10
- package/dist/src/artifacts/watcher.js +1 -1
- package/dist/src/auth/credential-store.js +2 -1
- package/dist/src/catalog/cli.d.mts +5 -0
- package/dist/src/channel/manager.d.mts +20 -0
- package/dist/src/channel/manager.mjs +78 -12
- package/dist/src/cli/child-process-result.js +40 -0
- package/dist/src/cli/command-log.js +2 -3
- package/dist/src/cli/env.js +38 -16
- package/dist/src/cli/flag-parsing.js +236 -0
- package/dist/src/cli/handlers/artifacts.js +3 -0
- package/dist/src/cli/handlers/auth.js +3 -0
- package/dist/src/cli/handlers/decision.js +218 -5
- package/dist/src/cli/handlers/diagnose.js +13 -5
- package/dist/src/cli/handlers/effect.js +4 -2
- package/dist/src/cli/handlers/evidence.js +3 -0
- package/dist/src/cli/handlers/feedback.js +14 -5
- package/dist/src/cli/handlers/help.js +1 -0
- package/dist/src/cli/handlers/index.js +3 -1
- package/dist/src/cli/handlers/init.js +248 -30
- package/dist/src/cli/handlers/lint.js +5 -0
- package/dist/src/cli/handlers/mc.js +23 -0
- package/dist/src/cli/handlers/models.js +169 -10
- package/dist/src/cli/handlers/ralph-launcher.js +2 -0
- package/dist/src/cli/handlers/ralph.js +3 -0
- package/dist/src/cli/handlers/refresh.js +28 -0
- package/dist/src/cli/handlers/regenerate.js +14 -0
- package/dist/src/cli/handlers/resource-versions.js +3 -0
- package/dist/src/cli/handlers/rules.js +195 -0
- package/dist/src/cli/handlers/run.js +4 -0
- package/dist/src/cli/handlers/runtime-info.js +25 -11
- package/dist/src/cli/handlers/script-runner.js +19 -8
- package/dist/src/cli/handlers/session.js +406 -62
- package/dist/src/cli/handlers/sessions.js +243 -76
- package/dist/src/cli/handlers/setup-manifest.js +474 -79
- package/dist/src/cli/handlers/setup.js +180 -39
- package/dist/src/cli/handlers/steward.js +11 -0
- package/dist/src/cli/handlers/subcommands.js +60 -3
- package/dist/src/cli/handlers/team.js +18 -8
- package/dist/src/cli/handlers/uhp.js +3 -0
- package/dist/src/cli/handlers/use.js +307 -55
- package/dist/src/cli/handlers/utilities.js +125 -26
- package/dist/src/cli/handlers/version.js +8 -0
- package/dist/src/cli/prompt-utils.js +72 -0
- package/dist/src/cli/provider-resolution.js +11 -0
- package/dist/src/cli/router.js +15 -1
- package/dist/src/cli/services/deployment-verification.js +19 -9
- package/dist/src/cli/services/provider-prepare-coordinator.js +24 -0
- package/dist/src/cli/skill-usage.js +2 -3
- package/dist/src/config/aiwg-config.js +349 -35
- package/dist/src/config/cli.js +256 -23
- package/dist/src/config/decision-config.js +106 -0
- package/dist/src/config/dispatch-thresholds-runtime.d.mts +8 -0
- package/dist/src/config/dispatch-thresholds-runtime.mjs +38 -0
- package/dist/src/config/gitignore.js +50 -0
- package/dist/src/config/index-graph-overrides.js +36 -0
- package/dist/src/config/project-artifacts-health.d.mts +37 -0
- package/dist/src/config/project-artifacts-health.mjs +14 -3
- package/dist/src/config/project-artifacts-runtime.d.mts +16 -0
- package/dist/src/config/user-config-dir.d.mts +9 -0
- package/dist/src/config/user-config.js +38 -11
- package/dist/src/config/user-registry.js +23 -15
- package/dist/src/config/user-state.js +7 -0
- package/dist/src/decision/adapters/jev.js +75 -27
- package/dist/src/decision/ask.js +203 -43
- package/dist/src/decision/context-live-qualification.js +2 -2
- package/dist/src/decision/driver.js +14 -7
- package/dist/src/decision/ensemble/aggregate.js +23 -10
- package/dist/src/decision/ensemble-study/multifact-study.js +6 -2
- package/dist/src/decision/entry.js +25 -6
- package/dist/src/decision/graph-live-qualification.js +1 -1
- package/dist/src/decision/graph-run.js +9 -0
- package/dist/src/decision/heldout/collector.js +15 -14
- package/dist/src/decision/heldout/contract.js +30 -7
- package/dist/src/decision/index.js +1 -0
- package/dist/src/decision/interop.js +60 -8
- package/dist/src/decision/jev-credentials.js +15 -1
- package/dist/src/decision/ledger.js +942 -0
- package/dist/src/decision/offload-activation.js +137 -0
- package/dist/src/decision/offload.js +550 -0
- package/dist/src/decision/qualification/load.js +4 -6
- package/dist/src/decision/savings.js +28 -0
- package/dist/src/decision/validate.js +6 -3
- package/dist/src/effects/dispatch-verifier.js +252 -0
- package/dist/src/effects/index.js +1 -0
- package/dist/src/effects/types.js +5 -1
- package/dist/src/effects/verifiers/git.js +2 -1
- package/dist/src/effects/verifiers/tracker.js +26 -14
- package/dist/src/extensions/commands/definitions.js +19 -0
- package/dist/src/extensions/project-local-remove.js +36 -1
- package/dist/src/features/installer.js +2 -2
- package/dist/src/flow/graph-metadata.js +5 -0
- package/dist/src/gates/providers/loader.js +64 -18
- package/dist/src/installation/manager-command.d.mts +18 -0
- package/dist/src/installation/manager-command.mjs +15 -3
- package/dist/src/installation/manager.d.mts +49 -0
- package/dist/src/installation/manager.mjs +95 -5
- package/dist/src/issues/cli.js +4 -4
- package/dist/src/issues/local.js +24 -5
- package/dist/src/jobs/runner.js +1 -1
- package/dist/src/lint/cli.js +27 -1
- package/dist/src/lint/loader.js +2 -1
- package/dist/src/lint/reporters.js +25 -1
- package/dist/src/lint/rule-activation.js +43 -0
- package/dist/src/lint/runner.js +137 -62
- package/dist/src/mcp/adapters/codex-runtime.js +366 -56
- package/dist/src/mcp/claude-install.d.mts +4 -0
- package/dist/src/mcp/claude-install.mjs +41 -0
- package/dist/src/mcp/cli.d.mts +1 -0
- package/dist/src/mcp/cli.mjs +620 -85
- package/dist/src/mcp/config-file.d.mts +28 -0
- package/dist/src/mcp/config-file.mjs +279 -0
- package/dist/src/mcp/config-layers.d.mts +36 -0
- package/dist/src/mcp/config-layers.mjs +348 -0
- package/dist/src/mcp/credentials.d.mts +51 -0
- package/dist/src/mcp/credentials.mjs +484 -0
- package/dist/src/mcp/grok-build-config.d.mts +6 -0
- package/dist/src/mcp/grok-build-config.mjs +17 -27
- package/dist/src/mcp/helpers.mjs +109 -4
- package/dist/src/mcp/muse-native-config.d.mts +13 -0
- package/dist/src/mcp/muse-native-config.mjs +1 -0
- package/dist/src/mcp/omp-config.d.mts +4 -0
- package/dist/src/mcp/omp-config.mjs +50 -29
- package/dist/src/mcp/profiles.js +97 -23
- package/dist/src/mcp/profiles.mjs +99 -27
- package/dist/src/mcp/registry.js +248 -131
- package/dist/src/mcp/registry.mjs +169 -100
- package/dist/src/mcp/server-config.d.mts +3 -0
- package/dist/src/mcp/server-config.mjs +89 -0
- package/dist/src/mcp/server.mjs +127 -82
- package/dist/src/mcp/test-simple.mjs +2 -1
- package/dist/src/mcp/toml-editor.d.mts +4 -0
- package/dist/src/mcp/toml-string.d.mts +1 -0
- package/dist/src/mcp/toml-string.mjs +9 -0
- package/dist/src/mcp/toml-strip-mcp.d.mts +1 -0
- package/dist/src/mcp/toml-strip-mcp.mjs +135 -0
- package/dist/src/mcp/tool-filters.d.mts +46 -0
- package/dist/src/mcp/tool-filters.mjs +357 -0
- package/dist/src/mcp/tools/agentic-sandbox.mjs +3 -1
- package/dist/src/mcp/tools/decision.mjs +22 -3
- package/dist/src/mcp/tools/discovery.mjs +62 -55
- package/dist/src/mcp/tools/orchestration.mjs +50 -2
- package/dist/src/mcp/tools/subsystems.mjs +39 -8
- package/dist/src/mcp/tools/worker-invoke.mjs +2856 -0
- package/dist/src/mcp/tools/worker-shell-control.mjs +289 -0
- package/dist/src/mcp/tools/worker-stdin-runtime.mjs +79 -0
- package/dist/src/memory/project-registry.js +2 -2
- package/dist/src/mission-protocol/codecs.js +647 -1
- package/dist/src/mission-protocol/types.js +110 -0
- package/dist/src/mission-protocol/worker-status.js +2 -0
- package/dist/src/models/config-loader.js +76 -14
- package/dist/src/models/grok-build-models.js +93 -41
- package/dist/src/models/model-capabilities.v1.json +3183 -24
- package/dist/src/models/model-discovery.js +931 -67
- package/dist/src/models/provider-policy.js +719 -11
- package/dist/src/models/qualification-digest.d.mts +2 -0
- package/dist/src/models/qualification-digest.mjs +17 -0
- package/dist/src/models/resolver.js +261 -0
- package/dist/src/models/worker-direct-readiness.js +550 -0
- package/dist/src/models/worker-dispatch-offer.js +169 -0
- package/dist/src/models/worker-health-readiness.js +144 -0
- package/dist/src/models/worker-installation.d.mts +39 -0
- package/dist/src/models/worker-installation.mjs +986 -0
- package/dist/src/models/wrapper-route.js +18 -0
- package/dist/src/ops/registry.js +9 -14
- package/dist/src/plugins/standalone-packager.js +4 -3
- package/dist/src/process/bounded-child-process.d.mts +84 -0
- package/dist/src/process/bounded-child-process.mjs +430 -0
- package/dist/src/process/cli-command.d.mts +16 -0
- package/dist/src/process/cli-command.mjs +75 -0
- package/dist/src/process/signal-child.d.mts +6 -0
- package/dist/src/process/signal-child.mjs +7 -0
- package/dist/src/providers/capability-matrix.js +8 -0
- package/dist/src/providers/capability-matrix.yaml +270 -0
- package/dist/src/providers/deployed-skill-roots.js +20 -0
- package/dist/src/providers/grok-build-acp.js +3 -2
- package/dist/src/providers/grok-build-headless.js +53 -23
- package/dist/src/providers/grok-build-inspect.js +1 -0
- package/dist/src/providers/omp-agent.d.mts +8 -0
- package/dist/src/providers/omp-diagnostics.d.mts +1 -0
- package/dist/src/providers/omp-paths.d.mts +13 -0
- package/dist/src/providers/provider-definitions.js +9 -1
- package/dist/src/providers/provider-definitions.mjs +9 -2
- package/dist/src/providers/skill-ownership.d.mts +9 -0
- package/dist/src/providers/skill-ownership.mjs +88 -0
- package/dist/src/rules/activation.d.mts +21 -0
- package/dist/src/rules/activation.mjs +62 -0
- package/dist/src/rules/inline-budget.d.mts +26 -0
- package/dist/src/rules/inline-budget.mjs +66 -0
- package/dist/src/rules/inventory.js +129 -0
- package/dist/src/rules/pin-state.js +73 -0
- package/dist/src/rules/pins.d.mts +14 -0
- package/dist/src/rules/pins.mjs +112 -0
- package/dist/src/rules/rule-frontmatter.schema.json +197 -0
- package/dist/src/serve/executor-registry.js +16 -24
- package/dist/src/serve/fleet-mission-conductor.js +9 -0
- package/dist/src/serve/mission-conductor.js +47 -12
- package/dist/src/serve/shared-host-scheduler.js +2 -0
- package/dist/src/serve/worker-invocation.js +558 -0
- package/dist/src/serve/worker-stdin-frame.d.mts +10 -0
- package/dist/src/serve/worker-stdin-frame.mjs +107 -0
- package/dist/src/sessions/adapter-registry.js +49 -0
- package/dist/src/sessions/adapters/claude.js +39 -54
- package/dist/src/sessions/adapters/codex.js +82 -67
- package/dist/src/sessions/adapters/copilot.js +4 -4
- package/dist/src/sessions/adapters/cursor.js +40 -57
- package/dist/src/sessions/adapters/deepseek-harness.js +15 -12
- package/dist/src/sessions/adapters/factory.js +31 -27
- package/dist/src/sessions/adapters/generic.js +43 -9
- package/dist/src/sessions/adapters/grok-build.js +11 -11
- package/dist/src/sessions/adapters/grokbot-locator.js +111 -0
- package/dist/src/sessions/adapters/grokbot.js +434 -24
- package/dist/src/sessions/adapters/hermes.js +27 -29
- package/dist/src/sessions/adapters/muse-workspace-scan.js +128 -0
- package/dist/src/sessions/adapters/muse.js +200 -104
- package/dist/src/sessions/adapters/omp.js +28 -14
- package/dist/src/sessions/adapters/openclaw.js +89 -79
- package/dist/src/sessions/adapters/opencode.js +27 -24
- package/dist/src/sessions/adapters/openhuman.js +18 -60
- package/dist/src/sessions/adapters/pi.js +30 -14
- package/dist/src/sessions/adapters/warp.js +3 -3
- package/dist/src/sessions/adapters/windsurf.js +19 -48
- package/dist/src/sessions/batch-contracts.js +25 -5
- package/dist/src/sessions/batch-import.js +72 -51
- package/dist/src/sessions/candidates.js +47 -11
- package/dist/src/sessions/contracts.js +75 -2
- package/dist/src/sessions/coverage-preflight.js +134 -0
- package/dist/src/sessions/discovery.js +3 -0
- package/dist/src/sessions/export-plan.js +4 -3
- package/dist/src/sessions/grok-build-cli.js +67 -5
- package/dist/src/sessions/import-exclusions.js +72 -0
- package/dist/src/sessions/import-lease.js +34 -18
- package/dist/src/sessions/import-limits.js +37 -0
- package/dist/src/sessions/importer.js +84 -46
- package/dist/src/sessions/index.js +2 -0
- package/dist/src/sessions/lifecycle.js +45 -0
- package/dist/src/sessions/policy.js +133 -25
- package/dist/src/sessions/readers.js +106 -53
- package/dist/src/sessions/refresh.js +106 -0
- package/dist/src/sessions/repository.js +199 -63
- package/dist/src/sessions/workspace-discovery.js +315 -88
- package/dist/src/sessions/workspace-matching.js +107 -0
- package/dist/src/skills/adapters/clawhub.js +10 -8
- package/dist/src/skills/adapters/openclaw.js +10 -7
- package/dist/src/skills/importer.js +1 -0
- package/dist/src/smiths/context-pipeline/aiwg-md.js +11 -0
- package/dist/src/smiths/context-pipeline/claude-hook.js +3 -26
- package/dist/src/smiths/context-pipeline/finalization.js +6 -5
- package/dist/src/smiths/context-pipeline/generator.js +21 -4
- package/dist/src/smiths/context-pipeline/parallelism-section.js +195 -14
- package/dist/src/smiths/context-pipeline/workspace-context.js +116 -9
- package/dist/src/smiths/hook-bridge/codex-translator.js +6 -5
- package/dist/src/smiths/mcpsmith/example.js +1 -1
- package/dist/src/smiths/mcpsmith/generator.js +1 -1
- package/dist/src/smiths/toolsmith/runtime-discovery.d.mts +10 -0
- package/dist/src/smiths/toolsmith/runtime-discovery.mjs +85 -31
- package/dist/src/storage/backends/fs.js +18 -76
- package/dist/src/storage/backends/logseq.js +68 -7
- package/dist/src/storage/backends/obsidian.js +1 -0
- package/dist/src/storage/fortemi-qualification-receipt.js +2 -2
- package/dist/src/testing/generators/test-code-generator.js +57 -30
- package/dist/src/tracker/forge-http.js +2 -1
- package/dist/src/uhp/client.js +11 -1
- package/dist/src/uhp/mission.js +5 -0
- package/dist/src/update/checker.d.mts +2 -0
- package/dist/src/update/checker.mjs +5 -5
- package/dist/src/update/notifier.mjs +54 -2
- package/dist/src/update/service.d.mts +22 -0
- package/dist/src/utils/contained-filesystem.d.mts +37 -0
- package/dist/src/utils/contained-filesystem.mjs +683 -0
- package/dist/src/utils/temporary-directory.js +36 -0
- package/dist/src/writing/example-generator.js +1 -1
- package/dist/src/writing/fidelity.js +18 -1
- package/package.json +32 -2
- package/schemas/mission-v1.schema.json +2429 -0
- package/schemas/models/model-catalog.v1.schema.json +301 -0
- package/schemas/models/model-config-compatibility.v1.schema.json +281 -0
- package/schemas/models/model-policy.v1.schema.json +14 -0
- package/schemas/models/provider-model-capabilities.v1.schema.json +1072 -0
- package/tools/_resolve-impl.mjs +39 -2
- package/tools/agents/deploy-agents.mjs +64 -23
- package/tools/agents/providers/base.mjs +153 -166
- package/tools/agents/providers/claude.mjs +8 -24
- package/tools/agents/providers/codex.mjs +18 -11
- package/tools/agents/providers/cursor.mjs +19 -18
- package/tools/agents/providers/grok-build.mjs +3 -1
- package/tools/agents/providers/grokbot.mjs +11 -12
- package/tools/agents/providers/hermes.mjs +62 -49
- package/tools/agents/providers/omp.mjs +5 -2
- package/tools/agents/providers/openclaw-translator.mjs +19 -5
- package/tools/agents/providers/openclaw.mjs +9 -4
- package/tools/agents/providers/pi.mjs +5 -0
- package/tools/agents/providers/provider-prepare-channel.mjs +5 -0
- package/tools/agents/providers/provider-prepare-coordinator.mjs +247 -0
- package/tools/agents/providers/provider-prepare-worker.mjs +84 -0
- package/tools/agents/providers/rule-delivery.mjs +1270 -0
- package/tools/agents/providers/warp.mjs +20 -26
- package/tools/cli/decision-offload-report.mjs +40 -0
- package/tools/cli/workspace-status.mjs +862 -0
- package/tools/plugin/package-plugins.mjs +186 -8
- package/tools/plugin/plugin-links.mjs +114 -0
- package/tools/providers/antigravity-transport.mjs +3 -1
- package/tools/providers/deepseek-harness-transport.mjs +360 -0
- package/tools/providers/omp-transport.mjs +194 -0
- package/tools/ralph-external/lib/claude-adapter.mjs +389 -0
- package/tools/ralph-external/lib/codex-adapter.mjs +432 -0
- package/tools/ralph-external/lib/consecutive-failure-circuit-breaker.mjs +1748 -0
- package/tools/ralph-external/lib/deepseek-harness-adapter.mjs +397 -0
- package/tools/ralph-external/lib/factory-adapter.mjs +503 -0
- package/tools/ralph-external/lib/launcher-recovery-evidence.mjs +55 -0
- package/tools/ralph-external/lib/muse-adapter.mjs +364 -0
- package/tools/ralph-external/lib/omp-adapter.mjs +315 -0
- package/tools/ralph-external/lib/opencode-adapter.mjs +575 -0
- package/tools/ralph-external/lib/openhuman-adapter.mjs +75 -0
- package/tools/ralph-external/lib/pi-adapter.mjs +329 -0
- package/tools/ralph-external/lib/provider-adapter.mjs +748 -0
- package/tools/ralph-external/lib/recovery-probe.mjs +72 -0
- package/tools/ralph-external/lib/session-environment.mjs +28 -0
- package/tools/ralph-external/lib/systemd-client.mjs +49 -0
- package/tools/ralph-external/lib/worker-health.mjs +439 -0
- package/tools/ralph-external/lib/worker-isolation.mjs +717 -0
- package/tools/ralph-external/lib/worker-overflow.mjs +50 -0
- package/tools/ralph-external/process-monitor.mjs +1017 -0
- package/tools/ralph-external/session-launcher.mjs +5057 -0
- package/tools/scripts/resource-preflight.mjs +541 -0
- package/tools/skills/deploy-skills-codex.mjs +2 -1
- package/vscode-extension/schemas/aiwg.config.v1.json +2916 -0
|
@@ -16,13 +16,15 @@ import { load as loadYaml } from 'js-yaml';
|
|
|
16
16
|
import { validateDecisionDocument } from '../decision/validate.js';
|
|
17
17
|
import { parseDecisionJson, parseDecisionYaml } from '../decision/entry.js';
|
|
18
18
|
import { validateGateDocument } from '../gates/schema.js';
|
|
19
|
-
import {
|
|
19
|
+
import { INDEX_EXTRACTOR_VERSION, INDEX_VERSION, INDEX_DIR, OPERATIONAL_DISCOVERY_TYPES, PHASE_DIRECTORIES, GRAPH_CONFIGS, TEMPLATE_INDEX_EXTENSIONS, resolveGraphScanDir, loadUserGraphConfigs, loadGlobalGraphConfigs, resolveGraphBackendType, } from './types.js';
|
|
20
20
|
import { parseCitationSidecar, citationResultToEdges, buildRefToPathMap } from './citation-parser.js';
|
|
21
21
|
import { writeIndexFile, resolveIndexDir, loadGraphIndexFile } from './index-reader.js';
|
|
22
22
|
import { loadManifest, writeManifest, statMatches, makeEntry } from './checksum-manifest.js';
|
|
23
|
+
import { FRAMEWORK_RELATIONS_REVISION } from './framework-source-digest.js';
|
|
23
24
|
import { normalizeOperationalState } from './operational-state.js';
|
|
24
25
|
import { DEFAULT_PROJECT_AIWG_DIR, resolveProjectAiwgDir, } from '../config/project-artifacts.js';
|
|
25
26
|
import { normalizeStateTransferProjection } from './state-transfer.js';
|
|
27
|
+
import { runIndexPreparation } from './index-preparation.js';
|
|
26
28
|
import { collectGraphIndexFiles, findArtifactFiles, indexPathFor } from './index-files.js';
|
|
27
29
|
function absoluteEntryPath(cwd, entryPath, graph) {
|
|
28
30
|
if ((!graph || graph === 'project') && entryPath.startsWith(`${DEFAULT_PROJECT_AIWG_DIR}/`)) {
|
|
@@ -56,6 +58,30 @@ export function parseFrontmatter(content) {
|
|
|
56
58
|
return { data: {}, body: content };
|
|
57
59
|
}
|
|
58
60
|
}
|
|
61
|
+
/** Read the target rule schema tolerantly while older rules remain untagged. */
|
|
62
|
+
export function extractRuleBindings(data, body = '') {
|
|
63
|
+
const bound_to = {};
|
|
64
|
+
const raw = data.bound_to;
|
|
65
|
+
if (raw && typeof raw === 'object' && !Array.isArray(raw)) {
|
|
66
|
+
for (const key of ['skills', 'agents', 'flows']) {
|
|
67
|
+
const targets = raw[key];
|
|
68
|
+
if (Array.isArray(targets)) {
|
|
69
|
+
const names = [...new Set(targets.filter((name) => typeof name === 'string' && name.trim().length > 0))];
|
|
70
|
+
if (names.length)
|
|
71
|
+
bound_to[key] = names;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const enforcement = typeof data.enforcement === 'string' ? data.enforcement
|
|
76
|
+
: body.match(/^\*\*Enforcement Level\*\*:\s*([A-Za-z]+)/m)?.[1];
|
|
77
|
+
return {
|
|
78
|
+
...(enforcement ? { ruleEnforcement: enforcement.trim().toLowerCase() } : {}),
|
|
79
|
+
...(Array.isArray(data.paths) ? { rulePaths: data.paths.filter((value) => typeof value === 'string') } : {}),
|
|
80
|
+
...(typeof data.activation === 'string' ? { activation: data.activation } : {}),
|
|
81
|
+
...(typeof data.summary === 'string' ? { ruleSummary: data.summary } : {}),
|
|
82
|
+
...(Object.keys(bound_to).length ? { bound_to } : {}),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
59
85
|
/**
|
|
60
86
|
* Extract @-mention references from content
|
|
61
87
|
*/
|
|
@@ -810,29 +836,99 @@ function resolveInstallRootHint() {
|
|
|
810
836
|
catch { /* fall through */ }
|
|
811
837
|
return '<aiwg install root>';
|
|
812
838
|
}
|
|
839
|
+
/** Shared serial/worker read, checksum and extraction. No index output or global reduction. */
|
|
840
|
+
export function prepareIndexArtifact(job) {
|
|
841
|
+
const { fullPath, relativePath } = job;
|
|
842
|
+
const content = fs.readFileSync(fullPath, 'utf8');
|
|
843
|
+
const checksum = computeChecksum(content);
|
|
844
|
+
if (job.existingChecksum === checksum)
|
|
845
|
+
return { checksum };
|
|
846
|
+
const { data, body } = parseFrontmatter(content);
|
|
847
|
+
// YAML Flow documents (workflow.aiwg.io/v1) are pure YAML, not
|
|
848
|
+
// markdown+frontmatter — detect them up front so they classify and
|
|
849
|
+
// become discoverable (#1540).
|
|
850
|
+
const flow = parseFlowDoc(content, relativePath);
|
|
851
|
+
const decision = flow ? null : parseDecisionDoc(content, relativePath);
|
|
852
|
+
const gatePack = flow || decision ? null : parseGatePackDoc(content, relativePath);
|
|
853
|
+
const inferredType = inferType(data, relativePath);
|
|
854
|
+
const physicalType = inferType({ ...data, type: undefined }, relativePath);
|
|
855
|
+
const runbook = flow || decision || gatePack ? null : parseRunbookDoc(data, body, relativePath);
|
|
856
|
+
const schemaDoc = inferredType === 'schema' ? parseSchemaDoc(content, relativePath) : null;
|
|
857
|
+
const title = flow?.name ?? decision?.name ?? gatePack?.name ?? schemaDoc?.title ?? extractTitle(data, body);
|
|
858
|
+
const phase = typeof data.phase === 'string' ? data.phase : inferPhase(relativePath);
|
|
859
|
+
const type = flow?.type ?? decision?.type ?? gatePack?.type ?? (runbook ? 'runbook' : inferredType);
|
|
860
|
+
const tags = flow?.tags ?? decision?.tags ?? gatePack?.tags ?? (Array.isArray(data.tags) ? data.tags.map(String) : []);
|
|
861
|
+
const summary = flow?.description ?? decision?.description ?? gatePack?.description ?? schemaDoc?.capability ?? runbook?.capability ?? extractSummary(data, body);
|
|
862
|
+
const dependencies = extractMentions(content);
|
|
863
|
+
const markdownLinks = extractMarkdownLinks(content);
|
|
864
|
+
// Discovery metadata (#1214, #1540, #1792) — meaningful for operational
|
|
865
|
+
// AIWG artifact kinds. Kept undefined on document types so the index file
|
|
866
|
+
// stays small for the common case.
|
|
867
|
+
const isDiscoverable = OPERATIONAL_DISCOVERY_TYPES.includes(type);
|
|
868
|
+
// Declarative processes have no trigger phrases — they rely on their
|
|
869
|
+
// capability and structure-aware search terms.
|
|
870
|
+
const triggers = isDiscoverable && !flow ? extractTriggers(body, data) : undefined;
|
|
871
|
+
const capability = flow?.capability ?? decision?.capability ?? gatePack?.capability ?? schemaDoc?.capability ?? runbook?.capability ?? (isDiscoverable ? extractCapability(data, body) : undefined);
|
|
872
|
+
const kind = flow?.kind ?? decision?.kind ?? gatePack?.kind ?? runbook?.kind;
|
|
873
|
+
const sourceType = runbook && physicalType !== 'runbook' ? physicalType : undefined;
|
|
874
|
+
const searchTerms = flow?.searchTerms ?? decision?.searchTerms ?? gatePack?.searchTerms ?? schemaDoc?.searchTerms ?? runbook?.searchTerms;
|
|
875
|
+
const kernel = data.kernel === true || data.kernel === 'true' ? true : undefined;
|
|
876
|
+
// Script entrypoint metadata is meaningful for skills only (#1227).
|
|
877
|
+
const script = type === 'skill' ? extractSkillScript(data) : undefined;
|
|
878
|
+
const operationalState = normalizeOperationalState(data.operational_state);
|
|
879
|
+
const stateTransfer = normalizeStateTransferProjection(data.state_transfer);
|
|
880
|
+
// Canonical short name (#1233) — used by the scorer to floor exact-name
|
|
881
|
+
// queries to 1.0 so hyphenated kernel-skill names like `aiwg-doctor`
|
|
882
|
+
// remain searchable even when the rendered title strips the hyphen.
|
|
883
|
+
const name = flow?.name ?? decision?.name ?? gatePack?.name ?? schemaDoc?.name ?? (isDiscoverable ? extractCanonicalName(data, relativePath) : undefined);
|
|
884
|
+
const entry = {
|
|
885
|
+
path: relativePath,
|
|
886
|
+
type,
|
|
887
|
+
...(kind ? { kind } : {}),
|
|
888
|
+
...(sourceType ? { sourceType } : {}),
|
|
889
|
+
phase,
|
|
890
|
+
title,
|
|
891
|
+
tags,
|
|
892
|
+
created: typeof data.created === 'string' ? data.created : new Date(job.birthtimeMs).toISOString(),
|
|
893
|
+
updated: new Date(job.mtimeMs).toISOString(),
|
|
894
|
+
checksum,
|
|
895
|
+
summary,
|
|
896
|
+
dependencies,
|
|
897
|
+
...(markdownLinks.length > 0 ? { markdownLinks } : {}),
|
|
898
|
+
dependents: [], // Computed after all entries are processed
|
|
899
|
+
...(name ? { name } : {}),
|
|
900
|
+
...(triggers && triggers.length > 0 ? { triggers } : {}),
|
|
901
|
+
...(capability ? { capability } : {}),
|
|
902
|
+
...(searchTerms && searchTerms.length > 0 ? { searchTerms } : {}),
|
|
903
|
+
...(kernel ? { kernel } : {}),
|
|
904
|
+
...(script ? { script } : {}),
|
|
905
|
+
...(type === 'rule' || type === 'behavior' ? extractRuleBindings(data, body) :
|
|
906
|
+
Array.isArray(data.paths) ? { governedPaths: data.paths.filter((value) => typeof value === 'string') } : {}),
|
|
907
|
+
...(operationalState ? { operationalState } : {}),
|
|
908
|
+
...(stateTransfer ? { stateTransfer } : {}),
|
|
909
|
+
};
|
|
910
|
+
return { checksum, entry };
|
|
911
|
+
}
|
|
813
912
|
export async function buildIndex(cwd, options = {}) {
|
|
814
|
-
const { force = false, verbose = false, scope, outputDir, graph, explicit = true } = options;
|
|
913
|
+
const { force = false, verbose = false, scope, includeIgnored = false, outputDir, graph, explicit = true } = options;
|
|
815
914
|
const startTime = Date.now();
|
|
915
|
+
const log = options.quiet ? (..._args) => { } : console.log;
|
|
816
916
|
// Ensure user-defined graphs are loaded
|
|
817
917
|
loadUserGraphConfigs(cwd);
|
|
818
918
|
loadGlobalGraphConfigs();
|
|
819
919
|
// Determine scan directories based on graph type
|
|
820
920
|
const graphConfig = graph ? GRAPH_CONFIGS[graph] : undefined;
|
|
821
921
|
let scanDirs;
|
|
822
|
-
let fileExtensions;
|
|
823
922
|
if (scope) {
|
|
824
923
|
// Explicit scope overrides graph config
|
|
825
924
|
scanDirs = [path.join(cwd, scope)];
|
|
826
|
-
fileExtensions = [...DEFAULT_INDEX_EXTENSIONS];
|
|
827
925
|
}
|
|
828
926
|
else if (graphConfig) {
|
|
829
927
|
scanDirs = graphConfig.scanDirs.map(d => resolveGraphScanDir(cwd, d));
|
|
830
|
-
fileExtensions = graphConfig.extensions;
|
|
831
928
|
}
|
|
832
929
|
else {
|
|
833
930
|
// Default: scan .aiwg/ (backward compatible)
|
|
834
931
|
scanDirs = [resolveProjectAiwgDir(cwd)];
|
|
835
|
-
fileExtensions = [...DEFAULT_INDEX_EXTENSIONS];
|
|
836
932
|
}
|
|
837
933
|
// Verify at least one scan directory exists
|
|
838
934
|
const existingDirs = scanDirs.filter(d => fs.existsSync(d));
|
|
@@ -851,16 +947,16 @@ export async function buildIndex(cwd, options = {}) {
|
|
|
851
947
|
// required directories" sends the operator looking in the wrong place (#2530).
|
|
852
948
|
if (graph === 'framework') {
|
|
853
949
|
const installRoot = resolveInstallRootHint();
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
950
|
+
log('The framework graph indexes the AIWG corpus and can only be built at the');
|
|
951
|
+
log('install root, not in a consumer project. Build it there, then sync here:');
|
|
952
|
+
log('');
|
|
953
|
+
log(` cd ${installRoot} && aiwg index build --graph framework --force`);
|
|
954
|
+
log(` cd ${cwd} && aiwg index sync --backend fortemi-core --graph framework`);
|
|
955
|
+
log('');
|
|
956
|
+
log("As an immediate workaround, discovery also works with '--backend local'.");
|
|
861
957
|
}
|
|
862
958
|
else {
|
|
863
|
-
|
|
959
|
+
log('Run this command from a project with the required directories.');
|
|
864
960
|
}
|
|
865
961
|
process.exit(1);
|
|
866
962
|
}
|
|
@@ -890,24 +986,21 @@ export async function buildIndex(cwd, options = {}) {
|
|
|
890
986
|
verbose,
|
|
891
987
|
});
|
|
892
988
|
const buildTimeMs = Date.now() - startTime;
|
|
893
|
-
|
|
894
|
-
|
|
989
|
+
log(`Source graph built in ${buildTimeMs}ms`);
|
|
990
|
+
log(` Output: ${INDEX_DIR}/source/`);
|
|
895
991
|
return;
|
|
896
992
|
}
|
|
897
993
|
// Load existing index for incremental updates
|
|
898
|
-
const
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
const canReuseExisting = existingIndex?.version === INDEX_VERSION
|
|
904
|
-
&& existingIndex.extractorVersion === INDEX_EXTRACTOR_VERSION;
|
|
905
|
-
const existingEntries = canReuseExisting ? existingIndex.entries : {};
|
|
906
|
-
// Load checksum manifest for fast stat-based change detection (#794).
|
|
907
|
-
// When --force is set we skip the manifest entirely and rebuild everything.
|
|
908
|
-
const manifest = force || !canReuseExisting
|
|
994
|
+
const backendType = resolveGraphBackendType(graph);
|
|
995
|
+
const buildConfigHash = createHash('sha256')
|
|
996
|
+
.update(JSON.stringify({ graphConfig, backendType }))
|
|
997
|
+
.digest('hex');
|
|
998
|
+
const storedManifest = force
|
|
909
999
|
? { version: 1, generated: '', entries: {} }
|
|
910
1000
|
: loadManifest(indexOutputDir);
|
|
1001
|
+
const useFilenameMetadata = graphConfig?.nodeStrategy === 'filename-metadata';
|
|
1002
|
+
const reusable = !useFilenameMetadata && !graphConfig?.metadataSupplements?.length && !graphConfig?.edgeExtraction;
|
|
1003
|
+
const fileStats = !force && reusable ? new Map() : undefined;
|
|
911
1004
|
const nextManifestEntries = {};
|
|
912
1005
|
const manifestStats = {
|
|
913
1006
|
checked: 0,
|
|
@@ -917,16 +1010,117 @@ export async function buildIndex(cwd, options = {}) {
|
|
|
917
1010
|
pruned: 0,
|
|
918
1011
|
};
|
|
919
1012
|
// Collect files from all scan directories
|
|
920
|
-
const files = scope
|
|
921
|
-
? existingDirs.flatMap(dir => findArtifactFiles(dir, fileExtensions))
|
|
922
|
-
: await collectGraphIndexFiles(cwd, graph);
|
|
1013
|
+
const files = await collectGraphIndexFiles(cwd, graph, { scope, includeIgnored, fileStats });
|
|
923
1014
|
const entries = {};
|
|
924
1015
|
const tagIndex = {};
|
|
925
1016
|
const depGraph = {};
|
|
926
1017
|
let newCount = 0;
|
|
927
1018
|
let updatedCount = 0;
|
|
928
1019
|
let unchangedCount = 0;
|
|
929
|
-
const
|
|
1020
|
+
const reportBuild = (buildTimeMs, total) => {
|
|
1021
|
+
log(`Artifact index built in ${buildTimeMs}ms`);
|
|
1022
|
+
log(` Indexed ${newCount} new, updated ${updatedCount}, unchanged ${unchangedCount}`);
|
|
1023
|
+
log(` Total: ${total} artifacts`);
|
|
1024
|
+
if (!force && manifestStats.checked > 0) {
|
|
1025
|
+
const fastPath = manifestStats.statSkipped;
|
|
1026
|
+
const slowPath = manifestStats.checked - manifestStats.statSkipped;
|
|
1027
|
+
log(` Change detection: ${manifestStats.checked} checked, ${fastPath} skipped via stat, ${slowPath} content-read, ${manifestStats.reindexed} re-indexed`);
|
|
1028
|
+
if (manifestStats.pruned > 0) {
|
|
1029
|
+
log(` Pruned ${manifestStats.pruned} stale manifest entries (files no longer on disk)`);
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
const displayDir = graph ? indexOutputDir : `${INDEX_DIR}/`;
|
|
1033
|
+
log(` Output: ${displayDir}`);
|
|
1034
|
+
};
|
|
1035
|
+
const requiredFiles = ['tags.json', 'dependencies.json'];
|
|
1036
|
+
if (backendType === 'sqlite')
|
|
1037
|
+
requiredFiles.push('graph.db');
|
|
1038
|
+
const fileSignature = (filename) => {
|
|
1039
|
+
try {
|
|
1040
|
+
const stat = fs.statSync(path.join(indexOutputDir, filename), { bigint: true });
|
|
1041
|
+
return [stat.dev, stat.ino, stat.size, stat.mtimeNs, stat.ctimeNs].join(':');
|
|
1042
|
+
}
|
|
1043
|
+
catch {
|
|
1044
|
+
return '';
|
|
1045
|
+
}
|
|
1046
|
+
};
|
|
1047
|
+
const relationsReceiptMatches = () => {
|
|
1048
|
+
const projection = storedManifest.receipt?.relations;
|
|
1049
|
+
return graph !== 'framework' || Boolean(projection?.revision === FRAMEWORK_RELATIONS_REVISION
|
|
1050
|
+
&& projection.signature && projection.signature === fileSignature('relations.json'));
|
|
1051
|
+
};
|
|
1052
|
+
const entriesDigest = (values) => createHash('sha256').update(JSON.stringify(values)).digest('hex');
|
|
1053
|
+
const writeBuildManifest = (values) => {
|
|
1054
|
+
writeManifest(indexOutputDir, { version: 1, generated: new Date().toISOString(), entries: values,
|
|
1055
|
+
...(reusable ? { receipt: {
|
|
1056
|
+
indexVersion: INDEX_VERSION, extractorVersion: INDEX_EXTRACTOR_VERSION, buildConfigHash,
|
|
1057
|
+
sourceRoot: path.resolve(cwd), metadataSignature: fileSignature('metadata.json'), entriesDigest: entriesDigest(values),
|
|
1058
|
+
...(graph === 'framework' ? { relations: { revision: FRAMEWORK_RELATIONS_REVISION, signature: fileSignature('relations.json') } } : {}),
|
|
1059
|
+
} } : {}),
|
|
1060
|
+
});
|
|
1061
|
+
};
|
|
1062
|
+
// A successful receipt proves the manifest belongs to this exact metadata
|
|
1063
|
+
// file. Still enumerate/stat every source and verify the complete file set;
|
|
1064
|
+
// unchanged builds need not parse the much larger metadata/dependency data.
|
|
1065
|
+
const receipt = storedManifest.receipt;
|
|
1066
|
+
if (!force && reusable && storedManifest.generated && receipt
|
|
1067
|
+
&& receipt.indexVersion === INDEX_VERSION && receipt.extractorVersion === INDEX_EXTRACTOR_VERSION
|
|
1068
|
+
&& receipt.buildConfigHash === buildConfigHash && receipt.sourceRoot === path.resolve(cwd)
|
|
1069
|
+
&& receipt.metadataSignature && receipt.metadataSignature === fileSignature('metadata.json')
|
|
1070
|
+
&& relationsReceiptMatches()
|
|
1071
|
+
&& receipt.entriesDigest === entriesDigest(storedManifest.entries)
|
|
1072
|
+
&& files.length === Object.keys(storedManifest.entries).length
|
|
1073
|
+
&& requiredFiles.every(filename => fs.existsSync(path.join(indexOutputDir, filename)))) {
|
|
1074
|
+
const stats = loadIndexFromDir(indexOutputDir, 'stats.json');
|
|
1075
|
+
if (stats?.version === INDEX_VERSION && stats.extractorVersion === INDEX_EXTRACTOR_VERSION
|
|
1076
|
+
&& stats.totalArtifacts === files.length && files.every(file => {
|
|
1077
|
+
try {
|
|
1078
|
+
return statMatches(fileStats?.get(file) ?? fs.statSync(file), storedManifest.entries[indexPathFor(cwd, file, graph)]);
|
|
1079
|
+
}
|
|
1080
|
+
catch {
|
|
1081
|
+
return false;
|
|
1082
|
+
}
|
|
1083
|
+
})) {
|
|
1084
|
+
unchangedCount = files.length;
|
|
1085
|
+
manifestStats.checked = files.length;
|
|
1086
|
+
manifestStats.statSkipped = files.length;
|
|
1087
|
+
const buildTimeMs = Date.now() - startTime;
|
|
1088
|
+
writeIndexFile(effectiveOutputCwd, 'stats.json', { ...stats, builtAt: new Date().toISOString(), buildTimeMs }, indexOutputDir);
|
|
1089
|
+
reportBuild(buildTimeMs, files.length);
|
|
1090
|
+
return;
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
const existingIndex = force ? null : outputDir
|
|
1094
|
+
? loadIndexFromDir(indexOutputDir, 'metadata.json')
|
|
1095
|
+
: loadGraphIndexFile(effectiveOutputCwd, 'metadata.json', graph);
|
|
1096
|
+
const canReuseExisting = existingIndex?.version === INDEX_VERSION
|
|
1097
|
+
&& existingIndex.extractorVersion === INDEX_EXTRACTOR_VERSION && existingIndex.buildConfigHash === buildConfigHash;
|
|
1098
|
+
const existingEntries = canReuseExisting ? existingIndex.entries : {};
|
|
1099
|
+
const manifest = canReuseExisting ? storedManifest : { version: 1, generated: '', entries: {} };
|
|
1100
|
+
// Establish the complete changed-file batch before any extraction/reduction.
|
|
1101
|
+
// Warm stat hits never create threads or read source contents.
|
|
1102
|
+
const preparationStats = new Map();
|
|
1103
|
+
const jobs = [];
|
|
1104
|
+
if (!useFilenameMetadata)
|
|
1105
|
+
for (const fullPath of files) {
|
|
1106
|
+
let stat;
|
|
1107
|
+
try {
|
|
1108
|
+
stat = fileStats?.get(fullPath) ?? fs.statSync(fullPath);
|
|
1109
|
+
}
|
|
1110
|
+
catch (error) {
|
|
1111
|
+
if (error.code === 'ENOENT')
|
|
1112
|
+
continue;
|
|
1113
|
+
throw error;
|
|
1114
|
+
}
|
|
1115
|
+
preparationStats.set(fullPath, stat);
|
|
1116
|
+
const relativePath = indexPathFor(cwd, fullPath, graph), previous = manifest.entries[relativePath];
|
|
1117
|
+
if (!force && statMatches(stat, previous) && existingEntries[relativePath]?.checksum === previous?.checksum)
|
|
1118
|
+
continue;
|
|
1119
|
+
jobs.push({ fullPath, relativePath, mtimeMs: stat.mtimeMs, birthtimeMs: stat.birthtimeMs, sizeBytes: stat.size,
|
|
1120
|
+
...(!force && existingEntries[relativePath] ? { existingChecksum: existingEntries[relativePath].checksum } : {}) });
|
|
1121
|
+
}
|
|
1122
|
+
const preparation = await runIndexPreparation(jobs, prepareIndexArtifact, import.meta.url, options.workers);
|
|
1123
|
+
const preparedArtifacts = new Map(jobs.map((job, index) => [job.fullPath, preparation.results[index]]));
|
|
930
1124
|
for (const fullPath of files) {
|
|
931
1125
|
const relativePath = indexPathFor(cwd, fullPath, graph);
|
|
932
1126
|
let entry;
|
|
@@ -944,7 +1138,7 @@ export async function buildIndex(cwd, options = {}) {
|
|
|
944
1138
|
entries[relativePath] = existingEntries[relativePath];
|
|
945
1139
|
unchangedCount++;
|
|
946
1140
|
if (verbose)
|
|
947
|
-
|
|
1141
|
+
log(` unchanged: ${relativePath}`);
|
|
948
1142
|
continue;
|
|
949
1143
|
}
|
|
950
1144
|
entry = buildFilenameMetadataEntry(relativePath, fullPath, graphConfig?.filenamePattern);
|
|
@@ -956,13 +1150,13 @@ export async function buildIndex(cwd, options = {}) {
|
|
|
956
1150
|
// This is the fast path: unchanged files don't touch the filesystem beyond fs.statSync.
|
|
957
1151
|
let stat;
|
|
958
1152
|
try {
|
|
959
|
-
stat = fs.statSync(fullPath);
|
|
1153
|
+
stat = preparationStats.get(fullPath) ?? fs.statSync(fullPath);
|
|
960
1154
|
}
|
|
961
1155
|
catch (err) {
|
|
962
1156
|
if (err.code === 'ENOENT') {
|
|
963
1157
|
manifestStats.pruned++;
|
|
964
1158
|
if (verbose)
|
|
965
|
-
|
|
1159
|
+
log(` skipped missing: ${relativePath}`);
|
|
966
1160
|
continue;
|
|
967
1161
|
}
|
|
968
1162
|
throw err;
|
|
@@ -976,98 +1170,70 @@ export async function buildIndex(cwd, options = {}) {
|
|
|
976
1170
|
unchangedCount++;
|
|
977
1171
|
manifestStats.statSkipped++;
|
|
978
1172
|
if (verbose)
|
|
979
|
-
|
|
1173
|
+
log(` unchanged (stat): ${relativePath}`);
|
|
980
1174
|
continue;
|
|
981
1175
|
}
|
|
982
|
-
|
|
983
|
-
const
|
|
984
|
-
const checksum = computeChecksum(content);
|
|
985
|
-
// Skip unchanged files in incremental mode (checksum matched despite stat drift)
|
|
1176
|
+
const prepared = preparedArtifacts.get(fullPath);
|
|
1177
|
+
const { checksum } = prepared;
|
|
986
1178
|
if (!force && existingEntries[relativePath]?.checksum === checksum) {
|
|
987
1179
|
entries[relativePath] = existingEntries[relativePath];
|
|
988
|
-
// Update manifest with current stat so Phase 1 succeeds next time.
|
|
989
1180
|
nextManifestEntries[relativePath] = makeEntry(checksum, stat);
|
|
990
1181
|
unchangedCount++;
|
|
991
1182
|
manifestStats.checksumSkipped++;
|
|
992
1183
|
if (verbose)
|
|
993
|
-
|
|
1184
|
+
log(` unchanged (checksum): ${relativePath}`);
|
|
994
1185
|
continue;
|
|
995
1186
|
}
|
|
996
1187
|
manifestStats.reindexed++;
|
|
997
1188
|
nextManifestEntries[relativePath] = makeEntry(checksum, stat);
|
|
998
|
-
|
|
999
|
-
// YAML Flow documents (workflow.aiwg.io/v1) are pure YAML, not
|
|
1000
|
-
// markdown+frontmatter — detect them up front so they classify and
|
|
1001
|
-
// become discoverable (#1540).
|
|
1002
|
-
const flow = parseFlowDoc(content, relativePath);
|
|
1003
|
-
const decision = flow ? null : parseDecisionDoc(content, relativePath);
|
|
1004
|
-
const gatePack = flow || decision ? null : parseGatePackDoc(content, relativePath);
|
|
1005
|
-
const inferredType = inferType(data, relativePath);
|
|
1006
|
-
const physicalType = inferType({ ...data, type: undefined }, relativePath);
|
|
1007
|
-
const runbook = flow || decision || gatePack ? null : parseRunbookDoc(data, body, relativePath);
|
|
1008
|
-
const schemaDoc = inferredType === 'schema' ? parseSchemaDoc(content, relativePath) : null;
|
|
1009
|
-
const title = flow?.name ?? decision?.name ?? gatePack?.name ?? schemaDoc?.title ?? extractTitle(data, body);
|
|
1010
|
-
const phase = typeof data.phase === 'string' ? data.phase : inferPhase(relativePath);
|
|
1011
|
-
const type = flow?.type ?? decision?.type ?? gatePack?.type ?? (runbook ? 'runbook' : inferredType);
|
|
1012
|
-
const tags = flow?.tags ?? decision?.tags ?? gatePack?.tags ?? (Array.isArray(data.tags) ? data.tags.map(String) : []);
|
|
1013
|
-
const summary = flow?.description ?? decision?.description ?? gatePack?.description ?? schemaDoc?.capability ?? runbook?.capability ?? extractSummary(data, body);
|
|
1014
|
-
const dependencies = extractMentions(content);
|
|
1015
|
-
const markdownLinks = extractMarkdownLinks(content);
|
|
1016
|
-
// Discovery metadata (#1214, #1540, #1792) — meaningful for operational
|
|
1017
|
-
// AIWG artifact kinds. Kept undefined on document types so the index file
|
|
1018
|
-
// stays small for the common case.
|
|
1019
|
-
const isDiscoverable = OPERATIONAL_DISCOVERY_TYPES.includes(type);
|
|
1020
|
-
// Declarative processes have no trigger phrases — they rely on their
|
|
1021
|
-
// capability and structure-aware search terms.
|
|
1022
|
-
const triggers = isDiscoverable && !flow ? extractTriggers(body, data) : undefined;
|
|
1023
|
-
const capability = flow?.capability ?? decision?.capability ?? gatePack?.capability ?? schemaDoc?.capability ?? runbook?.capability ?? (isDiscoverable ? extractCapability(data, body) : undefined);
|
|
1024
|
-
const kind = flow?.kind ?? decision?.kind ?? gatePack?.kind ?? runbook?.kind;
|
|
1025
|
-
const sourceType = runbook && physicalType !== 'runbook' ? physicalType : undefined;
|
|
1026
|
-
const searchTerms = flow?.searchTerms ?? decision?.searchTerms ?? gatePack?.searchTerms ?? schemaDoc?.searchTerms ?? runbook?.searchTerms;
|
|
1027
|
-
const kernel = data.kernel === true || data.kernel === 'true' ? true : undefined;
|
|
1028
|
-
// Script entrypoint metadata is meaningful for skills only (#1227).
|
|
1029
|
-
const script = type === 'skill' ? extractSkillScript(data) : undefined;
|
|
1030
|
-
const operationalState = normalizeOperationalState(data.operational_state);
|
|
1031
|
-
const stateTransfer = normalizeStateTransferProjection(data.state_transfer);
|
|
1032
|
-
// Canonical short name (#1233) — used by the scorer to floor exact-name
|
|
1033
|
-
// queries to 1.0 so hyphenated kernel-skill names like `aiwg-doctor`
|
|
1034
|
-
// remain searchable even when the rendered title strips the hyphen.
|
|
1035
|
-
const name = flow?.name ?? decision?.name ?? gatePack?.name ?? schemaDoc?.name ?? (isDiscoverable ? extractCanonicalName(data, relativePath) : undefined);
|
|
1036
|
-
entry = {
|
|
1037
|
-
path: relativePath,
|
|
1038
|
-
type,
|
|
1039
|
-
...(kind ? { kind } : {}),
|
|
1040
|
-
...(sourceType ? { sourceType } : {}),
|
|
1041
|
-
phase,
|
|
1042
|
-
title,
|
|
1043
|
-
tags,
|
|
1044
|
-
created: typeof data.created === 'string' ? data.created : stat.birthtime.toISOString(),
|
|
1045
|
-
updated: stat.mtime.toISOString(),
|
|
1046
|
-
checksum,
|
|
1047
|
-
summary,
|
|
1048
|
-
dependencies,
|
|
1049
|
-
...(markdownLinks.length > 0 ? { markdownLinks } : {}),
|
|
1050
|
-
dependents: [], // Computed after all entries are processed
|
|
1051
|
-
...(name ? { name } : {}),
|
|
1052
|
-
...(triggers && triggers.length > 0 ? { triggers } : {}),
|
|
1053
|
-
...(capability ? { capability } : {}),
|
|
1054
|
-
...(searchTerms && searchTerms.length > 0 ? { searchTerms } : {}),
|
|
1055
|
-
...(kernel ? { kernel } : {}),
|
|
1056
|
-
...(script ? { script } : {}),
|
|
1057
|
-
...(operationalState ? { operationalState } : {}),
|
|
1058
|
-
...(stateTransfer ? { stateTransfer } : {}),
|
|
1059
|
-
};
|
|
1189
|
+
entry = prepared.entry;
|
|
1060
1190
|
}
|
|
1061
1191
|
entries[relativePath] = entry;
|
|
1062
1192
|
if (existingEntries[relativePath]) {
|
|
1063
1193
|
updatedCount++;
|
|
1064
1194
|
if (verbose)
|
|
1065
|
-
|
|
1195
|
+
log(` updated: ${relativePath}`);
|
|
1066
1196
|
}
|
|
1067
1197
|
else {
|
|
1068
1198
|
newCount++;
|
|
1069
1199
|
if (verbose)
|
|
1070
|
-
|
|
1200
|
+
log(` new: ${relativePath}`);
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
// Reuse derived indexes only when their complete input set is unchanged.
|
|
1204
|
+
// Supplements can live outside the scanned files, so they must still be read.
|
|
1205
|
+
// Configured edge extractors must run to discard stale cached edges even
|
|
1206
|
+
// when source checksums match.
|
|
1207
|
+
const total = Object.keys(entries).length;
|
|
1208
|
+
if (canReuseExisting && !useFilenameMetadata && !graphConfig?.metadataSupplements?.length
|
|
1209
|
+
&& !graphConfig?.edgeExtraction
|
|
1210
|
+
&& newCount === 0 && updatedCount === 0
|
|
1211
|
+
&& total === Object.keys(existingEntries).length
|
|
1212
|
+
&& manifest.generated && total === Object.keys(manifest.entries).length
|
|
1213
|
+
&& manifestStats.pruned === 0) {
|
|
1214
|
+
const stats = loadIndexFromDir(indexOutputDir, 'stats.json');
|
|
1215
|
+
if (stats?.version === INDEX_VERSION && stats.extractorVersion === INDEX_EXTRACTOR_VERSION
|
|
1216
|
+
&& stats.totalArtifacts === total
|
|
1217
|
+
&& requiredFiles.every(filename => fs.existsSync(path.join(indexOutputDir, filename)))) {
|
|
1218
|
+
// A timestamp-only source change needs a manifest refresh, but does not
|
|
1219
|
+
// invalidate metadata, tags, dependencies, or the persistent backend.
|
|
1220
|
+
const projectionNeedsRepair = graph === 'framework' && !relationsReceiptMatches();
|
|
1221
|
+
if (graph === 'framework') {
|
|
1222
|
+
const { writeRelations } = await import('./relations-builder.js');
|
|
1223
|
+
await writeRelations(entries, effectiveOutputCwd, indexOutputDir, force || !relationsReceiptMatches());
|
|
1224
|
+
}
|
|
1225
|
+
const buildTimeMs = Date.now() - startTime;
|
|
1226
|
+
writeIndexFile(effectiveOutputCwd, 'stats.json', {
|
|
1227
|
+
...stats,
|
|
1228
|
+
builtAt: new Date().toISOString(),
|
|
1229
|
+
buildTimeMs,
|
|
1230
|
+
}, indexOutputDir);
|
|
1231
|
+
// Preserve no-op manifest bytes after output-only timestamp drift.
|
|
1232
|
+
// Renew receipts only for changed source stats or repaired projections.
|
|
1233
|
+
if (manifestStats.checksumSkipped > 0 || projectionNeedsRepair)
|
|
1234
|
+
writeBuildManifest(nextManifestEntries);
|
|
1235
|
+
reportBuild(buildTimeMs, total);
|
|
1236
|
+
return;
|
|
1071
1237
|
}
|
|
1072
1238
|
}
|
|
1073
1239
|
// Apply metadata supplements if configured (enriches filename-metadata nodes from sidecars)
|
|
@@ -1084,13 +1250,18 @@ export async function buildIndex(cwd, options = {}) {
|
|
|
1084
1250
|
}
|
|
1085
1251
|
// Build dependency graph and compute dependents
|
|
1086
1252
|
let markdownLinkEdgeCount = 0;
|
|
1253
|
+
const entryPaths = Object.keys(entries);
|
|
1254
|
+
const dependencyPaths = new Map();
|
|
1087
1255
|
for (const entry of Object.values(entries)) {
|
|
1088
1256
|
if (!depGraph[entry.path]) {
|
|
1089
1257
|
depGraph[entry.path] = { upstream: [], downstream: [] };
|
|
1090
1258
|
}
|
|
1091
1259
|
for (const dep of entry.dependencies) {
|
|
1092
1260
|
// Normalize: check if referenced path exists in the index
|
|
1093
|
-
|
|
1261
|
+
if (!dependencyPaths.has(dep)) {
|
|
1262
|
+
dependencyPaths.set(dep, entryPaths.find(p => p === dep || p.endsWith(dep)));
|
|
1263
|
+
}
|
|
1264
|
+
const normalizedDep = dependencyPaths.get(dep);
|
|
1094
1265
|
if (normalizedDep && normalizedDep !== entry.path) {
|
|
1095
1266
|
addDependencyEdge(depGraph, entries, entry.path, normalizedDep, 'depends-on');
|
|
1096
1267
|
}
|
|
@@ -1173,18 +1344,23 @@ export async function buildIndex(cwd, options = {}) {
|
|
|
1173
1344
|
.filter(edge => !canonicalOutgoing.has(edge)).length,
|
|
1174
1345
|
};
|
|
1175
1346
|
if (verbose && citationEdgeCount > 0) {
|
|
1176
|
-
|
|
1347
|
+
log(` citation edges: ${citationEdgeCount}`);
|
|
1177
1348
|
}
|
|
1178
1349
|
}
|
|
1179
1350
|
// Deduplicate dependents
|
|
1180
1351
|
for (const entry of Object.values(entries)) {
|
|
1181
1352
|
entry.dependents = [...new Set(entry.dependents)];
|
|
1182
1353
|
}
|
|
1354
|
+
if (graph === 'framework') {
|
|
1355
|
+
const { writeRelations } = await import('./relations-builder.js');
|
|
1356
|
+
await writeRelations(entries, effectiveOutputCwd, indexOutputDir, force || !relationsReceiptMatches());
|
|
1357
|
+
}
|
|
1183
1358
|
const buildTimeMs = Date.now() - startTime;
|
|
1184
1359
|
// Write index files
|
|
1185
1360
|
const index = {
|
|
1186
1361
|
version: INDEX_VERSION,
|
|
1187
1362
|
extractorVersion: INDEX_EXTRACTOR_VERSION,
|
|
1363
|
+
buildConfigHash,
|
|
1188
1364
|
builtAt: new Date().toISOString(),
|
|
1189
1365
|
buildTimeMs,
|
|
1190
1366
|
entries,
|
|
@@ -1195,8 +1371,6 @@ export async function buildIndex(cwd, options = {}) {
|
|
|
1195
1371
|
// Materialize the configured backend and always retain dependencies.json as
|
|
1196
1372
|
// the stable compatibility/export contract.
|
|
1197
1373
|
const { createGraphBackend } = await import('./graph-backend.js');
|
|
1198
|
-
const { resolveGraphBackendType } = await import('./types.js');
|
|
1199
|
-
const backendType = resolveGraphBackendType(graph);
|
|
1200
1374
|
const persistentPath = backendType === 'sqlite' ? path.join(indexOutputDir, 'graph.db') : undefined;
|
|
1201
1375
|
let selectedBackend;
|
|
1202
1376
|
try {
|
|
@@ -1210,15 +1384,9 @@ export async function buildIndex(cwd, options = {}) {
|
|
|
1210
1384
|
// The next manifest contains entries for every file we processed this build.
|
|
1211
1385
|
// Files that disappeared from disk are pruned; the resulting manifest is
|
|
1212
1386
|
// written atomically.
|
|
1213
|
-
const nextManifest = {
|
|
1214
|
-
version: 1,
|
|
1215
|
-
generated: new Date().toISOString(),
|
|
1216
|
-
entries: nextManifestEntries,
|
|
1217
|
-
};
|
|
1218
1387
|
manifestStats.pruned = Object.keys(manifest.entries).length - Object.keys(nextManifestEntries).length;
|
|
1219
1388
|
if (manifestStats.pruned < 0)
|
|
1220
1389
|
manifestStats.pruned = 0;
|
|
1221
|
-
writeManifest(indexOutputDir, nextManifest);
|
|
1222
1390
|
// Write stats
|
|
1223
1391
|
const downstreamEdges = Object.values(depGraph).reduce((sum, node) => sum + node.downstream.length, 0);
|
|
1224
1392
|
const adjacencyEntries = Object.values(depGraph).reduce((sum, node) => sum + node.upstream.length + node.downstream.length, 0);
|
|
@@ -1262,22 +1430,8 @@ export async function buildIndex(cwd, options = {}) {
|
|
|
1262
1430
|
mostReferenced,
|
|
1263
1431
|
},
|
|
1264
1432
|
}, indexOutputDir);
|
|
1433
|
+
writeBuildManifest(nextManifestEntries);
|
|
1265
1434
|
// Report
|
|
1266
|
-
|
|
1267
|
-
console.log(`Artifact index built in ${buildTimeMs}ms`);
|
|
1268
|
-
console.log(` Indexed ${newCount} new, updated ${updatedCount}, unchanged ${unchangedCount}`);
|
|
1269
|
-
console.log(` Total: ${total} artifacts`);
|
|
1270
|
-
// Report manifest-driven change detection stats (only meaningful when !force
|
|
1271
|
-
// and we actually went through the content-read path for at least one file)
|
|
1272
|
-
if (!force && manifestStats.checked > 0) {
|
|
1273
|
-
const fastPath = manifestStats.statSkipped;
|
|
1274
|
-
const slowPath = manifestStats.checked - manifestStats.statSkipped;
|
|
1275
|
-
console.log(` Change detection: ${manifestStats.checked} checked, ${fastPath} skipped via stat, ${slowPath} content-read, ${manifestStats.reindexed} re-indexed`);
|
|
1276
|
-
if (manifestStats.pruned > 0) {
|
|
1277
|
-
console.log(` Pruned ${manifestStats.pruned} stale manifest entries (files no longer on disk)`);
|
|
1278
|
-
}
|
|
1279
|
-
}
|
|
1280
|
-
const displayDir = graph ? indexOutputDir : `${INDEX_DIR}/`;
|
|
1281
|
-
console.log(` Output: ${displayDir}`);
|
|
1435
|
+
reportBuild(buildTimeMs, total);
|
|
1282
1436
|
}
|
|
1283
1437
|
//# sourceMappingURL=index-builder.js.map
|