@aiwg/cli 0.0.0-bootstrap.0 → 2026.7.18
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/LICENSE +21 -0
- package/README.md +22 -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 +1486 -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 +886 -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 +65 -9
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* profile-generate-fm — PROF-P (FM authors) + PROF-G (group) profiles (#1502).
|
|
3
|
+
*
|
|
4
|
+
* Port of profiles/build_fm_profiles.py. The hardcoded FM_PAPERS + group_specs
|
|
5
|
+
* dicts are NOT ported — they are corpus-specific data and live in a
|
|
6
|
+
* corpus-local `documentation/profiles/fm-config.yaml` (absent → no-op). Reuses
|
|
7
|
+
* the shared generation context + PROF-P body builder from profile-generate.
|
|
8
|
+
*
|
|
9
|
+
* @source historical: profiles/build_fm_profiles.py
|
|
10
|
+
*/
|
|
11
|
+
import * as fs from 'fs';
|
|
12
|
+
import * as path from 'path';
|
|
13
|
+
import { load as loadYaml } from 'js-yaml';
|
|
14
|
+
import { loadGenContext, buildProfileBody, slugifyAuthor } from './profile-generate.js';
|
|
15
|
+
/** Institutional markers excluded from FM PROF-P generation (build_fm_profiles). */
|
|
16
|
+
const FM_INST_KEYWORDS = [' team', 'ai @', 'deepseek-ai', 'anthropic', 'openai', 'et al.'];
|
|
17
|
+
/**
|
|
18
|
+
* Load `documentation/profiles/fm-config.yaml` (absent → empty). Shape:
|
|
19
|
+
* fm-papers:
|
|
20
|
+
* REF-052: { model: "GPT-3", top-authors: 5 }
|
|
21
|
+
* REF-835: { model: "Llama 3", group: PROF-G-llama-team }
|
|
22
|
+
* groups:
|
|
23
|
+
* PROF-G-llama-team:
|
|
24
|
+
* name: "Llama Team — AI @ Meta"
|
|
25
|
+
* parent-org: "Meta AI Research"
|
|
26
|
+
* parent-slug: PROF-O-meta-fair
|
|
27
|
+
* refs: [REF-835]
|
|
28
|
+
*/
|
|
29
|
+
export function loadFmConfig(corpusRoot) {
|
|
30
|
+
const file = path.join(corpusRoot, 'documentation', 'profiles', 'fm-config.yaml');
|
|
31
|
+
let raw;
|
|
32
|
+
try {
|
|
33
|
+
raw = loadYaml(fs.readFileSync(file, 'utf-8'));
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return { fmPapers: new Map(), groups: [] };
|
|
37
|
+
}
|
|
38
|
+
const obj = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : {};
|
|
39
|
+
const fmPapers = new Map();
|
|
40
|
+
const papers = obj['fm-papers'];
|
|
41
|
+
if (papers && typeof papers === 'object' && !Array.isArray(papers)) {
|
|
42
|
+
for (const [ref, v] of Object.entries(papers)) {
|
|
43
|
+
const e = (v && typeof v === 'object' && !Array.isArray(v) ? v : {});
|
|
44
|
+
fmPapers.set(ref, {
|
|
45
|
+
model: String(e.model ?? ref),
|
|
46
|
+
topAuthors: typeof e['top-authors'] === 'number' ? e['top-authors'] : 0,
|
|
47
|
+
group: e.group ? String(e.group) : undefined,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const groups = [];
|
|
52
|
+
const grp = obj['groups'];
|
|
53
|
+
if (grp && typeof grp === 'object' && !Array.isArray(grp)) {
|
|
54
|
+
for (const [slug, v] of Object.entries(grp)) {
|
|
55
|
+
const e = (v && typeof v === 'object' && !Array.isArray(v) ? v : {});
|
|
56
|
+
groups.push({
|
|
57
|
+
slug,
|
|
58
|
+
name: String(e.name ?? slug),
|
|
59
|
+
parentOrg: String(e['parent-org'] ?? ''),
|
|
60
|
+
parentSlug: e['parent-slug'] ? String(e['parent-slug']) : undefined,
|
|
61
|
+
refs: Array.isArray(e.refs) ? e.refs.map((r) => String(r)) : [],
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return { fmPapers, groups };
|
|
66
|
+
}
|
|
67
|
+
function shortTitle(t, n = 60) {
|
|
68
|
+
const s = (t ?? '').replace(/"/g, '').trim();
|
|
69
|
+
return s.length > n ? s.slice(0, n) + '...' : s;
|
|
70
|
+
}
|
|
71
|
+
/** Build a PROF-G group profile body. Mirrors build_fm_profiles' group block. */
|
|
72
|
+
function buildGroupBody(g, byId, today) {
|
|
73
|
+
const nextDue = new Date(new Date(`${today}T00:00:00Z`).getTime() + 180 * 86_400_000).toISOString().slice(0, 10);
|
|
74
|
+
const yamlRefs = '[' + g.refs.map((r) => `'${r}'`).join(', ') + ']';
|
|
75
|
+
const lines = [
|
|
76
|
+
'---',
|
|
77
|
+
`prof-id: ${g.slug}`,
|
|
78
|
+
`name: "${g.name}"`,
|
|
79
|
+
'type: group',
|
|
80
|
+
`parent-org: ${g.parentSlug ?? '(no PROF-O entry)'}`,
|
|
81
|
+
`aliases: ["${g.name}"]`,
|
|
82
|
+
`corpus-refs: ${yamlRefs}`,
|
|
83
|
+
'refresh-cadence: semi-annual',
|
|
84
|
+
`last-refreshed: ${today}`,
|
|
85
|
+
'last-refreshed-by: profile-generate-scaffold',
|
|
86
|
+
'grade-influence: A',
|
|
87
|
+
'grade-trajectory: rising',
|
|
88
|
+
'sources-searched: [corpus-citation-sidecars]',
|
|
89
|
+
'---',
|
|
90
|
+
'',
|
|
91
|
+
`# ${g.name} — Entity Profile`,
|
|
92
|
+
'',
|
|
93
|
+
'**Type**: Group (foundation-model release team)',
|
|
94
|
+
`**Profile ID**: \`${g.slug}\``,
|
|
95
|
+
`**Parent organization**: ${g.parentOrg}`,
|
|
96
|
+
`**Last refreshed**: ${today}`,
|
|
97
|
+
`**Next refresh due**: ${nextDue}`,
|
|
98
|
+
'',
|
|
99
|
+
'---',
|
|
100
|
+
'',
|
|
101
|
+
'## 1. Entity Summary',
|
|
102
|
+
'',
|
|
103
|
+
`The ${g.name} is the institutional collective publishing foundation-model release papers under collective authorship rather than under named individuals — typical of large open-weight launches where the contributor list is too large for first-author attribution.`,
|
|
104
|
+
'',
|
|
105
|
+
'**Research Identity**: Foundation-model release team.',
|
|
106
|
+
`**Parent**: ${g.parentOrg}.`,
|
|
107
|
+
'',
|
|
108
|
+
'---',
|
|
109
|
+
'',
|
|
110
|
+
'## 2. Corpus Presence',
|
|
111
|
+
'',
|
|
112
|
+
'| REF | Title | Year |',
|
|
113
|
+
'|---|---|---|',
|
|
114
|
+
];
|
|
115
|
+
for (const r of g.refs) {
|
|
116
|
+
const rec = byId.get(r);
|
|
117
|
+
lines.push(`| [${r}](../../references/) | ${shortTitle(rec?.title)} | ${rec?.year ?? '—'} |`);
|
|
118
|
+
}
|
|
119
|
+
lines.push('', `**Total corpus appearances**: ${g.refs.length}`, '', '---', '', '## 3. Notes', '', '- Group profile for a foundation-model release team. Individual contributors are profiled where corpus presence supports it.', '- Generated by `aiwg corpus profile-generate --fm` from `documentation/profiles/fm-config.yaml`.', '');
|
|
120
|
+
return lines.join('\n');
|
|
121
|
+
}
|
|
122
|
+
/** Generate FM-author PROF-P + group PROF-G profiles from fm-config.yaml. */
|
|
123
|
+
export function generateFmProfiles(corpusRoot, opts = {}) {
|
|
124
|
+
const today = opts.today || new Date().toISOString().slice(0, 10);
|
|
125
|
+
const cfg = loadFmConfig(corpusRoot);
|
|
126
|
+
const ctx = loadGenContext(corpusRoot);
|
|
127
|
+
const results = [];
|
|
128
|
+
const seen = new Set();
|
|
129
|
+
// PROF-P for unprofiled top-N authors of each FM paper.
|
|
130
|
+
for (const [ref, paper] of cfg.fmPapers) {
|
|
131
|
+
if (paper.topAuthors <= 0)
|
|
132
|
+
continue;
|
|
133
|
+
const authors = ctx.byId.get(ref)?.authors ?? [];
|
|
134
|
+
for (const a of authors.slice(0, paper.topAuthors)) {
|
|
135
|
+
if (FM_INST_KEYWORDS.some((kw) => a.toLowerCase().includes(kw)))
|
|
136
|
+
continue;
|
|
137
|
+
const slug = slugifyAuthor(a);
|
|
138
|
+
if (ctx.existing.has(slug) || seen.has(slug))
|
|
139
|
+
continue;
|
|
140
|
+
seen.add(slug);
|
|
141
|
+
const refs = [...(ctx.authorRefs.get(a) ?? [])].sort();
|
|
142
|
+
const outRel = path.join('documentation', 'profiles', 'people', `PROF-P-${slug}.md`);
|
|
143
|
+
const content = buildProfileBody(a, slug, refs, ctx.byId, ctx.inDeg, today);
|
|
144
|
+
results.push(emitProfile(corpusRoot, outRel, content, `${a} (top author of ${paper.model})`, opts.write));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// PROF-G for institutional/team authorship.
|
|
148
|
+
for (const g of cfg.groups) {
|
|
149
|
+
const outRel = path.join('documentation', 'profiles', 'groups', `${g.slug}.md`);
|
|
150
|
+
const content = buildGroupBody(g, ctx.byId, today);
|
|
151
|
+
results.push(emitProfile(corpusRoot, outRel, content, g.name, opts.write));
|
|
152
|
+
}
|
|
153
|
+
return results;
|
|
154
|
+
}
|
|
155
|
+
/** Write/skip/dry-run a profile; result `slug` is the full prof-id (PROF-P-… / PROF-G-…) from the path. */
|
|
156
|
+
function emitProfile(corpusRoot, outRel, content, name, write) {
|
|
157
|
+
const id = path.basename(outRel).replace(/\.md$/, '');
|
|
158
|
+
const outAbs = path.join(corpusRoot, outRel);
|
|
159
|
+
if (!write)
|
|
160
|
+
return { slug: id, name, status: 'dry-run', message: `DRY-RUN ${id}: ${name}`, outPath: outRel, content };
|
|
161
|
+
if (fs.existsSync(outAbs))
|
|
162
|
+
return { slug: id, name, status: 'skip', message: `SKIP ${id} (exists)`, outPath: outRel };
|
|
163
|
+
fs.mkdirSync(path.dirname(outAbs), { recursive: true });
|
|
164
|
+
fs.writeFileSync(outAbs, content, 'utf-8');
|
|
165
|
+
return { slug: id, name, status: 'wrote', message: `WROTE ${id}: ${name}`, outPath: outRel, content };
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=profile-generate-fm.js.map
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* profile-generate — scaffold compact PROF-P profiles for unprofiled hub authors (#1502).
|
|
3
|
+
*
|
|
4
|
+
* Port of profiles/build_tier1_profiles.py: ranks REFs by corpus in-degree
|
|
5
|
+
* (derived from citation outgoing-edges), takes each top REF's primary author,
|
|
6
|
+
* skips institutional/group "authors" and already-profiled people, and stamps a
|
|
7
|
+
* compact 5-section PROF-P sidecar. Reuses the #1497 parser (loadCorpus gives
|
|
8
|
+
* authors + edges + titles; loadProfileSlugs gives existing profiles) rather
|
|
9
|
+
* than re-parsing citation sidecars. Dry-run unless `write`; skips existing.
|
|
10
|
+
*
|
|
11
|
+
* `corpus-refs` is written as a list of REF-id strings (matching the corpus
|
|
12
|
+
* convention + build_tier1); the #1497 parser tolerates both that and the
|
|
13
|
+
* list-of-dicts shape.
|
|
14
|
+
*
|
|
15
|
+
* @source historical: profiles/build_tier1_profiles.py
|
|
16
|
+
*/
|
|
17
|
+
import * as fs from 'fs';
|
|
18
|
+
import * as path from 'path';
|
|
19
|
+
import { loadCorpus, loadProfileSlugs } from '../corpus-views/ref-parser.js';
|
|
20
|
+
/** Institutional / group "author" markers — these get group profiles, not PROF-P. */
|
|
21
|
+
const INST_KEYWORDS = ['team', 'labs', 'contributors', 'foundation', 'consortium', 'committee', 'anthropic alignment', 'stanford hai'];
|
|
22
|
+
/** Port of build_tier1_profiles.slugify: "Last, First" / "First Last" → "last-first". */
|
|
23
|
+
export function slugifyAuthor(name) {
|
|
24
|
+
let last;
|
|
25
|
+
let first;
|
|
26
|
+
if (name.includes(',')) {
|
|
27
|
+
const [l, f] = name.split(',', 2).map((s) => s.trim());
|
|
28
|
+
last = l ?? '';
|
|
29
|
+
first = f ?? '';
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
const parts = name.trim().split(/\s+/);
|
|
33
|
+
first = parts[0] ?? '';
|
|
34
|
+
last = parts[parts.length - 1] ?? '';
|
|
35
|
+
}
|
|
36
|
+
const firstWord = first.split(/\s+/)[0] ?? '';
|
|
37
|
+
const slug = `${last}-${firstWord}`.toLowerCase().replace(/ /g, '-').replace(/\./g, '').replace(/'/g, '');
|
|
38
|
+
return slug.replace(/-+/g, '-');
|
|
39
|
+
}
|
|
40
|
+
function shortTitle(t, n = 70) {
|
|
41
|
+
const s = (t ?? '').replace(/"/g, '').trim();
|
|
42
|
+
return s.length > n ? s.slice(0, n) + '...' : s;
|
|
43
|
+
}
|
|
44
|
+
/** Compute corpus in-degree per REF from citation outgoing-edges (within corpus). */
|
|
45
|
+
function inDegrees(records, byId) {
|
|
46
|
+
const inDeg = new Map();
|
|
47
|
+
for (const r of records) {
|
|
48
|
+
for (const t of r.outgoing) {
|
|
49
|
+
if (byId.has(t))
|
|
50
|
+
inDeg.set(t, (inDeg.get(t) ?? 0) + 1);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return inDeg;
|
|
54
|
+
}
|
|
55
|
+
/** Build the generation context once from the corpus (loadCorpus + in-degree + author index). */
|
|
56
|
+
export function loadGenContext(corpusRoot) {
|
|
57
|
+
const { records } = loadCorpus(corpusRoot);
|
|
58
|
+
const byId = new Map(records.map((r) => [r.refId, r]));
|
|
59
|
+
const inDeg = inDegrees(records, byId);
|
|
60
|
+
const existing = loadProfileSlugs(corpusRoot);
|
|
61
|
+
const authorRefs = new Map();
|
|
62
|
+
for (const r of records)
|
|
63
|
+
for (const a of r.authors)
|
|
64
|
+
(authorRefs.get(a) ?? authorRefs.set(a, new Set()).get(a)).add(r.refId);
|
|
65
|
+
return { records, byId, inDeg, authorRefs, existing };
|
|
66
|
+
}
|
|
67
|
+
/** Build the compact 5-section PROF-P markdown body. Mirrors generate_profile(). */
|
|
68
|
+
export function buildProfileBody(name, slug, refs, byId, inDeg, today) {
|
|
69
|
+
const refsData = refs
|
|
70
|
+
.map((r) => ({ ref: r, title: shortTitle(byId.get(r)?.title), year: byId.get(r)?.year != null ? String(byId.get(r).year) : '—', deg: inDeg.get(r) ?? 0 }))
|
|
71
|
+
.sort((a, b) => b.deg - a.deg);
|
|
72
|
+
const topRef = refsData[0] ?? { ref: '—', deg: 0, year: '—', title: '' };
|
|
73
|
+
// Co-author counts across this author's refs.
|
|
74
|
+
const coCount = new Map();
|
|
75
|
+
const coRefs = new Map();
|
|
76
|
+
for (const r of refs) {
|
|
77
|
+
for (const ca of byId.get(r)?.authors ?? []) {
|
|
78
|
+
if (ca === name)
|
|
79
|
+
continue;
|
|
80
|
+
coCount.set(ca, (coCount.get(ca) ?? 0) + 1);
|
|
81
|
+
(coRefs.get(ca) ?? coRefs.set(ca, []).get(ca)).push(r);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const topCo = [...coCount.entries()].sort((a, b) => b[1] - a[1]).slice(0, 10);
|
|
85
|
+
const yamlRefs = '[' + refs.map((r) => `'${r}'`).join(', ') + ']';
|
|
86
|
+
const nextDue = new Date(new Date(`${today}T00:00:00Z`).getTime() + 180 * 86_400_000).toISOString().slice(0, 10);
|
|
87
|
+
const summary = `${name} is the primary author of ${topRef.ref} (corpus in-degree ${topRef.deg}), ` +
|
|
88
|
+
`one of the top hubs in the corpus citation network. ${refs.length} corpus paper${refs.length !== 1 ? 's' : ''}.`;
|
|
89
|
+
const lines = [
|
|
90
|
+
'---',
|
|
91
|
+
`prof-id: PROF-P-${slug}`,
|
|
92
|
+
`name: "${name}"`,
|
|
93
|
+
'type: person',
|
|
94
|
+
'affiliation: ""',
|
|
95
|
+
`aliases: ["${name}"]`,
|
|
96
|
+
`corpus-refs: ${yamlRefs}`,
|
|
97
|
+
'refresh-cadence: semi-annual',
|
|
98
|
+
`last-refreshed: ${today}`,
|
|
99
|
+
'last-refreshed-by: profile-generate-scaffold',
|
|
100
|
+
'grade-influence: A',
|
|
101
|
+
'grade-trajectory: stable',
|
|
102
|
+
'sources-searched: [corpus-citation-sidecars]',
|
|
103
|
+
'---',
|
|
104
|
+
'',
|
|
105
|
+
`# ${name} — Entity Profile`,
|
|
106
|
+
'',
|
|
107
|
+
'**Type**: Person',
|
|
108
|
+
`**Profile ID**: \`PROF-P-${slug}\``,
|
|
109
|
+
`**Last refreshed**: ${today}`,
|
|
110
|
+
`**Next refresh due**: ${nextDue}`,
|
|
111
|
+
'',
|
|
112
|
+
'---',
|
|
113
|
+
'',
|
|
114
|
+
'## 1. Entity Summary',
|
|
115
|
+
'',
|
|
116
|
+
summary,
|
|
117
|
+
'',
|
|
118
|
+
'**Research Identity**: Foundational corpus author.',
|
|
119
|
+
`**Top hub authored**: [${topRef.ref}](../../references/) (in-degree ${topRef.deg})`,
|
|
120
|
+
`**Active in corpus since**: ${refsData[refsData.length - 1]?.year ?? '—'}`,
|
|
121
|
+
'',
|
|
122
|
+
'---',
|
|
123
|
+
'',
|
|
124
|
+
'## 2. Corpus Presence',
|
|
125
|
+
'',
|
|
126
|
+
'| REF | Title | Year | In-degree |',
|
|
127
|
+
'|---|---|---|---:|',
|
|
128
|
+
];
|
|
129
|
+
for (const rd of refsData)
|
|
130
|
+
lines.push(`| [${rd.ref}](../../references/) | ${rd.title} | ${rd.year} | ${rd.deg} |`);
|
|
131
|
+
lines.push('', `**Total corpus appearances**: ${refs.length}`, `**Most-cited corpus paper**: ${topRef.ref} (in-degree ${topRef.deg})`, '', '---', '', '## 3. Research Focus Profile', '', 'Derived mechanically from corpus paper titles. Manual topic-classification deferred to next refresh.', '', '---', '', '## 4. Co-Author Network (Top 10)', '', '| Co-Author | Joint Papers | REFs |', '|---|---|---|');
|
|
132
|
+
if (topCo.length) {
|
|
133
|
+
for (const [ca, count] of topCo)
|
|
134
|
+
lines.push(`| ${ca} | ${count} | ${(coRefs.get(ca) ?? []).join(', ')} |`);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
lines.push('| (single-author papers — no co-authors recorded) | — | — |');
|
|
138
|
+
}
|
|
139
|
+
lines.push('', `_Derived mechanically from ${refs.length} corpus citation sidecar(s) on ${today}.${coCount.size ? ` Top 10 of ${coCount.size} unique collaborators.` : ''}_`, '', '---', '', '## 5. Notes', '', '- Profile generated by `aiwg corpus profile-generate` (Tier-1 hub-primary-author pass).', '- Mechanical extraction from citation-sidecar frontmatter. Affiliation intentionally blank — populate after consulting the listed REFs.', '- Refresh recommended after the next major induction wave touches this researcher.', '');
|
|
140
|
+
return lines.join('\n');
|
|
141
|
+
}
|
|
142
|
+
/** Generate Tier-1 PROF-P profiles for unprofiled hub primary authors. */
|
|
143
|
+
export function generateTier1Profiles(corpusRoot, opts = {}) {
|
|
144
|
+
const today = opts.today || new Date().toISOString().slice(0, 10);
|
|
145
|
+
const limit = opts.limit ?? 25;
|
|
146
|
+
const scan = opts.scan ?? 60;
|
|
147
|
+
const ctx = loadGenContext(corpusRoot);
|
|
148
|
+
const ranked = [...ctx.inDeg.entries()].sort((a, b) => b[1] - a[1]).slice(0, scan);
|
|
149
|
+
const results = [];
|
|
150
|
+
const seen = new Set();
|
|
151
|
+
for (const [refId] of ranked) {
|
|
152
|
+
if (results.length >= limit)
|
|
153
|
+
break;
|
|
154
|
+
const primary = ctx.byId.get(refId)?.authors[0];
|
|
155
|
+
if (!primary)
|
|
156
|
+
continue;
|
|
157
|
+
if (INST_KEYWORDS.some((kw) => primary.toLowerCase().includes(kw)))
|
|
158
|
+
continue;
|
|
159
|
+
const slug = slugifyAuthor(primary);
|
|
160
|
+
if (ctx.existing.has(slug) || seen.has(slug))
|
|
161
|
+
continue;
|
|
162
|
+
seen.add(slug);
|
|
163
|
+
const refs = [...(ctx.authorRefs.get(primary) ?? [])].sort();
|
|
164
|
+
const outRel = path.join('documentation', 'profiles', 'people', `PROF-P-${slug}.md`);
|
|
165
|
+
const content = buildProfileBody(primary, slug, refs, ctx.byId, ctx.inDeg, today);
|
|
166
|
+
const outAbs = path.join(corpusRoot, outRel);
|
|
167
|
+
if (!opts.write) {
|
|
168
|
+
results.push({ slug, name: primary, status: 'dry-run', message: `DRY-RUN PROF-P-${slug}: ${primary} (${refs.length} refs)`, outPath: outRel, content });
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
if (fs.existsSync(outAbs)) {
|
|
172
|
+
results.push({ slug, name: primary, status: 'skip', message: `SKIP PROF-P-${slug} (exists)`, outPath: outRel });
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
fs.mkdirSync(path.dirname(outAbs), { recursive: true });
|
|
176
|
+
fs.writeFileSync(outAbs, content, 'utf-8');
|
|
177
|
+
results.push({ slug, name: primary, status: 'wrote', message: `WROTE PROF-P-${slug}: ${primary} (${refs.length} refs)`, outPath: outRel, content });
|
|
178
|
+
}
|
|
179
|
+
return results;
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=profile-generate.js.map
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* profile-metrics — corpus-local influence/centrality metrics (#1501).
|
|
3
|
+
*
|
|
4
|
+
* Port of profiles/compute_metrics.py: per-paper CD-index + PageRank, and
|
|
5
|
+
* per-PROF-P h-index / mean-CD / mean-PageRank + co-author centrality
|
|
6
|
+
* (betweenness/eigenvector/clustering) + influence grade. Reuses corpus-graph
|
|
7
|
+
* algorithms and the #1497 parser.
|
|
8
|
+
*
|
|
9
|
+
* @source historical: profiles/compute_metrics.py
|
|
10
|
+
*/
|
|
11
|
+
import { loadCorpus, loadProfiles } from '../corpus-views/ref-parser.js';
|
|
12
|
+
import { slugifyAuthor } from './profile-generate.js';
|
|
13
|
+
import { buildCitationGraph, buildCoauthorGraph, hIndex, cdIndex, pageRank, betweenness, eigenvector, clustering, } from './corpus-graph.js';
|
|
14
|
+
/** h-index → influence grade (compute_metrics.grade_influence thresholds). */
|
|
15
|
+
function gradeInfluence(h) {
|
|
16
|
+
if (h >= 3)
|
|
17
|
+
return 'A';
|
|
18
|
+
if (h >= 2)
|
|
19
|
+
return 'B';
|
|
20
|
+
if (h >= 1)
|
|
21
|
+
return 'C';
|
|
22
|
+
return 'D';
|
|
23
|
+
}
|
|
24
|
+
function mean(xs) {
|
|
25
|
+
return xs.length ? xs.reduce((a, b) => a + b, 0) / xs.length : 0;
|
|
26
|
+
}
|
|
27
|
+
/** Compute paper-level + person-level metrics across the corpus. */
|
|
28
|
+
export function computeMetrics(corpusRoot) {
|
|
29
|
+
const { records } = loadCorpus(corpusRoot);
|
|
30
|
+
const cite = buildCitationGraph(records);
|
|
31
|
+
const coauthor = buildCoauthorGraph(records);
|
|
32
|
+
// Paper-level: CD-index + PageRank.
|
|
33
|
+
const pr = pageRank(cite);
|
|
34
|
+
const papers = records.map((r) => ({
|
|
35
|
+
refId: r.refId,
|
|
36
|
+
cdIndex: cdIndex(r.refId, cite),
|
|
37
|
+
pageRank: Math.round((pr.get(r.refId) ?? 0) * 1e6) / 1e6,
|
|
38
|
+
}));
|
|
39
|
+
const paperById = new Map(papers.map((p) => [p.refId, p]));
|
|
40
|
+
// Co-author centrality (keyed by author display name).
|
|
41
|
+
const bc = betweenness(coauthor);
|
|
42
|
+
const ec = eigenvector(coauthor);
|
|
43
|
+
const cc = clustering(coauthor);
|
|
44
|
+
// author display-name → slug (to match PROF-P).
|
|
45
|
+
const slugToAuthor = new Map();
|
|
46
|
+
for (const a of coauthor.keys())
|
|
47
|
+
slugToAuthor.set(slugifyAuthor(a), a);
|
|
48
|
+
// Per-PROF-P aggregation.
|
|
49
|
+
const people = [];
|
|
50
|
+
for (const p of loadProfiles(corpusRoot)) {
|
|
51
|
+
if (p.type !== 'person')
|
|
52
|
+
continue;
|
|
53
|
+
const refs = p.corpusRefs.filter((r) => cite.out.has(r));
|
|
54
|
+
const citationCounts = refs.map((r) => (cite.in.get(r) ?? new Set()).size);
|
|
55
|
+
const h = hIndex(citationCounts);
|
|
56
|
+
const cds = refs.map((r) => paperById.get(r)?.cdIndex).filter((x) => x != null);
|
|
57
|
+
const prs = refs.map((r) => paperById.get(r)?.pageRank ?? 0);
|
|
58
|
+
const slug = p.profId.replace(/^PROF-P-/, '');
|
|
59
|
+
const author = slugToAuthor.get(slug);
|
|
60
|
+
people.push({
|
|
61
|
+
profId: p.profId,
|
|
62
|
+
name: p.name ?? '',
|
|
63
|
+
paperCount: refs.length,
|
|
64
|
+
hIndex: h,
|
|
65
|
+
meanCdIndex: cds.length ? Math.round(mean(cds) * 1e4) / 1e4 : null,
|
|
66
|
+
meanPageRank: Math.round(mean(prs) * 1e6) / 1e6,
|
|
67
|
+
betweenness: author ? Math.round((bc.get(author) ?? 0) * 1e6) / 1e6 : 0,
|
|
68
|
+
eigenvector: author ? Math.round((ec.get(author) ?? 0) * 1e6) / 1e6 : 0,
|
|
69
|
+
clustering: author ? Math.round((cc.get(author) ?? 0) * 1e4) / 1e4 : 0,
|
|
70
|
+
gradeInfluence: gradeInfluence(h),
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
people.sort((a, b) => b.hIndex - a.hIndex || b.meanPageRank - a.meanPageRank || (a.profId < b.profId ? -1 : 1));
|
|
74
|
+
return { papers, people };
|
|
75
|
+
}
|
|
76
|
+
/** Render person-level metrics as a markdown table (or `--papers` for paper-level). */
|
|
77
|
+
export function renderMetrics(m, mode = 'people') {
|
|
78
|
+
if (mode === 'papers') {
|
|
79
|
+
const lines = ['| REF | CD-index | PageRank |', '|---|---:|---:|'];
|
|
80
|
+
for (const p of [...m.papers].sort((a, b) => b.pageRank - a.pageRank)) {
|
|
81
|
+
lines.push(`| ${p.refId} | ${p.cdIndex ?? '—'} | ${p.pageRank} |`);
|
|
82
|
+
}
|
|
83
|
+
return lines.join('\n') + '\n';
|
|
84
|
+
}
|
|
85
|
+
const lines = [
|
|
86
|
+
'# Entity influence metrics',
|
|
87
|
+
'',
|
|
88
|
+
`${m.people.length} profiled people · ${m.papers.length} papers`,
|
|
89
|
+
'',
|
|
90
|
+
'| Profile | Papers | h-index | Mean CD | Mean PageRank | Betweenness | Eigenvector | Grade |',
|
|
91
|
+
'|---|---:|---:|---:|---:|---:|---:|---|',
|
|
92
|
+
];
|
|
93
|
+
for (const p of m.people) {
|
|
94
|
+
lines.push(`| ${p.profId} | ${p.paperCount} | ${p.hIndex} | ${p.meanCdIndex ?? '—'} | ${p.meanPageRank} | ${p.betweenness} | ${p.eigenvector} | ${p.gradeInfluence} |`);
|
|
95
|
+
}
|
|
96
|
+
return lines.join('\n') + '\n';
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=profile-metrics.js.map
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* profile-status — entity profiles past their refresh cadence (#1502).
|
|
3
|
+
*
|
|
4
|
+
* Port of profiles/find_stale_profiles.py: reads PROF-{P,O,G,F,S} frontmatter
|
|
5
|
+
* via the shared parser, computes staleness with the shared computeStaleness
|
|
6
|
+
* helper, and reports most-overdue-first. Profile-specific semantics, faithful
|
|
7
|
+
* to the source:
|
|
8
|
+
* - missing `refresh-cadence` defaults to `annual`; an unknown cadence word is
|
|
9
|
+
* also treated as `annual` (find_stale's CADENCE_DAYS.get(cadence, 365));
|
|
10
|
+
* - `on-demand` is never stale;
|
|
11
|
+
* - stale when overdue ≥ 0 (at or past the window), vs radar's strictly-> 0.
|
|
12
|
+
*
|
|
13
|
+
* @source historical: profiles/find_stale_profiles.py
|
|
14
|
+
*/
|
|
15
|
+
import { loadProfiles } from '../corpus-views/ref-parser.js';
|
|
16
|
+
import { computeStaleness, cadenceWindowDays } from '../corpus-views/corpus-config.js';
|
|
17
|
+
function asOf(today) {
|
|
18
|
+
return new Date(`${today ?? new Date().toISOString().slice(0, 10)}T00:00:00Z`);
|
|
19
|
+
}
|
|
20
|
+
/** Stringify a frontmatter value; js-yaml parses bare ISO dates to Date. */
|
|
21
|
+
function fmStr(v) {
|
|
22
|
+
if (typeof v === 'string')
|
|
23
|
+
return v.trim() || null;
|
|
24
|
+
if (typeof v === 'number')
|
|
25
|
+
return String(v);
|
|
26
|
+
if (v instanceof Date)
|
|
27
|
+
return v.toISOString().slice(0, 10);
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
/** One status row per profile that has a `last-refreshed`, sorted most-overdue-first. */
|
|
31
|
+
export function profileStatusRows(corpusRoot, opts = {}) {
|
|
32
|
+
const today = asOf(opts.today);
|
|
33
|
+
const rows = [];
|
|
34
|
+
for (const p of loadProfiles(corpusRoot)) {
|
|
35
|
+
const lastRefreshed = fmStr(p.frontmatter['last-refreshed']);
|
|
36
|
+
if (!lastRefreshed)
|
|
37
|
+
continue; // find_stale skips profiles without last-refreshed
|
|
38
|
+
let cadence = fmStr(p.frontmatter['refresh-cadence']) ?? 'annual';
|
|
39
|
+
if (cadenceWindowDays(cadence) === undefined)
|
|
40
|
+
cadence = 'annual'; // unknown -> 365, per source
|
|
41
|
+
const s = computeStaleness(cadence, lastRefreshed, today);
|
|
42
|
+
rows.push({
|
|
43
|
+
profId: p.profId,
|
|
44
|
+
name: p.name ?? '',
|
|
45
|
+
type: p.type ?? '',
|
|
46
|
+
cadence,
|
|
47
|
+
lastRefreshed,
|
|
48
|
+
daysSince: s.daysSince,
|
|
49
|
+
overdueDays: s.overdueDays,
|
|
50
|
+
isStale: s.overdueDays !== null && s.overdueDays >= 0, // source: days_overdue >= 0
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
const filtered = opts.staleOnly ? rows.filter((r) => r.isStale) : rows;
|
|
54
|
+
return filtered.sort((a, b) => {
|
|
55
|
+
const ao = a.overdueDays ?? -Infinity;
|
|
56
|
+
const bo = b.overdueDays ?? -Infinity;
|
|
57
|
+
if (ao !== bo)
|
|
58
|
+
return bo - ao;
|
|
59
|
+
return a.profId < b.profId ? -1 : a.profId > b.profId ? 1 : 0;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/** Render profile-status rows as a markdown table, CSV, or plain list. */
|
|
63
|
+
export function renderProfileStatus(rows, format = 'table') {
|
|
64
|
+
if (format === 'csv') {
|
|
65
|
+
const head = 'prof_id,type,cadence,last_refreshed,days_since,overdue_days,is_stale';
|
|
66
|
+
const body = rows.map((r) => `${r.profId},${r.type},${r.cadence},${r.lastRefreshed},${r.daysSince ?? ''},${r.overdueDays ?? ''},${r.isStale}`);
|
|
67
|
+
return [head, ...body].join('\n') + '\n';
|
|
68
|
+
}
|
|
69
|
+
if (format === 'list') {
|
|
70
|
+
return (rows
|
|
71
|
+
.map((r) => {
|
|
72
|
+
const tag = r.isStale ? `STALE +${r.overdueDays}d` : r.overdueDays === null ? 'n/a' : `ok (${-r.overdueDays}d left)`;
|
|
73
|
+
return `- ${r.profId} [${r.type}] ${r.cadence} — last ${r.lastRefreshed} — ${tag}`;
|
|
74
|
+
})
|
|
75
|
+
.join('\n') + '\n');
|
|
76
|
+
}
|
|
77
|
+
const lines = [
|
|
78
|
+
'| Profile | Type | Cadence | Last Refreshed | Days Since | Overdue (days) | Stale |',
|
|
79
|
+
'|---|---|---|---|---:|---:|---|',
|
|
80
|
+
];
|
|
81
|
+
for (const r of rows) {
|
|
82
|
+
lines.push(`| ${r.profId} | ${r.type || '—'} | ${r.cadence} | ${r.lastRefreshed} | ${r.daysSince ?? '—'} | ${r.overdueDays ?? '—'} | ${r.isStale ? 'yes' : 'no'} |`);
|
|
83
|
+
}
|
|
84
|
+
return lines.join('\n') + '\n';
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=profile-status.js.map
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* profile-temporal — publication trajectory + hot-streak detection (#1501).
|
|
3
|
+
*
|
|
4
|
+
* Port of profiles/temporal_analysis.py (stdlib): per-year paper counts, topic
|
|
5
|
+
* drift (cosine distance between consecutive-year topic vectors), hot-streak
|
|
6
|
+
* detection (≥3 consecutive years with ≥1 A-grade paper, Fortunato 2018),
|
|
7
|
+
* career-phase classification, and trajectory trend. Reuses the #1497 parser
|
|
8
|
+
* (year + topics) + the analysis-doc GRADE reader.
|
|
9
|
+
*
|
|
10
|
+
* @source historical: profiles/temporal_analysis.py
|
|
11
|
+
*/
|
|
12
|
+
import { loadCorpus, loadProfiles } from '../corpus-views/ref-parser.js';
|
|
13
|
+
import { readAnalysisGrade } from './radar-shared.js';
|
|
14
|
+
function topicVector(topics) {
|
|
15
|
+
const counts = new Map();
|
|
16
|
+
for (const t of topics)
|
|
17
|
+
counts.set(t, (counts.get(t) ?? 0) + 1);
|
|
18
|
+
const mag = Math.sqrt([...counts.values()].reduce((a, b) => a + b * b, 0));
|
|
19
|
+
if (mag === 0)
|
|
20
|
+
return new Map();
|
|
21
|
+
const v = new Map();
|
|
22
|
+
for (const [t, c] of counts)
|
|
23
|
+
v.set(t, c / mag);
|
|
24
|
+
return v;
|
|
25
|
+
}
|
|
26
|
+
function cosineDistance(a, b) {
|
|
27
|
+
if (!a.size || !b.size)
|
|
28
|
+
return 0;
|
|
29
|
+
const keys = new Set([...a.keys(), ...b.keys()]);
|
|
30
|
+
let dot = 0;
|
|
31
|
+
for (const k of keys)
|
|
32
|
+
dot += (a.get(k) ?? 0) * (b.get(k) ?? 0);
|
|
33
|
+
const m1 = Math.sqrt([...a.values()].reduce((s, x) => s + x * x, 0));
|
|
34
|
+
const m2 = Math.sqrt([...b.values()].reduce((s, x) => s + x * x, 0));
|
|
35
|
+
if (m1 === 0 || m2 === 0)
|
|
36
|
+
return 0;
|
|
37
|
+
return Math.round((1 - dot / (m1 * m2)) * 1e4) / 1e4;
|
|
38
|
+
}
|
|
39
|
+
function detectHotStreak(annual) {
|
|
40
|
+
let best = null;
|
|
41
|
+
let start = null;
|
|
42
|
+
let len = 0;
|
|
43
|
+
const close = (active) => {
|
|
44
|
+
if (len >= 3 && (best === null || len > best.length))
|
|
45
|
+
best = { startYear: start, length: len, ...(active ? { active: true } : {}) };
|
|
46
|
+
};
|
|
47
|
+
for (const d of annual) {
|
|
48
|
+
if (d.hasAGrade) {
|
|
49
|
+
if (start === null) {
|
|
50
|
+
start = d.year;
|
|
51
|
+
len = 1;
|
|
52
|
+
}
|
|
53
|
+
else
|
|
54
|
+
len++;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
close(false);
|
|
58
|
+
start = null;
|
|
59
|
+
len = 0;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
close(true);
|
|
63
|
+
return best;
|
|
64
|
+
}
|
|
65
|
+
/** Compute the temporal trajectory for one PROF-P/PROF-O profile. */
|
|
66
|
+
export function computeTrajectory(corpusRoot, profId, asOfYear = new Date().getUTCFullYear()) {
|
|
67
|
+
const profiles = loadProfiles(corpusRoot);
|
|
68
|
+
const profile = profiles.find((p) => p.profId === profId);
|
|
69
|
+
const empty = { profId, annualData: [], hotStreak: null, careerPhase: 'unknown', trajectoryTrend: 'insufficient data', firstYear: null, lastYear: null, totalPapers: 0 };
|
|
70
|
+
if (!profile)
|
|
71
|
+
return empty;
|
|
72
|
+
const { records } = loadCorpus(corpusRoot);
|
|
73
|
+
const byId = new Map(records.map((r) => [r.refId, r]));
|
|
74
|
+
const yearly = new Map();
|
|
75
|
+
for (const ref of profile.corpusRefs) {
|
|
76
|
+
const rec = byId.get(ref);
|
|
77
|
+
if (!rec || rec.year == null)
|
|
78
|
+
continue;
|
|
79
|
+
const grade = readAnalysisGrade(corpusRoot, ref);
|
|
80
|
+
(yearly.get(rec.year) ?? yearly.set(rec.year, []).get(rec.year)).push({ grade, topics: rec.topics });
|
|
81
|
+
}
|
|
82
|
+
if (yearly.size === 0)
|
|
83
|
+
return empty;
|
|
84
|
+
const years = [...yearly.keys()].sort((a, b) => a - b);
|
|
85
|
+
const annualData = [];
|
|
86
|
+
let prev = new Map();
|
|
87
|
+
for (const year of years) {
|
|
88
|
+
const papers = yearly.get(year);
|
|
89
|
+
const topics = papers.flatMap((p) => p.topics);
|
|
90
|
+
const grades = papers.map((p) => p.grade);
|
|
91
|
+
const tv = topicVector(topics);
|
|
92
|
+
annualData.push({
|
|
93
|
+
year,
|
|
94
|
+
paperCount: papers.length,
|
|
95
|
+
grades,
|
|
96
|
+
topTopics: [...tv.keys()].slice(0, 3),
|
|
97
|
+
topicDrift: prev.size ? cosineDistance(prev, tv) : null,
|
|
98
|
+
hasAGrade: grades.some((g) => g.toUpperCase().startsWith('A')),
|
|
99
|
+
});
|
|
100
|
+
prev = tv;
|
|
101
|
+
}
|
|
102
|
+
const firstYear = years[0];
|
|
103
|
+
const careerLength = asOfYear - firstYear;
|
|
104
|
+
const careerPhase = careerLength <= 5 ? 'early' : careerLength <= 15 ? 'mid' : 'senior';
|
|
105
|
+
const recent = annualData.slice(-3);
|
|
106
|
+
const counts = recent.map((d) => d.paperCount);
|
|
107
|
+
const trend = counts.length >= 2 ? (counts[counts.length - 1] > counts[0] ? 'accelerating' : counts[counts.length - 1] < counts[0] ? 'decelerating' : 'stable') : 'insufficient data';
|
|
108
|
+
return {
|
|
109
|
+
profId,
|
|
110
|
+
annualData,
|
|
111
|
+
hotStreak: detectHotStreak(annualData),
|
|
112
|
+
careerPhase,
|
|
113
|
+
trajectoryTrend: trend,
|
|
114
|
+
firstYear,
|
|
115
|
+
lastYear: years[years.length - 1],
|
|
116
|
+
totalPapers: annualData.reduce((s, d) => s + d.paperCount, 0),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/** Render a trajectory as a markdown summary + the §7 year table. */
|
|
120
|
+
export function renderTrajectory(t) {
|
|
121
|
+
if (!t.annualData.length)
|
|
122
|
+
return `${t.profId}: no dated corpus papers.\n`;
|
|
123
|
+
const hs = t.hotStreak ? `${t.hotStreak.length} years from ${t.hotStreak.startYear}${t.hotStreak.active ? ' (active)' : ''}` : 'none detected';
|
|
124
|
+
const lines = [
|
|
125
|
+
`# ${t.profId} — publication trajectory`,
|
|
126
|
+
'',
|
|
127
|
+
`Career phase: **${t.careerPhase}** · trend: **${t.trajectoryTrend}** · ${t.firstYear}–${t.lastYear} · ${t.totalPapers} papers`,
|
|
128
|
+
`Hot streak: ${hs}`,
|
|
129
|
+
'',
|
|
130
|
+
'| Year | Papers | Top Topics | Topic Drift |',
|
|
131
|
+
'|---|---:|---|---|',
|
|
132
|
+
];
|
|
133
|
+
for (const d of t.annualData) {
|
|
134
|
+
const drift = d.topicDrift == null ? '—' : d.topicDrift > 0.3 ? `${d.topicDrift} *(pivot)*` : String(d.topicDrift);
|
|
135
|
+
lines.push(`| ${d.year} | ${d.paperCount} | ${d.topTopics.join(', ') || '—'} | ${drift} |`);
|
|
136
|
+
}
|
|
137
|
+
return lines.join('\n') + '\n';
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=profile-temporal.js.map
|