@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,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical, extensible source-type registry + normalizer (#1509).
|
|
3
|
+
*
|
|
4
|
+
* A research corpus accumulates three drifting type vocabularies — frontmatter
|
|
5
|
+
* `type:` (mixes source type with doc role), `source_type:` (hyphen/underscore
|
|
6
|
+
* drift), and a body "Source Type" field. This module gives one canonical
|
|
7
|
+
* registry and a `normalizeSourceType` that folds all three (plus a venue
|
|
8
|
+
* fallback) into a single source-type dimension.
|
|
9
|
+
*
|
|
10
|
+
* The authoritative runtime default is `DEFAULT_SOURCE_TYPES` below; the
|
|
11
|
+
* human-readable + overridable form ships at
|
|
12
|
+
* `agentic/code/frameworks/research-complete/config/source-types.yaml`
|
|
13
|
+
* (a corpus may override at `documentation/source-types.yaml`). A drift test
|
|
14
|
+
* keeps the YAML and this constant in sync.
|
|
15
|
+
*
|
|
16
|
+
* Consumed by: the `by-source-type` index view, per-type induction audit
|
|
17
|
+
* (#1504), acquisition dispatch (#1507).
|
|
18
|
+
*
|
|
19
|
+
* @source historical: section9 REFERENCE-TEMPLATE*.md per-type rules
|
|
20
|
+
* @tests @test/unit/artifacts/source-types.test.ts
|
|
21
|
+
*/
|
|
22
|
+
import * as fs from 'fs';
|
|
23
|
+
import * as path from 'path';
|
|
24
|
+
import { load as loadYaml } from 'js-yaml';
|
|
25
|
+
const OVERRIDE_FILE = ['documentation', 'source-types.yaml'];
|
|
26
|
+
/** Authoritative runtime default registry. Mirrors the framework source-types.yaml. */
|
|
27
|
+
export const DEFAULT_SOURCE_TYPES = {
|
|
28
|
+
version: 1,
|
|
29
|
+
// VENUE_PATTERNS label → canonical type. Academic conferences/journals → paper;
|
|
30
|
+
// arXiv → preprint; lab/vendor research posts → blog; GitHub/Docs → repo;
|
|
31
|
+
// RFC → standard; Wikipedia → encyclopedia. Used only when frontmatter
|
|
32
|
+
// type/source_type is absent or unmatched.
|
|
33
|
+
venueFallback: {
|
|
34
|
+
NeurIPS: 'paper', ICML: 'paper', ICLR: 'paper', ACL: 'paper', EMNLP: 'paper',
|
|
35
|
+
NAACL: 'paper', CVPR: 'paper', ICCV: 'paper', ECCV: 'paper', AAAI: 'paper',
|
|
36
|
+
IJCAI: 'paper', KDD: 'paper', SIGIR: 'paper', WWW: 'paper', RSS: 'paper',
|
|
37
|
+
CoRL: 'paper', ICRA: 'paper', IROS: 'paper', OSDI: 'paper', SOSP: 'paper',
|
|
38
|
+
NSDI: 'paper', 'USENIX ATC': 'paper', 'USENIX Security': 'paper',
|
|
39
|
+
'IEEE S&P / Oakland': 'paper', CCS: 'paper', CHI: 'paper', UIST: 'paper',
|
|
40
|
+
VLDB: 'paper', SIGMOD: 'paper', FAccT: 'paper', TMLR: 'paper', JMLR: 'paper',
|
|
41
|
+
Nature: 'paper', Science: 'paper', PNAS: 'paper',
|
|
42
|
+
arXiv: 'preprint',
|
|
43
|
+
'RFC (IETF)': 'standard',
|
|
44
|
+
'Anthropic Research': 'blog', 'OpenAI Research': 'blog',
|
|
45
|
+
'DeepMind / Google Research': 'blog', 'Meta AI / FAIR': 'blog',
|
|
46
|
+
'Microsoft Research': 'blog',
|
|
47
|
+
'GitHub / Documentation': 'repo',
|
|
48
|
+
'Blog / Web Article': 'blog',
|
|
49
|
+
Wikipedia: 'encyclopedia',
|
|
50
|
+
},
|
|
51
|
+
metaRoles: ['redirect', 'stub', 'gap-note', 'merged', 'index'],
|
|
52
|
+
types: {
|
|
53
|
+
paper: { description: 'Peer-reviewed conference or journal paper.', aliases: ['paper', 'conference-paper', 'conference_paper', 'conference paper', 'journal_article', 'journal-article', 'journal article', 'reference', 'peer-reviewed'], template: 'reference-academic', requiredSections: ['Citation', 'Summary', 'Key Contributions', 'Benchmark Results', 'Comparison with Related Work'], citationFormat: 'doi-bibtex', acquisition: 'pdf-download', storage: 'sources/pdfs/full', qualityRules: 'peer-review-grade', defaultRadarCadence: 'quarterly' },
|
|
54
|
+
preprint: { description: 'arXiv / preprint server; not yet peer reviewed.', aliases: ['preprint', 'arxiv', 'arxiv-preprint', 'eprint'], template: 'reference-academic', requiredSections: ['Citation', 'Summary', 'Key Contributions', 'Benchmark Results'], citationFormat: 'arxiv-id', acquisition: 'pdf-download', storage: 'sources/pdfs/full', qualityRules: 'preprint-hedged-grade', defaultRadarCadence: 'quarterly' },
|
|
55
|
+
blog: { description: 'Blog post, lab announcement, or vendor research post.', aliases: ['blog', 'blog-post', 'blog post', 'announcement', 'lab-announcement', 'lab announcement', 'vendor-research', 'post'], template: 'reference-web', requiredSections: ['Citation', 'Executive Summary', 'Key Claim', 'Practical Relevance'], citationFormat: 'url-venue-retrieved', acquisition: 'web-snapshot', storage: 'sources/web', qualityRules: 'non-peer-reviewed-hedging', defaultRadarCadence: 'biannual' },
|
|
56
|
+
repo: { description: 'Code repository or benchmark repository.', aliases: ['repo', 'codebase', 'code', 'repository', 'benchmark-repository', 'benchmark-repo', 'benchmark repository', 'github'], template: 'reference-repo', requiredSections: ['Citation', 'Summary', 'Architecture', 'Maintenance Signals'], citationFormat: 'repo-url-commit', acquisition: 'git-clone', storage: 'sources/repos', qualityRules: 'maintenance-activity-signals', defaultRadarCadence: 'on-demand' },
|
|
57
|
+
book: { description: 'Book.', aliases: ['book', 'monograph'], template: 'reference-academic', requiredSections: ['Citation', 'Summary', 'Key Contributions'], citationFormat: 'isbn', acquisition: 'manual', storage: 'sources/pdfs/full', qualityRules: 'editorial-grade', defaultRadarCadence: 'on-demand' },
|
|
58
|
+
chapter: { description: 'Book chapter.', aliases: ['chapter', 'book_chapter', 'book-chapter', 'book chapter'], template: 'reference-academic', requiredSections: ['Citation', 'Summary', 'Key Contributions'], citationFormat: 'isbn-chapter', acquisition: 'manual', storage: 'sources/pdfs/full', qualityRules: 'editorial-grade', defaultRadarCadence: 'on-demand' },
|
|
59
|
+
standard: { description: 'RFC, IETF/ISO/W3C standard, or formal specification.', aliases: ['standard', 'rfc', 'spec', 'specification', 'ietf', 'iso', 'w3c'], template: 'reference-web', requiredSections: ['Citation', 'Summary', 'Scope', 'Key Requirements'], citationFormat: 'standard-id', acquisition: 'web-snapshot', storage: 'sources/web', qualityRules: 'normative-spec', defaultRadarCadence: 'annual' },
|
|
60
|
+
doc: { description: 'Maintainer/vendor documentation, technical report, or report.', aliases: ['doc', 'documentation', 'maintainer-doc', 'vendor-doc', 'technical-report', 'technical report', 'report', 'manual'], template: 'reference-web', requiredSections: ['Citation', 'Summary', 'Practical Relevance'], citationFormat: 'url-venue-retrieved', acquisition: 'web-snapshot', storage: 'sources/web', qualityRules: 'non-peer-reviewed-hedging', defaultRadarCadence: 'biannual' },
|
|
61
|
+
discussion: { description: 'Issue, forum thread, or discussion.', aliases: ['discussion', 'issue', 'thread', 'forum'], template: 'reference-web', requiredSections: ['Citation', 'Summary', 'Key Points'], citationFormat: 'url-venue-retrieved', acquisition: 'web-snapshot', storage: 'sources/web', qualityRules: 'anecdotal-hedging', defaultRadarCadence: 'on-demand' },
|
|
62
|
+
encyclopedia: { description: 'Encyclopedia / reference-work entry (e.g. Wikipedia).', aliases: ['encyclopedia', 'wikipedia', 'wiki'], template: 'reference-web', requiredSections: ['Citation', 'Summary'], citationFormat: 'url-venue-retrieved', acquisition: 'web-snapshot', storage: 'sources/web', qualityRules: 'tertiary-source-hedging', defaultRadarCadence: 'annual' },
|
|
63
|
+
'expert-material': { description: 'Expert commentary, talk, or interview material.', aliases: ['expert-material', 'expert material', 'talk', 'interview', 'keynote'], template: 'reference-media', requiredSections: ['Citation', 'Media Profile', 'Summary', 'Key Timestamps'], citationFormat: 'timestamp-transcript', acquisition: 'manual', storage: 'media/transcripts', qualityRules: 'expert-opinion-hedging', defaultRadarCadence: 'on-demand' },
|
|
64
|
+
video: { description: 'Video, conference recording, course recording, or platform-hosted talk.', aliases: ['video', 'recording', 'webcast', 'livestream', 'stream', 'lecture-video', 'conference-video'], template: 'reference-media', requiredSections: ['Citation', 'Media Profile', 'Summary', 'Key Timestamps', 'Evidence and Transcript Method'], citationFormat: 'timestamp-transcript', acquisition: 'media-curator', storage: 'media/video', qualityRules: 'media-grade', defaultRadarCadence: 'on-demand' },
|
|
65
|
+
audio: { description: 'Audio recording, lecture audio, or direct-hosted audio source.', aliases: ['audio', 'audio-recording', 'lecture-audio', 'recording-audio'], template: 'reference-media', requiredSections: ['Citation', 'Media Profile', 'Summary', 'Key Timestamps', 'Evidence and Transcript Method'], citationFormat: 'timestamp-transcript', acquisition: 'media-curator', storage: 'media/audio', qualityRules: 'media-grade', defaultRadarCadence: 'on-demand' },
|
|
66
|
+
podcast: { description: 'Podcast episode or feed-hosted interview.', aliases: ['podcast', 'podcast-episode', 'episode', 'interview-audio'], template: 'reference-media', requiredSections: ['Citation', 'Media Profile', 'Summary', 'Key Timestamps', 'Evidence and Transcript Method'], citationFormat: 'timestamp-transcript', acquisition: 'media-curator', storage: 'media/audio', qualityRules: 'interview-hedged-grade', defaultRadarCadence: 'on-demand' },
|
|
67
|
+
lecture: { description: 'Institutional lecture, course video, keynote, seminar, or invited talk recording.', aliases: ['lecture', 'course', 'seminar', 'keynote', 'talk', 'invited-talk', 'conference-talk'], template: 'reference-media', requiredSections: ['Citation', 'Media Profile', 'Summary', 'Key Timestamps', 'Evidence and Transcript Method'], citationFormat: 'timestamp-transcript', acquisition: 'media-curator', storage: 'media/video', qualityRules: 'lecture-grade', defaultRadarCadence: 'on-demand' },
|
|
68
|
+
'internal-review': { description: 'Internal research note or architecture review (not an external source).', aliases: ['internal-review', 'internal-research', 'internal-architecture-review', 'audit'], template: 'reference-internal', requiredSections: ['Summary', 'Findings'], citationFormat: 'internal-ref', acquisition: 'internal', storage: 'documentation/synthesis', qualityRules: 'internal-note', defaultRadarCadence: 'on-demand' },
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
/** Coerce a parsed YAML registry (snake_case fields) into the typed registry. */
|
|
72
|
+
function coerceRegistry(raw) {
|
|
73
|
+
if (!raw || typeof raw !== 'object' || !raw.types)
|
|
74
|
+
return null;
|
|
75
|
+
const types = {};
|
|
76
|
+
for (const [k, v] of Object.entries(raw.types)) {
|
|
77
|
+
types[k] = {
|
|
78
|
+
description: String(v.description ?? ''),
|
|
79
|
+
aliases: (v.aliases ?? []).map(String),
|
|
80
|
+
template: String(v.template ?? ''),
|
|
81
|
+
requiredSections: (v.required_sections ?? v.requiredSections ?? []).map(String),
|
|
82
|
+
citationFormat: String(v.citation_format ?? v.citationFormat ?? ''),
|
|
83
|
+
acquisition: String(v.acquisition ?? ''),
|
|
84
|
+
storage: String(v.storage ?? ''),
|
|
85
|
+
qualityRules: String(v.quality_rules ?? v.qualityRules ?? ''),
|
|
86
|
+
defaultRadarCadence: String(v.default_radar_cadence ?? v.defaultRadarCadence ?? 'on-demand'),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
version: Number(raw.version ?? 1),
|
|
91
|
+
types,
|
|
92
|
+
venueFallback: (raw.venue_fallback ?? raw.venueFallback ?? {}),
|
|
93
|
+
metaRoles: (raw.meta_roles ?? raw.metaRoles ?? []).map(String),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/** Load the registry: corpus override (`documentation/source-types.yaml`) → built-in default. */
|
|
97
|
+
export function loadSourceTypeRegistry(corpusRoot) {
|
|
98
|
+
const override = path.join(corpusRoot, ...OVERRIDE_FILE);
|
|
99
|
+
if (fs.existsSync(override)) {
|
|
100
|
+
try {
|
|
101
|
+
const reg = coerceRegistry(loadYaml(fs.readFileSync(override, 'utf-8')));
|
|
102
|
+
if (reg && Object.keys(reg.types).length)
|
|
103
|
+
return reg;
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
/* malformed override → default */
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return DEFAULT_SOURCE_TYPES;
|
|
110
|
+
}
|
|
111
|
+
/** Build alias → canonical and meta-role lookups for fast normalization. */
|
|
112
|
+
function buildLookup(reg) {
|
|
113
|
+
const alias = new Map();
|
|
114
|
+
for (const [canonical, t] of Object.entries(reg.types)) {
|
|
115
|
+
alias.set(canonical.toLowerCase(), canonical);
|
|
116
|
+
for (const a of t.aliases)
|
|
117
|
+
alias.set(a.toLowerCase().trim(), canonical);
|
|
118
|
+
}
|
|
119
|
+
return { alias, meta: new Set(reg.metaRoles.map((r) => r.toLowerCase())) };
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Normalize any of the three drifting type vocabularies (+ venue fallback) to a
|
|
123
|
+
* canonical source type. Returns the canonical key, `'meta'` for doc-role
|
|
124
|
+
* values (redirect/stub/…), or `'other'` when nothing matches.
|
|
125
|
+
*/
|
|
126
|
+
export function normalizeSourceType(input, reg = DEFAULT_SOURCE_TYPES) {
|
|
127
|
+
const { alias, meta } = buildLookup(reg);
|
|
128
|
+
const candidates = [input.sourceType, input.type, input.bodySourceType]
|
|
129
|
+
.map((v) => (v ?? '').toLowerCase().trim())
|
|
130
|
+
.filter(Boolean);
|
|
131
|
+
for (const c of candidates) {
|
|
132
|
+
if (meta.has(c))
|
|
133
|
+
return 'meta';
|
|
134
|
+
if (alias.has(c))
|
|
135
|
+
return alias.get(c);
|
|
136
|
+
}
|
|
137
|
+
// No explicit type matched — try the venue classification fallback.
|
|
138
|
+
if (input.venue && reg.venueFallback[input.venue])
|
|
139
|
+
return reg.venueFallback[input.venue];
|
|
140
|
+
return 'other';
|
|
141
|
+
}
|
|
142
|
+
/** Look up a canonical source type's rules. */
|
|
143
|
+
export function getSourceType(canonical, reg = DEFAULT_SOURCE_TYPES) {
|
|
144
|
+
return reg.types[canonical] ?? null;
|
|
145
|
+
}
|
|
146
|
+
/** List canonical source-type keys. */
|
|
147
|
+
export function listSourceTypes(reg = DEFAULT_SOURCE_TYPES) {
|
|
148
|
+
return Object.keys(reg.types).sort();
|
|
149
|
+
}
|
|
150
|
+
/** Render the registry as a human-readable table. */
|
|
151
|
+
export function renderSourceTypes(reg) {
|
|
152
|
+
const out = [];
|
|
153
|
+
out.push(`Source-type registry (v${reg.version}) — ${Object.keys(reg.types).length} canonical types`);
|
|
154
|
+
out.push('');
|
|
155
|
+
out.push(`${'type'.padEnd(16)} ${'template'.padEnd(20)} ${'acquisition'.padEnd(14)} ${'cadence'.padEnd(10)} aliases`);
|
|
156
|
+
for (const key of listSourceTypes(reg)) {
|
|
157
|
+
const t = reg.types[key];
|
|
158
|
+
out.push(`${key.padEnd(16)} ${t.template.padEnd(20)} ${t.acquisition.padEnd(14)} ${t.defaultRadarCadence.padEnd(10)} ${t.aliases.slice(0, 4).join(', ')}${t.aliases.length > 4 ? ', …' : ''}`);
|
|
159
|
+
}
|
|
160
|
+
out.push('');
|
|
161
|
+
out.push(`meta roles (not source types): ${reg.metaRoles.join(', ')}`);
|
|
162
|
+
return out.join('\n') + '\n';
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=source-types.js.map
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scanned-page vision extraction (#1507). TS-native, provider-neutral port of
|
|
3
|
+
* section9 `scripts/corpus/codex_vision_extract_pages.sh`.
|
|
4
|
+
*
|
|
5
|
+
* Transcribes a directory of scanned page PNGs into per-page + combined Markdown
|
|
6
|
+
* via a pluggable vision adapter (the source script hardcoded the `codex` CLI;
|
|
7
|
+
* per the issue this is provider-neutral). Preserves the resumable / retry /
|
|
8
|
+
* `# Page N` contract and the `<!-- extraction-status: complete -->` markers.
|
|
9
|
+
* Optionally rasterizes a PDF → page PNGs first (poppler `pdftoppm`).
|
|
10
|
+
*
|
|
11
|
+
* Adapters:
|
|
12
|
+
* - `codex` — `codex exec --sandbox read-only --image … --output-last-message`
|
|
13
|
+
* - `command` — a generic shell-command template (AIWG_VISION_COMMAND) with
|
|
14
|
+
* {image}/{prompt_file}/{out} placeholders → works with any vision
|
|
15
|
+
* CLI (claude, a custom script, …). Truly provider-neutral.
|
|
16
|
+
* - a caller-supplied adapter (used by tests with a fake transcriber).
|
|
17
|
+
*
|
|
18
|
+
* @source historical: corpus/codex_vision_extract_pages.sh
|
|
19
|
+
* @tests @test/unit/artifacts/vision-extract.test.ts
|
|
20
|
+
*/
|
|
21
|
+
import * as fs from 'fs';
|
|
22
|
+
import * as path from 'path';
|
|
23
|
+
import { spawnSync } from 'child_process';
|
|
24
|
+
/** Strict-transcription prompt. `title` parameterizes the corpus-specific intro. */
|
|
25
|
+
export function buildPrompt(page, title) {
|
|
26
|
+
const subject = title ? `from ${title}` : 'from a scanned document';
|
|
27
|
+
return [
|
|
28
|
+
`You are transcribing one scanned page image ${subject}.`,
|
|
29
|
+
'',
|
|
30
|
+
'Task:',
|
|
31
|
+
'- Extract all readable text from this image as accurately as possible.',
|
|
32
|
+
'- Preserve reading order.',
|
|
33
|
+
'- Keep headings, captions, labels, footnotes, marginal text, chart labels, table entries, and page numbers when readable.',
|
|
34
|
+
'- If text is part of a figure or chart, include it under a short marker like "[figure text]" or "[chart labels]".',
|
|
35
|
+
'- Do not summarize, interpret, modernize spelling, or add commentary.',
|
|
36
|
+
'- If a word is uncertain, write the best reading followed by "[?]".',
|
|
37
|
+
'- If a region is unreadable, write "[unreadable]" only for that region.',
|
|
38
|
+
'- Output Markdown only.',
|
|
39
|
+
`- Start exactly with: "# Page ${page}"`,
|
|
40
|
+
'',
|
|
41
|
+
'Accuracy is more important than preserving coordinates or line breaks.',
|
|
42
|
+
].join('\n');
|
|
43
|
+
}
|
|
44
|
+
// ── Adapters ─────────────────────────────────────────────────────────────────
|
|
45
|
+
const codexAdapter = {
|
|
46
|
+
name: 'codex',
|
|
47
|
+
transcribe(imagePath, prompt, ctx) {
|
|
48
|
+
const tmp = path.join(path.dirname(imagePath), `.codex-out-${ctx.page}.txt`);
|
|
49
|
+
const args = ['exec'];
|
|
50
|
+
if (ctx.model)
|
|
51
|
+
args.push('--model', ctx.model);
|
|
52
|
+
args.push('--sandbox', 'read-only', '--cd', ctx.root, '--image', imagePath, '--output-last-message', tmp, '-');
|
|
53
|
+
try {
|
|
54
|
+
const r = spawnSync(process.env.AIWG_CODEX_BIN || 'codex', args, {
|
|
55
|
+
input: prompt,
|
|
56
|
+
timeout: ctx.timeoutSec * 1000,
|
|
57
|
+
encoding: 'utf8',
|
|
58
|
+
});
|
|
59
|
+
if (r.status === 0 && fs.existsSync(tmp)) {
|
|
60
|
+
const text = fs.readFileSync(tmp, 'utf8');
|
|
61
|
+
fs.rmSync(tmp, { force: true });
|
|
62
|
+
return { ok: true, text };
|
|
63
|
+
}
|
|
64
|
+
fs.rmSync(tmp, { force: true });
|
|
65
|
+
return { ok: false };
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
fs.rmSync(tmp, { force: true });
|
|
69
|
+
return { ok: false };
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Generic command-template adapter (provider-neutral). Runs
|
|
75
|
+
* `AIWG_VISION_COMMAND` (or the `--command` flag) with placeholders:
|
|
76
|
+
* {image} absolute image path
|
|
77
|
+
* {prompt_file} path to a file containing the prompt
|
|
78
|
+
* {out} path the command must write the transcription to
|
|
79
|
+
* e.g. claude -p "$(cat {prompt_file})" --image {image} > {out}
|
|
80
|
+
*/
|
|
81
|
+
function commandAdapter(template) {
|
|
82
|
+
return {
|
|
83
|
+
name: 'command',
|
|
84
|
+
transcribe(imagePath, prompt, ctx) {
|
|
85
|
+
const dir = path.dirname(imagePath);
|
|
86
|
+
const promptFile = path.join(dir, `.vision-prompt-${ctx.page}.txt`);
|
|
87
|
+
const out = path.join(dir, `.vision-out-${ctx.page}.txt`);
|
|
88
|
+
fs.writeFileSync(promptFile, prompt);
|
|
89
|
+
const cmd = template
|
|
90
|
+
.replaceAll('{image}', JSON.stringify(imagePath))
|
|
91
|
+
.replaceAll('{prompt_file}', JSON.stringify(promptFile))
|
|
92
|
+
.replaceAll('{out}', JSON.stringify(out));
|
|
93
|
+
try {
|
|
94
|
+
const r = spawnSync('sh', ['-c', cmd], { timeout: ctx.timeoutSec * 1000, encoding: 'utf8' });
|
|
95
|
+
let text;
|
|
96
|
+
if (fs.existsSync(out))
|
|
97
|
+
text = fs.readFileSync(out, 'utf8');
|
|
98
|
+
else if (r.status === 0 && r.stdout)
|
|
99
|
+
text = r.stdout; // command wrote to stdout
|
|
100
|
+
fs.rmSync(promptFile, { force: true });
|
|
101
|
+
fs.rmSync(out, { force: true });
|
|
102
|
+
return { ok: r.status === 0 && !!text, text };
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
fs.rmSync(promptFile, { force: true });
|
|
106
|
+
fs.rmSync(out, { force: true });
|
|
107
|
+
return { ok: false };
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/** Resolve the vision adapter from options/env. Throws when misconfigured. */
|
|
113
|
+
export function resolveAdapter(opts = {}) {
|
|
114
|
+
const command = opts.command ?? process.env.AIWG_VISION_COMMAND;
|
|
115
|
+
const provider = opts.provider ?? process.env.AIWG_VISION_PROVIDER ?? (command ? 'command' : 'codex');
|
|
116
|
+
if (provider === 'command') {
|
|
117
|
+
if (!command)
|
|
118
|
+
throw new Error("vision provider 'command' requires --command or AIWG_VISION_COMMAND (template with {image}/{prompt_file}/{out})");
|
|
119
|
+
return commandAdapter(command);
|
|
120
|
+
}
|
|
121
|
+
if (provider === 'codex')
|
|
122
|
+
return codexAdapter;
|
|
123
|
+
throw new Error(`unknown vision provider '${provider}' (codex | command)`);
|
|
124
|
+
}
|
|
125
|
+
// ── PDF → PNG rasterization (poppler pdftoppm) ───────────────────────────────
|
|
126
|
+
export function pdftoppmAvailable() {
|
|
127
|
+
try {
|
|
128
|
+
return spawnSync('pdftoppm', ['-v'], { encoding: 'utf8' }).status === 0 || spawnSync('pdftoppm', ['-h'], { encoding: 'utf8' }).status !== null;
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Rasterize a PDF into zero-padded `page-NNN.png` files in `outDir` via
|
|
136
|
+
* `pdftoppm`. Returns the page count. Throws if pdftoppm is unavailable.
|
|
137
|
+
*/
|
|
138
|
+
export function rasterizePdf(pdfPath, outDir, dpi = 200) {
|
|
139
|
+
if (!pdftoppmAvailable()) {
|
|
140
|
+
throw new Error('PDF rasterization needs poppler `pdftoppm` on PATH (macOS: `brew install poppler`; Debian/Ubuntu: `apt install poppler-utils`).');
|
|
141
|
+
}
|
|
142
|
+
if (!fs.existsSync(pdfPath))
|
|
143
|
+
throw new Error(`PDF not found: ${pdfPath}`);
|
|
144
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
145
|
+
// pdftoppm writes <prefix>-<n>.png with its own zero-padding based on page count.
|
|
146
|
+
const prefix = path.join(outDir, 'page');
|
|
147
|
+
const r = spawnSync('pdftoppm', ['-png', '-r', String(dpi), pdfPath, prefix], { encoding: 'utf8' });
|
|
148
|
+
if (r.status !== 0)
|
|
149
|
+
throw new Error(`pdftoppm failed: ${r.stderr || r.status}`);
|
|
150
|
+
// Normalize names to page-NNN.png (3-digit zero-pad).
|
|
151
|
+
let count = 0;
|
|
152
|
+
for (const f of fs.readdirSync(outDir)) {
|
|
153
|
+
const m = f.match(/^page-(\d+)\.png$/);
|
|
154
|
+
if (!m)
|
|
155
|
+
continue;
|
|
156
|
+
count++;
|
|
157
|
+
const padded = `page-${m[1].padStart(3, '0')}.png`;
|
|
158
|
+
if (padded !== f)
|
|
159
|
+
fs.renameSync(path.join(outDir, f), path.join(outDir, padded));
|
|
160
|
+
}
|
|
161
|
+
return count;
|
|
162
|
+
}
|
|
163
|
+
// ── Orchestration (resumable page loop + combine) ────────────────────────────
|
|
164
|
+
const COMPLETE_MARKER = '<!-- extraction-status: complete -->';
|
|
165
|
+
function pageNumber(file) {
|
|
166
|
+
const m = path.basename(file).match(/^page-0*(\d+)\.png$/);
|
|
167
|
+
return m ? parseInt(m[1], 10) : null;
|
|
168
|
+
}
|
|
169
|
+
function isComplete(outFile) {
|
|
170
|
+
return fs.existsSync(outFile) && fs.readFileSync(outFile, 'utf8').startsWith(COMPLETE_MARKER);
|
|
171
|
+
}
|
|
172
|
+
export async function extractPages(opts) {
|
|
173
|
+
if (!fs.existsSync(opts.imageDir))
|
|
174
|
+
throw new Error(`missing image directory: ${opts.imageDir}`);
|
|
175
|
+
const pageDir = path.join(opts.outDir, 'pages');
|
|
176
|
+
fs.mkdirSync(pageDir, { recursive: true });
|
|
177
|
+
const log = [];
|
|
178
|
+
const logLine = (s) => log.push(s);
|
|
179
|
+
const sleep = opts.sleep ?? (() => { });
|
|
180
|
+
const start = opts.start ?? 1;
|
|
181
|
+
const end = opts.end ?? Number.MAX_SAFE_INTEGER;
|
|
182
|
+
const retries = opts.retries ?? 0;
|
|
183
|
+
const timeoutSec = opts.timeoutSec ?? 240;
|
|
184
|
+
const images = fs
|
|
185
|
+
.readdirSync(opts.imageDir)
|
|
186
|
+
.filter((f) => /^page-\d+\.png$/.test(f))
|
|
187
|
+
.map((f) => path.join(opts.imageDir, f))
|
|
188
|
+
.sort();
|
|
189
|
+
let processed = 0;
|
|
190
|
+
let completed = 0;
|
|
191
|
+
let failed = 0;
|
|
192
|
+
for (const image of images) {
|
|
193
|
+
const page = pageNumber(image);
|
|
194
|
+
if (page == null || page < start || page > end)
|
|
195
|
+
continue;
|
|
196
|
+
processed++;
|
|
197
|
+
const outFile = path.join(pageDir, `page-${String(page).padStart(3, '0')}.md`);
|
|
198
|
+
if (!opts.force && isComplete(outFile)) {
|
|
199
|
+
logLine(`skip page ${page}: already complete`);
|
|
200
|
+
completed++;
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
const prompt = buildPrompt(page, opts.title);
|
|
204
|
+
let ok = false;
|
|
205
|
+
for (let attempt = 1; attempt <= retries + 1; attempt++) {
|
|
206
|
+
const res = opts.adapter.transcribe(image, prompt, { root: path.dirname(opts.imageDir), page, timeoutSec, model: opts.model });
|
|
207
|
+
if (res.ok && res.text && new RegExp(`^# Page ${page}\\b`, 'm').test(res.text)) {
|
|
208
|
+
fs.writeFileSync(outFile, `${COMPLETE_MARKER}\n<!-- source-image: ${image} -->\n\n${res.text.trimEnd()}\n`);
|
|
209
|
+
logLine(`page ${page}: complete (attempt ${attempt})`);
|
|
210
|
+
ok = true;
|
|
211
|
+
completed++;
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
logLine(`page ${page}: unusable output (attempt ${attempt})`);
|
|
215
|
+
if (attempt <= retries)
|
|
216
|
+
sleep(opts.sleepSec ?? 0);
|
|
217
|
+
}
|
|
218
|
+
if (!ok) {
|
|
219
|
+
fs.writeFileSync(outFile, `<!-- extraction-status: failed -->\n<!-- source-image: ${image} -->\n\n# Page ${page}\n\n[extraction failed]\n`);
|
|
220
|
+
logLine(`page ${page}: failed after ${retries + 1} attempts`);
|
|
221
|
+
failed++;
|
|
222
|
+
sleep(opts.sleepSec ?? 0);
|
|
223
|
+
}
|
|
224
|
+
sleep(opts.sleepSec ?? 0);
|
|
225
|
+
}
|
|
226
|
+
// Combine.
|
|
227
|
+
const slug = path.basename(opts.outDir);
|
|
228
|
+
const head = [`# ${opts.title ?? slug}`, '', `Source: vision extraction (${opts.adapter.name}) from page PNGs`, `Pages processed: ${processed}`, ''];
|
|
229
|
+
const parts = [];
|
|
230
|
+
for (const f of fs.readdirSync(pageDir).filter((x) => /^page-\d+\.md$/.test(x)).sort()) {
|
|
231
|
+
parts.push(fs.readFileSync(path.join(pageDir, f), 'utf8'), '\n---\n\n');
|
|
232
|
+
}
|
|
233
|
+
const combinedMd = head.join('\n') + parts.join('');
|
|
234
|
+
const combinedTxt = combinedMd.split('\n').filter((l) => !/^<!--.*-->$/.test(l.trim())).join('\n');
|
|
235
|
+
fs.writeFileSync(path.join(opts.outDir, `${slug}.vision.md`), combinedMd);
|
|
236
|
+
fs.writeFileSync(path.join(opts.outDir, `${slug}.vision.txt`), combinedTxt);
|
|
237
|
+
fs.writeFileSync(path.join(opts.outDir, 'run.log'), log.join('\n') + '\n');
|
|
238
|
+
return { processed, completed, failed, combinedMd, combinedTxt };
|
|
239
|
+
}
|
|
240
|
+
export function renderExtract(r) {
|
|
241
|
+
return `vision-extract: processed ${r.processed}, completed ${r.completed}, failed ${r.failed}\n`;
|
|
242
|
+
}
|
|
243
|
+
//# sourceMappingURL=vision-extract.js.map
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Research-corpus markdown-view builder (#1490).
|
|
3
|
+
*
|
|
4
|
+
* The native replacement for the retired `corpus-index-build/build.py`.
|
|
5
|
+
* `aiwg index build` invokes this in the same process that builds the JSON
|
|
6
|
+
* graphs, so the corpus is parsed once. Reads the view manifest from
|
|
7
|
+
* `index.graphs.indices.manifest` (canonical `.aiwg/aiwg.config`, #1491).
|
|
8
|
+
*
|
|
9
|
+
* @source historical: corpus-index-build/build.py (configured_graphs, main)
|
|
10
|
+
*/
|
|
11
|
+
import * as fs from 'fs';
|
|
12
|
+
import * as path from 'path';
|
|
13
|
+
import { readIndexConfig, readAiwgConfig } from '../../config/aiwg-config.js';
|
|
14
|
+
import { loadCorpus } from './ref-parser.js';
|
|
15
|
+
import { renderView, outputForView } from './renderers.js';
|
|
16
|
+
const DEFAULT_VIEWS = ['by-topic', 'by-year', 'authors', 'by-venue', 'by-method', 'training-pipeline', 'by-model-size'];
|
|
17
|
+
/**
|
|
18
|
+
* Resolve which views to render from the index config, mirroring build.py
|
|
19
|
+
* configured_graphs(): manifest entries (by name), else a default set, plus
|
|
20
|
+
* citation-network when it is present as an index.graphs key.
|
|
21
|
+
*/
|
|
22
|
+
function configuredViews(index) {
|
|
23
|
+
const views = new Map();
|
|
24
|
+
const graphs = (index?.graphs ?? {});
|
|
25
|
+
const indices = graphs.indices;
|
|
26
|
+
const manifest = Array.isArray(indices?.manifest) ? indices.manifest : [];
|
|
27
|
+
for (const entry of manifest) {
|
|
28
|
+
if (entry && typeof entry === 'object' && typeof entry.name === 'string') {
|
|
29
|
+
const e = entry;
|
|
30
|
+
views.set(e.name, e);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (views.size === 0) {
|
|
34
|
+
for (const name of DEFAULT_VIEWS)
|
|
35
|
+
views.set(name, { name });
|
|
36
|
+
}
|
|
37
|
+
if ('citation-network' in graphs && !views.has('citation-network')) {
|
|
38
|
+
views.set('citation-network', { name: 'citation-network' });
|
|
39
|
+
}
|
|
40
|
+
return views;
|
|
41
|
+
}
|
|
42
|
+
/** Read the Source-Checksum recorded in an existing view file (for staleness skip). */
|
|
43
|
+
function existingChecksum(filePath) {
|
|
44
|
+
if (!fs.existsSync(filePath))
|
|
45
|
+
return null;
|
|
46
|
+
const m = fs.readFileSync(filePath, 'utf-8').match(/^Source-Checksum:\s*sha256:([a-f0-9]{64})\s*$/m);
|
|
47
|
+
return m ? m[1] : null;
|
|
48
|
+
}
|
|
49
|
+
function utcTimestamp() {
|
|
50
|
+
// Second-precision UTC, matching build.py's isoformat().replace("+00:00","Z").
|
|
51
|
+
return new Date().toISOString().replace(/\.\d{3}Z$/, 'Z');
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Resolve the corpus root (#1497): `AIWG_CORPUS_ROOT` env > `research.corpusRoot`
|
|
55
|
+
* in `.aiwg/aiwg.config` > the project root (cwd). Relative values resolve
|
|
56
|
+
* against cwd.
|
|
57
|
+
*/
|
|
58
|
+
export async function resolveCorpusRoot(cwd) {
|
|
59
|
+
const env = process.env.AIWG_CORPUS_ROOT;
|
|
60
|
+
if (env && env.trim())
|
|
61
|
+
return path.isAbsolute(env) ? env : path.join(cwd, env);
|
|
62
|
+
try {
|
|
63
|
+
const cfg = await readAiwgConfig(cwd);
|
|
64
|
+
const cr = cfg?.research?.corpusRoot;
|
|
65
|
+
if (cr && cr.trim())
|
|
66
|
+
return path.isAbsolute(cr) ? cr : path.join(cwd, cr);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
/* no config / unreadable — fall through to cwd */
|
|
70
|
+
}
|
|
71
|
+
return cwd;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Render the configured research-corpus markdown views. Returns one result per
|
|
75
|
+
* selected view. Returns `[]` (renders nothing) when the corpus root has no
|
|
76
|
+
* `documentation/references/` corpus — so this is a safe no-op in ordinary
|
|
77
|
+
* SDLC projects.
|
|
78
|
+
*/
|
|
79
|
+
export async function buildCorpusViews(cwd, opts = {}) {
|
|
80
|
+
// Corpus root may differ from the project root (#1497): env override >
|
|
81
|
+
// research.corpusRoot in .aiwg/aiwg.config > project root. The index config
|
|
82
|
+
// is always read from the project's .aiwg/aiwg.config (cwd); corpus content
|
|
83
|
+
// and rendered views live under the corpus root.
|
|
84
|
+
const root = await resolveCorpusRoot(cwd);
|
|
85
|
+
// No research corpus → nothing to render.
|
|
86
|
+
if (!fs.existsSync(path.join(root, 'documentation', 'references')))
|
|
87
|
+
return [];
|
|
88
|
+
const { index } = await readIndexConfig(cwd);
|
|
89
|
+
const views = configuredViews(index);
|
|
90
|
+
// `only` selects a single view when it is one we render; an unrelated JSON
|
|
91
|
+
// graph name (e.g. 'codebase') selects nothing here.
|
|
92
|
+
let selected;
|
|
93
|
+
if (opts.only) {
|
|
94
|
+
if (!views.has(opts.only))
|
|
95
|
+
return [];
|
|
96
|
+
selected = [opts.only];
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
selected = [...views.keys()];
|
|
100
|
+
}
|
|
101
|
+
const { records, corpusRoot, checksum } = loadCorpus(root);
|
|
102
|
+
const generated = utcTimestamp();
|
|
103
|
+
const ctx = { records, corpusRoot, generated, checksum };
|
|
104
|
+
const results = [];
|
|
105
|
+
for (const name of selected) {
|
|
106
|
+
const outRel = outputForView(name, views.get(name)?.output);
|
|
107
|
+
const outPath = path.join(root, outRel);
|
|
108
|
+
if (!opts.force && existingChecksum(outPath) === checksum) {
|
|
109
|
+
results.push({ graph: name, status: 'skipped', output: outRel, papers: records.length });
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
let content;
|
|
113
|
+
try {
|
|
114
|
+
content = renderView(name, ctx);
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
results.push({ graph: name, status: 'unsupported', output: outRel, error: err.message });
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
121
|
+
fs.writeFileSync(outPath, content, 'utf-8');
|
|
122
|
+
results.push({ graph: name, status: 'built', output: outRel, papers: records.length });
|
|
123
|
+
}
|
|
124
|
+
return results;
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=build.js.map
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared research-corpus cadence + staleness config (#1498, #1502).
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for refresh-cadence → window math. Consumed by:
|
|
5
|
+
* - renderers.ts `radar-stale-queue` view (#1492)
|
|
6
|
+
* - the radar subsystem: radar-init GRADE→cadence default, radar-status (#1498)
|
|
7
|
+
* - the profile subsystem: profile-status staleness (#1502)
|
|
8
|
+
*
|
|
9
|
+
* Ports `corpus/radar_staleness.py` CADENCE_DAYS, `corpus/radar_init.py`
|
|
10
|
+
* CADENCE_BY_GRADE, and `profiles/find_stale_profiles.py`'s cadence map into one
|
|
11
|
+
* module so the date-math lives in exactly one place — the explicit #1498/#1502
|
|
12
|
+
* "one staleness helper" requirement.
|
|
13
|
+
*
|
|
14
|
+
* @source historical: corpus/radar_staleness.py, corpus/radar_init.py
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Refresh-cadence enum word → staleness window in days.
|
|
18
|
+
*
|
|
19
|
+
* `null` = on-demand: never auto-overdue. `biennial` is accepted as a synonym
|
|
20
|
+
* for `biannual` (180d); both spellings appear in corpus sidecars. The Python
|
|
21
|
+
* sources used distinct on-demand sentinels (radar_staleness: None;
|
|
22
|
+
* find_stale_profiles: 9999) — both mean "never auto-stale", normalized to
|
|
23
|
+
* `null` here.
|
|
24
|
+
*/
|
|
25
|
+
export const CADENCE_DAYS = {
|
|
26
|
+
// PROF-S curator revisit-cadence vocab (#1499): daily/weekly/biweekly.
|
|
27
|
+
daily: 1,
|
|
28
|
+
weekly: 7,
|
|
29
|
+
biweekly: 14,
|
|
30
|
+
monthly: 30,
|
|
31
|
+
quarterly: 90,
|
|
32
|
+
biannual: 180,
|
|
33
|
+
biennial: 180,
|
|
34
|
+
'semi-annual': 180, // profile sidecars (#1502) spell the 180-day cadence this way
|
|
35
|
+
annual: 365,
|
|
36
|
+
'on-demand': null,
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Default refresh cadence by GRADE letter (radar-init scaffold default).
|
|
40
|
+
* A→quarterly, B/C→biannual, D→on-demand. Ports `radar_init.py` CADENCE_BY_GRADE.
|
|
41
|
+
*/
|
|
42
|
+
export const CADENCE_BY_GRADE = {
|
|
43
|
+
A: 'quarterly',
|
|
44
|
+
B: 'biannual',
|
|
45
|
+
C: 'biannual',
|
|
46
|
+
D: 'on-demand',
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Look up the staleness window for a cadence word.
|
|
50
|
+
* Returns `null` for on-demand and `undefined` for an unknown/absent cadence —
|
|
51
|
+
* callers distinguish "never stale" (null) from "can't tell" (undefined).
|
|
52
|
+
*/
|
|
53
|
+
export function cadenceWindowDays(cadence) {
|
|
54
|
+
if (!cadence)
|
|
55
|
+
return undefined;
|
|
56
|
+
return CADENCE_DAYS[cadence.toLowerCase()];
|
|
57
|
+
}
|
|
58
|
+
/** Default cadence for a GRADE letter; falls back to `biannual` for unknown/absent grades. */
|
|
59
|
+
export function cadenceForGrade(grade) {
|
|
60
|
+
if (!grade)
|
|
61
|
+
return 'biannual';
|
|
62
|
+
const letter = grade.trim().toUpperCase()[0] ?? '';
|
|
63
|
+
return CADENCE_BY_GRADE[letter] ?? 'biannual';
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Default affiliation canonicalization map (#1503): canonical `PROF-O-{slug}`
|
|
67
|
+
* → variant org-name strings that should resolve to it. Ports
|
|
68
|
+
* `corpus/normalize_affiliation.py` CANONICAL_MAP. Per epic #1496 principle #3
|
|
69
|
+
* (externalize hardcoded data), this default is overridable per-corpus via a
|
|
70
|
+
* `documentation/profiles/orgs/affiliation-map.yaml` data file (loaded by the
|
|
71
|
+
* sidecar-repair tool); this module keeps only the pure default + reverse-map
|
|
72
|
+
* builder so it stays dependency-free.
|
|
73
|
+
*/
|
|
74
|
+
export const DEFAULT_AFFILIATION_MAP = {
|
|
75
|
+
'PROF-O-anthropic': ['anthropic'],
|
|
76
|
+
'PROF-O-openai': ['openai'],
|
|
77
|
+
'PROF-O-google-deepmind': ['google deepmind', 'deepmind', 'google brain (now part of google deepmind)'],
|
|
78
|
+
'PROF-O-meta-fair': ['meta fair', 'facebook ai research', 'meta ai', 'meta ai research'],
|
|
79
|
+
'PROF-O-microsoft-research': ['microsoft research'],
|
|
80
|
+
'PROF-O-mit-csail': ['mit csail', 'massachusetts institute of technology — csail'],
|
|
81
|
+
'PROF-O-nvidia': ['nvidia', 'nvidia research'],
|
|
82
|
+
'PROF-O-sakana-ai': ['sakana ai'],
|
|
83
|
+
'PROF-O-stanford-hai': ['stanford hai', 'stanford institute for human-centered artificial intelligence'],
|
|
84
|
+
'PROF-O-together-ai': ['together ai', 'together.ai'],
|
|
85
|
+
'PROF-O-uc-berkeley': ['uc berkeley', 'university of california, berkeley'],
|
|
86
|
+
'PROF-O-cohere': ['cohere'],
|
|
87
|
+
'PROF-O-apollo-research': ['apollo research'],
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Reverse a canonical map (slug → variants) into variant-name → slug, plus
|
|
91
|
+
* self-mapping each slug. All keys lowercased/trimmed for direct lookup.
|
|
92
|
+
*/
|
|
93
|
+
export function buildAffiliationReverse(map) {
|
|
94
|
+
const rev = new Map();
|
|
95
|
+
for (const [slug, names] of Object.entries(map)) {
|
|
96
|
+
for (const n of names)
|
|
97
|
+
rev.set(n.toLowerCase().trim(), slug);
|
|
98
|
+
rev.set(slug.toLowerCase(), slug);
|
|
99
|
+
}
|
|
100
|
+
return rev;
|
|
101
|
+
}
|
|
102
|
+
const MS_PER_DAY = 86_400_000;
|
|
103
|
+
/**
|
|
104
|
+
* Compute staleness for a `refresh-cadence` + `last-refreshed` ISO date as of
|
|
105
|
+
* `today`. Mirrors `radar_staleness.compute_staleness`: whole-day floor,
|
|
106
|
+
* UTC-midnight anchoring, and on-demand / unknown-cadence / undatable inputs all
|
|
107
|
+
* yield `overdueDays === null` (not stale).
|
|
108
|
+
*
|
|
109
|
+
* `today` should be a UTC-midnight Date (e.g. `new Date('2026-05-26T00:00:00Z')`)
|
|
110
|
+
* so day deltas are exact.
|
|
111
|
+
*/
|
|
112
|
+
export function computeStaleness(cadence, lastRefreshed, today) {
|
|
113
|
+
const windowDays = cadenceWindowDays(cadence);
|
|
114
|
+
let daysSince = null;
|
|
115
|
+
if (lastRefreshed) {
|
|
116
|
+
const last = new Date(`${lastRefreshed}T00:00:00Z`);
|
|
117
|
+
if (!Number.isNaN(last.getTime())) {
|
|
118
|
+
daysSince = Math.floor((today.getTime() - last.getTime()) / MS_PER_DAY);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const overdueDays = daysSince !== null && typeof windowDays === 'number' ? daysSince - windowDays : null;
|
|
122
|
+
return { daysSince, windowDays, overdueDays, isStale: overdueDays !== null && overdueDays > 0 };
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=corpus-config.js.map
|