@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,240 @@
|
|
|
1
|
+
// A2A push-notification webhook receiver — verifies HMAC-SHA256 signatures
|
|
2
|
+
// using the Stripe-style `X-AIWG-Signature: t=<ts>,v1=<hmac>` header, rejects
|
|
3
|
+
// stale timestamps (replay protection), and deduplicates by event-id
|
|
4
|
+
// (idempotency).
|
|
5
|
+
//
|
|
6
|
+
// The webhook is the push-based alternative to SSE described in
|
|
7
|
+
// roctinam/agentic-sandbox issue #211. The executor signs the raw request
|
|
8
|
+
// body with a per-config secret (registered via
|
|
9
|
+
// A2AClient.createPushNotificationConfig) and POSTs StreamResponse-shaped
|
|
10
|
+
// payloads to the AIWG receiver URL.
|
|
11
|
+
//
|
|
12
|
+
// This module is HTTP-framework-agnostic. The serve.ts wiring adapts Hono
|
|
13
|
+
// requests to `verifyWebhookSignature`; tests can call the same function
|
|
14
|
+
// directly with synthesized Buffers.
|
|
15
|
+
//
|
|
16
|
+
// @issue #1256
|
|
17
|
+
import { createHmac, timingSafeEqual } from 'node:crypto';
|
|
18
|
+
/** Header name (case-insensitive). */
|
|
19
|
+
export const SIGNATURE_HEADER = 'x-aiwg-signature';
|
|
20
|
+
/** Five minutes — RFC 8941 timestamp tolerance. */
|
|
21
|
+
export const DEFAULT_TIMESTAMP_TOLERANCE_SECONDS = 300;
|
|
22
|
+
/** Idempotency cache size. Old entries are evicted FIFO. */
|
|
23
|
+
export const DEFAULT_IDEMPOTENCY_CAPACITY = 4096;
|
|
24
|
+
/**
|
|
25
|
+
* Verify the `X-AIWG-Signature` header against the raw request body.
|
|
26
|
+
*
|
|
27
|
+
* Stripe-style format:
|
|
28
|
+
* `X-AIWG-Signature: t=1700000000,v1=<hex hmac-sha256>`
|
|
29
|
+
*
|
|
30
|
+
* The HMAC is computed over `t=<timestamp>.<raw body>` (the timestamp and
|
|
31
|
+
* a literal dot, prepended to the body). Multiple `v1=` entries may be
|
|
32
|
+
* present in a single header (during a key rotation); any match accepts.
|
|
33
|
+
*/
|
|
34
|
+
export async function verifyWebhookSignature(signature, body, configId, opts) {
|
|
35
|
+
if (!signature) {
|
|
36
|
+
return { ok: false, code: 'signature_missing', detail: 'missing X-AIWG-Signature header' };
|
|
37
|
+
}
|
|
38
|
+
const parsed = parseSignatureHeader(signature);
|
|
39
|
+
if (!parsed) {
|
|
40
|
+
return { ok: false, code: 'signature_malformed', detail: 'X-AIWG-Signature did not parse' };
|
|
41
|
+
}
|
|
42
|
+
const tolerance = opts.toleranceSeconds ?? DEFAULT_TIMESTAMP_TOLERANCE_SECONDS;
|
|
43
|
+
const now = opts.now ? opts.now() : Math.floor(Date.now() / 1000);
|
|
44
|
+
if (Math.abs(now - parsed.timestamp) > tolerance) {
|
|
45
|
+
return {
|
|
46
|
+
ok: false,
|
|
47
|
+
code: 'timestamp_skew',
|
|
48
|
+
detail: `timestamp skew ${Math.abs(now - parsed.timestamp)}s exceeds tolerance ${tolerance}s`,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
const secret = await opts.lookupSecret(configId);
|
|
52
|
+
if (!secret) {
|
|
53
|
+
return { ok: false, code: 'secret_unknown', detail: `no secret registered for configId='${configId}'` };
|
|
54
|
+
}
|
|
55
|
+
const signedPayload = `${parsed.timestamp}.${body.toString('utf8')}`;
|
|
56
|
+
const expected = createHmac('sha256', secret).update(signedPayload).digest('hex');
|
|
57
|
+
for (const candidate of parsed.v1) {
|
|
58
|
+
if (constantTimeHexEqual(candidate, expected)) {
|
|
59
|
+
return { ok: true, timestamp: parsed.timestamp };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return { ok: false, code: 'signature_mismatch', detail: 'no v1 signature matched' };
|
|
63
|
+
}
|
|
64
|
+
/** Parse `t=...,v1=...,(v1=...,)*` into structured fields. */
|
|
65
|
+
export function parseSignatureHeader(header) {
|
|
66
|
+
const parts = header.split(',').map(s => s.trim()).filter(Boolean);
|
|
67
|
+
let timestamp = null;
|
|
68
|
+
const v1 = [];
|
|
69
|
+
for (const p of parts) {
|
|
70
|
+
const eq = p.indexOf('=');
|
|
71
|
+
if (eq <= 0)
|
|
72
|
+
return null;
|
|
73
|
+
const key = p.slice(0, eq);
|
|
74
|
+
const value = p.slice(eq + 1);
|
|
75
|
+
if (key === 't') {
|
|
76
|
+
const n = Number(value);
|
|
77
|
+
if (!Number.isFinite(n))
|
|
78
|
+
return null;
|
|
79
|
+
timestamp = n;
|
|
80
|
+
}
|
|
81
|
+
else if (key === 'v1') {
|
|
82
|
+
if (!/^[0-9a-f]+$/i.test(value))
|
|
83
|
+
return null;
|
|
84
|
+
v1.push(value);
|
|
85
|
+
}
|
|
86
|
+
// ignore unknown keys forward-compat
|
|
87
|
+
}
|
|
88
|
+
if (timestamp === null || v1.length === 0)
|
|
89
|
+
return null;
|
|
90
|
+
return { timestamp, v1 };
|
|
91
|
+
}
|
|
92
|
+
function constantTimeHexEqual(a, b) {
|
|
93
|
+
if (a.length !== b.length)
|
|
94
|
+
return false;
|
|
95
|
+
const ab = Buffer.from(a, 'hex');
|
|
96
|
+
const bb = Buffer.from(b, 'hex');
|
|
97
|
+
if (ab.length !== bb.length || ab.length === 0)
|
|
98
|
+
return false;
|
|
99
|
+
return timingSafeEqual(ab, bb);
|
|
100
|
+
}
|
|
101
|
+
// ── idempotency cache ──────────────────────────────────────────────────
|
|
102
|
+
/**
|
|
103
|
+
* Bounded FIFO event-id deduper. The first call with a given id returns
|
|
104
|
+
* true; subsequent calls return false until the id falls out of the
|
|
105
|
+
* window.
|
|
106
|
+
*
|
|
107
|
+
* Subscribers MUST dedupe per the spec — the executor's delivery worker
|
|
108
|
+
* retries on non-2xx responses, so a flaky downstream handler will
|
|
109
|
+
* receive the same event-id multiple times.
|
|
110
|
+
*/
|
|
111
|
+
export class IdempotencyCache {
|
|
112
|
+
capacity;
|
|
113
|
+
seen = new Set();
|
|
114
|
+
order = [];
|
|
115
|
+
constructor(capacity = DEFAULT_IDEMPOTENCY_CAPACITY) {
|
|
116
|
+
this.capacity = Math.max(16, capacity);
|
|
117
|
+
}
|
|
118
|
+
/** Returns true if `id` is new (and stores it); false if it's a duplicate. */
|
|
119
|
+
markFresh(id) {
|
|
120
|
+
if (this.seen.has(id))
|
|
121
|
+
return false;
|
|
122
|
+
this.seen.add(id);
|
|
123
|
+
this.order.push(id);
|
|
124
|
+
while (this.order.length > this.capacity) {
|
|
125
|
+
const evicted = this.order.shift();
|
|
126
|
+
if (evicted !== undefined)
|
|
127
|
+
this.seen.delete(evicted);
|
|
128
|
+
}
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
size() {
|
|
132
|
+
return this.seen.size;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
export class PushSecretRegistry {
|
|
136
|
+
entries = new Map();
|
|
137
|
+
register(entry) {
|
|
138
|
+
this.entries.set(entry.configId, entry);
|
|
139
|
+
}
|
|
140
|
+
lookup(configId) {
|
|
141
|
+
return this.entries.get(configId) ?? null;
|
|
142
|
+
}
|
|
143
|
+
unregister(configId) {
|
|
144
|
+
return this.entries.delete(configId);
|
|
145
|
+
}
|
|
146
|
+
/** Test/debug helper. */
|
|
147
|
+
size() {
|
|
148
|
+
return this.entries.size;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* One-shot processor: takes a raw webhook request (configId + body +
|
|
153
|
+
* signature header + event-id header), verifies, dedupes, routes.
|
|
154
|
+
*
|
|
155
|
+
* Returns the status code and body the HTTP layer should emit. The HTTP
|
|
156
|
+
* adapter (serve.ts) is responsible for reading the raw body bytes
|
|
157
|
+
* BEFORE any JSON parsing — the signature is computed over raw bytes
|
|
158
|
+
* (whitespace-sensitive).
|
|
159
|
+
*/
|
|
160
|
+
export async function handleWebhook(configId, body, signature, eventId, opts) {
|
|
161
|
+
if (!configId) {
|
|
162
|
+
return {
|
|
163
|
+
status: 400,
|
|
164
|
+
body: errorBody('aiwg.webhook_config_missing', 'configId query parameter missing'),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
if (!eventId) {
|
|
168
|
+
return {
|
|
169
|
+
status: 400,
|
|
170
|
+
body: errorBody('aiwg.webhook_event_id_missing', 'event-id header missing'),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
// Verify signature first — never touch the body's contents until the
|
|
174
|
+
// HMAC has been checked.
|
|
175
|
+
const verification = await verifyWebhookSignature(signature, body, configId, {
|
|
176
|
+
lookupSecret: id => {
|
|
177
|
+
const entry = opts.registry.lookup(id);
|
|
178
|
+
return entry ? entry.secret : null;
|
|
179
|
+
},
|
|
180
|
+
...(opts.toleranceSeconds !== undefined ? { toleranceSeconds: opts.toleranceSeconds } : {}),
|
|
181
|
+
...(opts.now ? { now: opts.now } : {}),
|
|
182
|
+
});
|
|
183
|
+
if (!verification.ok) {
|
|
184
|
+
return {
|
|
185
|
+
status: verification.code === 'timestamp_skew'
|
|
186
|
+
? 401
|
|
187
|
+
: verification.code === 'secret_unknown'
|
|
188
|
+
? 404
|
|
189
|
+
: 401,
|
|
190
|
+
body: errorBody(`aiwg.webhook_${verification.code}`, verification.detail ?? ''),
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
// Idempotency check — duplicate event-ids are accepted with 200 but
|
|
194
|
+
// not re-routed. The executor's retry logic depends on a 2xx response
|
|
195
|
+
// to mark delivery complete; failing here would cause infinite retry.
|
|
196
|
+
const fresh = opts.idempotency.markFresh(eventId);
|
|
197
|
+
if (!fresh) {
|
|
198
|
+
return { status: 200, body: { ok: true, deduped: true } };
|
|
199
|
+
}
|
|
200
|
+
// Route the verified payload. Errors thrown here become 500 so the
|
|
201
|
+
// executor will retry — pick the abstraction carefully on the
|
|
202
|
+
// mission-state side.
|
|
203
|
+
const entry = opts.registry.lookup(configId);
|
|
204
|
+
if (!entry) {
|
|
205
|
+
// Edge case: secret was unregistered between verify and route.
|
|
206
|
+
return {
|
|
207
|
+
status: 404,
|
|
208
|
+
body: errorBody('aiwg.webhook_secret_unknown', `configId='${configId}' no longer registered`),
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
let parsed;
|
|
212
|
+
try {
|
|
213
|
+
parsed = JSON.parse(body.toString('utf8'));
|
|
214
|
+
}
|
|
215
|
+
catch (e) {
|
|
216
|
+
return {
|
|
217
|
+
status: 400,
|
|
218
|
+
body: errorBody('aiwg.webhook_body_not_json', e.message),
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
try {
|
|
222
|
+
await opts.route(entry, parsed);
|
|
223
|
+
}
|
|
224
|
+
catch (e) {
|
|
225
|
+
return {
|
|
226
|
+
status: 500,
|
|
227
|
+
body: errorBody('aiwg.webhook_route_failed', e.message),
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
return { status: 200, body: { ok: true } };
|
|
231
|
+
}
|
|
232
|
+
function errorBody(code, detail) {
|
|
233
|
+
return {
|
|
234
|
+
type: 'about:blank',
|
|
235
|
+
title: 'Webhook rejected',
|
|
236
|
+
code,
|
|
237
|
+
detail,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
//# sourceMappingURL=webhook.js.map
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Activity Log CLI — `aiwg activity-log <subcommand>`
|
|
3
|
+
*
|
|
4
|
+
* Subcommands:
|
|
5
|
+
* show [--since DATE] [--operation OP] [--limit N]
|
|
6
|
+
* append <operation> "<summary>"
|
|
7
|
+
* stats
|
|
8
|
+
*
|
|
9
|
+
* Persists through `resolveStorage('activity_log')` per #964 — the
|
|
10
|
+
* physical destination is `.aiwg/activity.log` on the default `fs`
|
|
11
|
+
* backend, byte-identical to the legacy `echo >> .aiwg/activity.log`
|
|
12
|
+
* pattern documented in the activity-log skill.
|
|
13
|
+
*
|
|
14
|
+
* @design @.aiwg/architecture/storage-design.md (§4, §8.2)
|
|
15
|
+
* @issue #934
|
|
16
|
+
* @issue #964
|
|
17
|
+
*/
|
|
18
|
+
import { ACTIVITY_OPERATIONS, formatEntry, formatUtcTimestamp, isActivityOperation, } from './types.js';
|
|
19
|
+
import { parseLog, parseUtcDate } from './parser.js';
|
|
20
|
+
import { resolveStorage } from '../storage/index.js';
|
|
21
|
+
const LOG_PATH = 'activity.log';
|
|
22
|
+
const DEFAULT_LIMIT = 20;
|
|
23
|
+
export async function main(args) {
|
|
24
|
+
const subcommand = args[0];
|
|
25
|
+
const subArgs = args.slice(1);
|
|
26
|
+
switch (subcommand) {
|
|
27
|
+
case 'show':
|
|
28
|
+
await handleShow(subArgs);
|
|
29
|
+
break;
|
|
30
|
+
case 'append':
|
|
31
|
+
await handleAppend(subArgs);
|
|
32
|
+
break;
|
|
33
|
+
case 'stats':
|
|
34
|
+
await handleStats();
|
|
35
|
+
break;
|
|
36
|
+
case 'rotate':
|
|
37
|
+
await handleRotate(subArgs);
|
|
38
|
+
break;
|
|
39
|
+
default:
|
|
40
|
+
printUsage();
|
|
41
|
+
if (subcommand) {
|
|
42
|
+
throw new Error(`Unknown activity-log subcommand: ${subcommand}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async function handleShow(args) {
|
|
47
|
+
const opts = parseShowArgs(args);
|
|
48
|
+
const adapter = await resolveStorage('activity_log');
|
|
49
|
+
const entries = await readEntries(adapter);
|
|
50
|
+
let filtered = entries;
|
|
51
|
+
if (opts.since) {
|
|
52
|
+
const since = opts.since;
|
|
53
|
+
filtered = filtered.filter((e) => e.timestamp >= since);
|
|
54
|
+
}
|
|
55
|
+
if (opts.operation) {
|
|
56
|
+
filtered = filtered.filter((e) => e.operation === opts.operation);
|
|
57
|
+
}
|
|
58
|
+
// Newest first
|
|
59
|
+
filtered.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
|
|
60
|
+
if (filtered.length > opts.limit) {
|
|
61
|
+
filtered = filtered.slice(0, opts.limit);
|
|
62
|
+
}
|
|
63
|
+
if (filtered.length === 0) {
|
|
64
|
+
console.log('No activity log entries match the filters.');
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
for (const entry of filtered) {
|
|
68
|
+
console.log(formatEntry(entry));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async function handleAppend(args) {
|
|
72
|
+
if (args.length < 2) {
|
|
73
|
+
throw new Error(`Usage: aiwg activity-log append <operation> "<summary>"\n` +
|
|
74
|
+
` Valid operations: ${ACTIVITY_OPERATIONS.join(', ')}`);
|
|
75
|
+
}
|
|
76
|
+
const op = args[0];
|
|
77
|
+
const summary = args.slice(1).join(' ').trim();
|
|
78
|
+
if (!isActivityOperation(op)) {
|
|
79
|
+
throw new Error(`Invalid operation "${op}". Valid operations: ${ACTIVITY_OPERATIONS.join(', ')}`);
|
|
80
|
+
}
|
|
81
|
+
if (summary.length === 0) {
|
|
82
|
+
throw new Error('Summary must be a non-empty string');
|
|
83
|
+
}
|
|
84
|
+
if (summary.length > 120) {
|
|
85
|
+
// Soft limit per the activity-log rule. Warn but don't refuse —
|
|
86
|
+
// the rule says "≤120 characters" but doesn't promise rejection.
|
|
87
|
+
console.warn(`warning: summary is ${summary.length} chars (rule recommends ≤120)`);
|
|
88
|
+
}
|
|
89
|
+
// #975: honor AIWG_SKIP_ACTIVITY_LOG=1 per the activity-log rule.
|
|
90
|
+
if (isActivityLogSkipped()) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const adapter = await resolveStorage('activity_log');
|
|
94
|
+
const newLine = formatEntry({ timestamp: new Date(), operation: op, summary });
|
|
95
|
+
// #976: prefer atomic append when the backend supports it. The fs
|
|
96
|
+
// backend uses fs.appendFile (O_APPEND) so concurrent appenders don't
|
|
97
|
+
// race with each other. Fall back to read-then-write for backends
|
|
98
|
+
// that don't expose append (e.g., Notion, AnythingLLM, Fortemi) —
|
|
99
|
+
// those backends have their own concurrency models anyway.
|
|
100
|
+
if (typeof adapter.append === 'function') {
|
|
101
|
+
// Append guarantees no read-modify-write race. We need to ensure the
|
|
102
|
+
// existing log ends with a newline before our line; do that with a
|
|
103
|
+
// single-byte preamble append when needed.
|
|
104
|
+
const existing = (await adapter.read(LOG_PATH)) ?? '';
|
|
105
|
+
if (existing.length > 0 && !existing.endsWith('\n')) {
|
|
106
|
+
await adapter.append(LOG_PATH, '\n');
|
|
107
|
+
}
|
|
108
|
+
await adapter.append(LOG_PATH, newLine + '\n');
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
const existing = (await adapter.read(LOG_PATH)) ?? '';
|
|
112
|
+
const trailing = existing.length === 0 || existing.endsWith('\n') ? '' : '\n';
|
|
113
|
+
await adapter.write(LOG_PATH, existing + trailing + newLine + '\n');
|
|
114
|
+
}
|
|
115
|
+
console.log(`Entry appended to .aiwg/activity.log:\n ${newLine}`);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Returns true when AIWG_SKIP_ACTIVITY_LOG is set (per the activity-log
|
|
119
|
+
* rule's documented opt-out). Accepts "1", "true" (case-insensitive),
|
|
120
|
+
* or any non-empty value other than "0"/"false".
|
|
121
|
+
*/
|
|
122
|
+
function isActivityLogSkipped() {
|
|
123
|
+
const raw = process.env['AIWG_SKIP_ACTIVITY_LOG'];
|
|
124
|
+
if (!raw)
|
|
125
|
+
return false;
|
|
126
|
+
const v = raw.toLowerCase().trim();
|
|
127
|
+
if (v === '0' || v === 'false' || v === '')
|
|
128
|
+
return false;
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
async function handleStats() {
|
|
132
|
+
const adapter = await resolveStorage('activity_log');
|
|
133
|
+
const entries = await readEntries(adapter);
|
|
134
|
+
if (entries.length === 0) {
|
|
135
|
+
console.log('Activity log is empty.');
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const counts = new Map();
|
|
139
|
+
for (const op of ACTIVITY_OPERATIONS)
|
|
140
|
+
counts.set(op, 0);
|
|
141
|
+
for (const e of entries)
|
|
142
|
+
counts.set(e.operation, (counts.get(e.operation) ?? 0) + 1);
|
|
143
|
+
const sorted = [...entries].sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
|
|
144
|
+
const first = sorted[0].timestamp;
|
|
145
|
+
const last = sorted[sorted.length - 1].timestamp;
|
|
146
|
+
const days = Math.max(1, Math.ceil((last.getTime() - first.getTime()) / 86_400_000) + 1);
|
|
147
|
+
console.log(`Activity Log Statistics`);
|
|
148
|
+
console.log(`Log file: .aiwg/activity.log`);
|
|
149
|
+
console.log(`Date range: ${formatUtcTimestamp(first).slice(0, 10)} → ${formatUtcTimestamp(last).slice(0, 10)} (${days} day${days === 1 ? '' : 's'})`);
|
|
150
|
+
console.log(`Total entries: ${entries.length}`);
|
|
151
|
+
console.log('');
|
|
152
|
+
console.log(`By operation:`);
|
|
153
|
+
// Sort by count desc, then by op name asc for stability
|
|
154
|
+
const ranked = [...counts.entries()]
|
|
155
|
+
.filter(([, n]) => n > 0)
|
|
156
|
+
.sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]));
|
|
157
|
+
const maxCount = ranked[0]?.[1] ?? 1;
|
|
158
|
+
for (const [op, n] of ranked) {
|
|
159
|
+
const pct = Math.round((n / entries.length) * 100);
|
|
160
|
+
const barLen = Math.max(1, Math.round((n / maxCount) * 20));
|
|
161
|
+
const bar = '█'.repeat(barLen);
|
|
162
|
+
console.log(` ${op.padEnd(8)} ${String(n).padStart(3)} ${bar.padEnd(20)} ${pct}%`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
async function handleRotate(args) {
|
|
166
|
+
const opts = parseRotateArgs(args);
|
|
167
|
+
const adapter = await resolveStorage('activity_log');
|
|
168
|
+
const existing = (await adapter.read(LOG_PATH)) ?? '';
|
|
169
|
+
const entries = parseLog(existing);
|
|
170
|
+
if (entries.length === 0) {
|
|
171
|
+
throw new Error('Nothing to rotate: the activity log is empty (or contains no parseable entries).');
|
|
172
|
+
}
|
|
173
|
+
// Decide what stays inline vs what goes to archive
|
|
174
|
+
const sortedAsc = [...entries].sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
|
|
175
|
+
const { kept, archived } = splitForRotation(sortedAsc, opts.keepLast);
|
|
176
|
+
if (archived.length === 0) {
|
|
177
|
+
throw new Error(`Nothing to archive: --keep-last would retain all ${entries.length} entries inline.`);
|
|
178
|
+
}
|
|
179
|
+
// Determine archive destination (subsystem-relative)
|
|
180
|
+
const stamp = formatArchiveStamp(new Date());
|
|
181
|
+
const archivePath = opts.to ?? `archive/activity-log/${stamp}.log`;
|
|
182
|
+
// Refuse to overwrite an existing archive
|
|
183
|
+
const existingArchive = await adapter.read(archivePath);
|
|
184
|
+
if (existingArchive !== null) {
|
|
185
|
+
throw new Error(`Refusing to overwrite existing archive: ${archivePath}\n` +
|
|
186
|
+
` Either pass --to <other-path> or remove the existing archive first.`);
|
|
187
|
+
}
|
|
188
|
+
// Write archive (full historical content, oldest-first to match log order)
|
|
189
|
+
const archiveBody = archived.map((e) => formatEntry(e)).join('\n') + '\n';
|
|
190
|
+
await adapter.write(archivePath, archiveBody);
|
|
191
|
+
// Rewrite the live log with the retained tail
|
|
192
|
+
const liveBody = kept.length > 0 ? kept.map((e) => formatEntry(e)).join('\n') + '\n' : '';
|
|
193
|
+
await adapter.write(LOG_PATH, liveBody);
|
|
194
|
+
// Append a rotate-record entry to the live log (also exercises the
|
|
195
|
+
// append path so concurrent-write protection still applies).
|
|
196
|
+
const recordSummary = `activity-log rotated, archived ${archived.length} entries to ${archivePath}`;
|
|
197
|
+
if (typeof adapter.append === 'function') {
|
|
198
|
+
await adapter.append(LOG_PATH, formatEntry({ timestamp: new Date(), operation: 'archive', summary: recordSummary }) + '\n');
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
const live = (await adapter.read(LOG_PATH)) ?? '';
|
|
202
|
+
const trailing = live.length === 0 || live.endsWith('\n') ? '' : '\n';
|
|
203
|
+
await adapter.write(LOG_PATH, live +
|
|
204
|
+
trailing +
|
|
205
|
+
formatEntry({ timestamp: new Date(), operation: 'archive', summary: recordSummary }) +
|
|
206
|
+
'\n');
|
|
207
|
+
}
|
|
208
|
+
console.log(`Rotated activity log:`);
|
|
209
|
+
console.log(` Archived ${archived.length} entr${archived.length === 1 ? 'y' : 'ies'} to ${archivePath}`);
|
|
210
|
+
console.log(` Retained ${kept.length} entr${kept.length === 1 ? 'y' : 'ies'} inline`);
|
|
211
|
+
}
|
|
212
|
+
function parseRotateArgs(args) {
|
|
213
|
+
const opts = {};
|
|
214
|
+
for (let i = 0; i < args.length; i++) {
|
|
215
|
+
const a = args[i];
|
|
216
|
+
if (a === '--keep-last') {
|
|
217
|
+
const v = args[++i];
|
|
218
|
+
if (!v)
|
|
219
|
+
throw new Error(`--keep-last requires a value (e.g., 90d or 1000)`);
|
|
220
|
+
opts.keepLast = parseKeepLast(v);
|
|
221
|
+
}
|
|
222
|
+
else if (a === '--to') {
|
|
223
|
+
const v = args[++i];
|
|
224
|
+
if (!v)
|
|
225
|
+
throw new Error(`--to requires a path`);
|
|
226
|
+
opts.to = v;
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
throw new Error(`Unknown flag: ${a}`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return opts;
|
|
233
|
+
}
|
|
234
|
+
function parseKeepLast(raw) {
|
|
235
|
+
const dur = /^(\d+)d$/.exec(raw);
|
|
236
|
+
if (dur)
|
|
237
|
+
return { kind: 'duration_ms', ms: Number(dur[1]) * 86_400_000 };
|
|
238
|
+
const cnt = /^(\d+)$/.exec(raw);
|
|
239
|
+
if (cnt) {
|
|
240
|
+
const n = Number(cnt[1]);
|
|
241
|
+
if (n <= 0)
|
|
242
|
+
throw new Error(`--keep-last count must be positive (got ${raw})`);
|
|
243
|
+
return { kind: 'count', n };
|
|
244
|
+
}
|
|
245
|
+
throw new Error(`--keep-last must be <N>d or <N> (got ${JSON.stringify(raw)})`);
|
|
246
|
+
}
|
|
247
|
+
function splitForRotation(sortedAsc, keepLast) {
|
|
248
|
+
if (!keepLast) {
|
|
249
|
+
return { kept: [], archived: sortedAsc };
|
|
250
|
+
}
|
|
251
|
+
if (keepLast.kind === 'count') {
|
|
252
|
+
if (sortedAsc.length <= keepLast.n) {
|
|
253
|
+
return { kept: [...sortedAsc], archived: [] };
|
|
254
|
+
}
|
|
255
|
+
const cut = sortedAsc.length - keepLast.n;
|
|
256
|
+
return {
|
|
257
|
+
archived: sortedAsc.slice(0, cut),
|
|
258
|
+
kept: sortedAsc.slice(cut),
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
// duration_ms
|
|
262
|
+
const cutoff = Date.now() - keepLast.ms;
|
|
263
|
+
const kept = [];
|
|
264
|
+
const archived = [];
|
|
265
|
+
for (const e of sortedAsc) {
|
|
266
|
+
if (e.timestamp.getTime() >= cutoff)
|
|
267
|
+
kept.push(e);
|
|
268
|
+
else
|
|
269
|
+
archived.push(e);
|
|
270
|
+
}
|
|
271
|
+
return { kept, archived };
|
|
272
|
+
}
|
|
273
|
+
function formatArchiveStamp(d) {
|
|
274
|
+
// YYYYMMDD-HHMMSS UTC — sortable, unique to the second
|
|
275
|
+
const y = d.getUTCFullYear();
|
|
276
|
+
const mo = String(d.getUTCMonth() + 1).padStart(2, '0');
|
|
277
|
+
const da = String(d.getUTCDate()).padStart(2, '0');
|
|
278
|
+
const h = String(d.getUTCHours()).padStart(2, '0');
|
|
279
|
+
const mi = String(d.getUTCMinutes()).padStart(2, '0');
|
|
280
|
+
const s = String(d.getUTCSeconds()).padStart(2, '0');
|
|
281
|
+
return `${y}${mo}${da}-${h}${mi}${s}`;
|
|
282
|
+
}
|
|
283
|
+
// ── helpers ──────────────────────────────────────────────────────────
|
|
284
|
+
async function readEntries(adapter) {
|
|
285
|
+
const content = await adapter.read(LOG_PATH);
|
|
286
|
+
if (content === null)
|
|
287
|
+
return [];
|
|
288
|
+
return parseLog(content);
|
|
289
|
+
}
|
|
290
|
+
function parseShowArgs(args) {
|
|
291
|
+
const opts = { limit: DEFAULT_LIMIT };
|
|
292
|
+
for (let i = 0; i < args.length; i++) {
|
|
293
|
+
const a = args[i];
|
|
294
|
+
if (a === '--since') {
|
|
295
|
+
const v = args[++i];
|
|
296
|
+
const d = parseUtcDate(v);
|
|
297
|
+
if (!d)
|
|
298
|
+
throw new Error(`--since must be YYYY-MM-DD (got ${JSON.stringify(v)})`);
|
|
299
|
+
opts.since = d;
|
|
300
|
+
}
|
|
301
|
+
else if (a === '--operation') {
|
|
302
|
+
const v = args[++i];
|
|
303
|
+
if (!isActivityOperation(v)) {
|
|
304
|
+
throw new Error(`--operation must be one of ${ACTIVITY_OPERATIONS.join(', ')} (got ${JSON.stringify(v)})`);
|
|
305
|
+
}
|
|
306
|
+
opts.operation = v;
|
|
307
|
+
}
|
|
308
|
+
else if (a === '--limit') {
|
|
309
|
+
const v = Number(args[++i]);
|
|
310
|
+
if (!Number.isFinite(v) || v <= 0) {
|
|
311
|
+
throw new Error(`--limit must be a positive integer`);
|
|
312
|
+
}
|
|
313
|
+
opts.limit = Math.floor(v);
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
throw new Error(`Unknown flag: ${a}`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return opts;
|
|
320
|
+
}
|
|
321
|
+
function printUsage() {
|
|
322
|
+
console.log(`Usage: aiwg activity-log <subcommand>
|
|
323
|
+
|
|
324
|
+
Subcommands:
|
|
325
|
+
show [--since YYYY-MM-DD] [--operation OP] [--limit N]
|
|
326
|
+
append <operation> "<summary>"
|
|
327
|
+
stats
|
|
328
|
+
rotate [--keep-last <Nd|N>] [--to <path>]
|
|
329
|
+
|
|
330
|
+
Operations: ${ACTIVITY_OPERATIONS.join(', ')}
|
|
331
|
+
|
|
332
|
+
Examples:
|
|
333
|
+
aiwg activity-log show
|
|
334
|
+
aiwg activity-log show --since 2026-04-01 --operation deploy
|
|
335
|
+
aiwg activity-log show --limit 5
|
|
336
|
+
aiwg activity-log append create ".aiwg/requirements/UC-007 created"
|
|
337
|
+
aiwg activity-log stats
|
|
338
|
+
aiwg activity-log rotate # archive everything
|
|
339
|
+
aiwg activity-log rotate --keep-last 90d # archive entries older than 90 days
|
|
340
|
+
aiwg activity-log rotate --keep-last 1000 # keep last 1000 entries inline
|
|
341
|
+
|
|
342
|
+
Environment:
|
|
343
|
+
AIWG_SKIP_ACTIVITY_LOG=1 suppress append (per the activity-log rule)
|
|
344
|
+
|
|
345
|
+
The log persists at .aiwg/activity.log on the default fs backend.
|
|
346
|
+
Configure .aiwg/storage.config to route to an external backend (#934).`);
|
|
347
|
+
}
|
|
348
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Activity Log Parser
|
|
3
|
+
*
|
|
4
|
+
* Parses `.aiwg/activity.log` lines into structured entries. Lines that
|
|
5
|
+
* don't match the expected format are silently skipped (the log is
|
|
6
|
+
* append-only and may contain malformed entries from older tooling or
|
|
7
|
+
* manual edits).
|
|
8
|
+
*
|
|
9
|
+
* @issue #934
|
|
10
|
+
* @issue #964
|
|
11
|
+
*/
|
|
12
|
+
import { isActivityOperation } from './types.js';
|
|
13
|
+
/**
|
|
14
|
+
* Pattern: `## [YYYY-MM-DD HH:MM] <operation> | <summary>`
|
|
15
|
+
*
|
|
16
|
+
* Match groups:
|
|
17
|
+
* 1: full timestamp (`YYYY-MM-DD HH:MM`)
|
|
18
|
+
* 2: operation token
|
|
19
|
+
* 3: summary
|
|
20
|
+
*/
|
|
21
|
+
const LINE_PATTERN = /^##\s+\[(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2})\]\s+([a-z]+)\s+\|\s+(.+?)\s*$/;
|
|
22
|
+
/**
|
|
23
|
+
* Parse a single log line. Returns null when the line doesn't match the
|
|
24
|
+
* canonical format or the operation token is unknown.
|
|
25
|
+
*/
|
|
26
|
+
export function parseLine(line) {
|
|
27
|
+
const m = LINE_PATTERN.exec(line);
|
|
28
|
+
if (!m)
|
|
29
|
+
return null;
|
|
30
|
+
const [, rawTimestamp, op, summary] = m;
|
|
31
|
+
if (!isActivityOperation(op))
|
|
32
|
+
return null;
|
|
33
|
+
const timestamp = parseUtcTimestamp(rawTimestamp);
|
|
34
|
+
if (!timestamp)
|
|
35
|
+
return null;
|
|
36
|
+
return { timestamp, rawTimestamp, operation: op, summary };
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Parse the entire log content into entries. Skips blank lines and
|
|
40
|
+
* lines that don't match the canonical format.
|
|
41
|
+
*/
|
|
42
|
+
export function parseLog(content) {
|
|
43
|
+
const out = [];
|
|
44
|
+
for (const line of content.split('\n')) {
|
|
45
|
+
if (line.trim().length === 0)
|
|
46
|
+
continue;
|
|
47
|
+
const entry = parseLine(line);
|
|
48
|
+
if (entry)
|
|
49
|
+
out.push(entry);
|
|
50
|
+
}
|
|
51
|
+
return out;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Parse a `YYYY-MM-DD HH:MM` UTC timestamp into a Date. Returns null on
|
|
55
|
+
* malformed input.
|
|
56
|
+
*/
|
|
57
|
+
export function parseUtcTimestamp(raw) {
|
|
58
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2})$/.exec(raw);
|
|
59
|
+
if (!m)
|
|
60
|
+
return null;
|
|
61
|
+
const [, y, mo, d, h, mi] = m;
|
|
62
|
+
const date = new Date(Date.UTC(Number(y), Number(mo) - 1, Number(d), Number(h), Number(mi), 0));
|
|
63
|
+
if (Number.isNaN(date.getTime()))
|
|
64
|
+
return null;
|
|
65
|
+
return date;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Parse a `YYYY-MM-DD` date (interpreted as UTC midnight). Returns null
|
|
69
|
+
* on malformed input. Used by `--since` filtering.
|
|
70
|
+
*/
|
|
71
|
+
export function parseUtcDate(raw) {
|
|
72
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(raw);
|
|
73
|
+
if (!m)
|
|
74
|
+
return null;
|
|
75
|
+
const [, y, mo, d] = m;
|
|
76
|
+
const date = new Date(Date.UTC(Number(y), Number(mo) - 1, Number(d), 0, 0, 0));
|
|
77
|
+
if (Number.isNaN(date.getTime()))
|
|
78
|
+
return null;
|
|
79
|
+
return date;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=parser.js.map
|