@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,832 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sandbox Registry
|
|
3
|
+
*
|
|
4
|
+
* Manages registered agentic-sandbox instances. Each sandbox registers
|
|
5
|
+
* with `aiwg serve` via POST /api/sandboxes/register and then pushes
|
|
6
|
+
* real-time events over WebSocket at /ws/sandbox/:sandboxId.
|
|
7
|
+
*
|
|
8
|
+
* This is the AIWG side of the bidirectional integration:
|
|
9
|
+
* - aiwg#731 = registration API (this file)
|
|
10
|
+
* - sandbox#132 = outbound registration (pushes events here)
|
|
11
|
+
*
|
|
12
|
+
* @issue #731
|
|
13
|
+
* @see #710 — epic
|
|
14
|
+
* @see #732 — HITL relay (consumes hitl.input_required events)
|
|
15
|
+
* @see #733 — operator controls (proxies to sandbox HTTP)
|
|
16
|
+
*/
|
|
17
|
+
import { randomUUID } from 'crypto';
|
|
18
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, renameSync, unlinkSync } from 'fs';
|
|
19
|
+
import { homedir } from 'os';
|
|
20
|
+
import { dirname, isAbsolute, join, resolve as resolvePath } from 'path';
|
|
21
|
+
import { projectAiwgPath } from '../config/project-artifacts.js';
|
|
22
|
+
/**
|
|
23
|
+
* Default identity store location — global, host-level. Preserved for
|
|
24
|
+
* backward compatibility when `.aiwg/storage.config` doesn't redirect
|
|
25
|
+
* `sandbox_identity` (#969).
|
|
26
|
+
*/
|
|
27
|
+
const DEFAULT_IDENTITY_STORE_PATH = join(homedir(), '.config', 'aiwg', 'sandbox-agents.json');
|
|
28
|
+
/**
|
|
29
|
+
* Resolve the identity-store path, honoring `roots.sandbox_identity`
|
|
30
|
+
* in `.aiwg/storage.config` when set. Sync read because the sandbox
|
|
31
|
+
* registry constructor is sync and load happens at construction time.
|
|
32
|
+
*
|
|
33
|
+
* Backend support: only `fs` (or absent config) is currently supported
|
|
34
|
+
* for the identity store — non-fs backends would require an async
|
|
35
|
+
* adapter call which doesn't fit the sync constructor. Throws a clear
|
|
36
|
+
* error if the user has configured a non-fs backend for this subsystem.
|
|
37
|
+
*
|
|
38
|
+
* Exported for testing — production callers omit `projectRootOverride`
|
|
39
|
+
* to use `process.cwd()`.
|
|
40
|
+
*
|
|
41
|
+
* @issue #969
|
|
42
|
+
*/
|
|
43
|
+
export function resolveIdentityStorePath(projectRootOverride) {
|
|
44
|
+
// First check env var for tests / one-off overrides
|
|
45
|
+
const envOverride = process.env['AIWG_SANDBOX_IDENTITY_STORE'];
|
|
46
|
+
if (envOverride)
|
|
47
|
+
return envOverride;
|
|
48
|
+
// Try storage.config — sync read of project-local file
|
|
49
|
+
const projectRoot = projectRootOverride ?? process.cwd();
|
|
50
|
+
const configPath = projectAiwgPath(projectRoot, 'storage.config');
|
|
51
|
+
if (!existsSync(configPath))
|
|
52
|
+
return DEFAULT_IDENTITY_STORE_PATH;
|
|
53
|
+
try {
|
|
54
|
+
const raw = readFileSync(configPath, 'utf-8');
|
|
55
|
+
const parsed = JSON.parse(raw);
|
|
56
|
+
if (parsed.version !== '1')
|
|
57
|
+
return DEFAULT_IDENTITY_STORE_PATH;
|
|
58
|
+
// Refuse non-fs backends — sync constructor can't await an adapter
|
|
59
|
+
const backendType = parsed.backends?.['sandbox_identity']?.type;
|
|
60
|
+
if (backendType && backendType !== 'fs') {
|
|
61
|
+
throw new Error(`sandbox-registry: backend "${backendType}" not supported for sandbox_identity ` +
|
|
62
|
+
`(only fs supported in v1; sync load constraint). Configure roots.sandbox_identity ` +
|
|
63
|
+
`to redirect within the fs backend, or remove the backends.sandbox_identity entry.`);
|
|
64
|
+
}
|
|
65
|
+
const override = parsed.roots?.['sandbox_identity'];
|
|
66
|
+
if (override) {
|
|
67
|
+
// Expand ~/ and resolve relative paths against project root
|
|
68
|
+
let resolved = override;
|
|
69
|
+
if (resolved.startsWith('~/'))
|
|
70
|
+
resolved = join(homedir(), resolved.slice(2));
|
|
71
|
+
else if (resolved === '~')
|
|
72
|
+
resolved = homedir();
|
|
73
|
+
else if (!isAbsolute(resolved))
|
|
74
|
+
resolved = resolvePath(projectRoot, resolved);
|
|
75
|
+
// The override is a directory; the legacy file lives inside it
|
|
76
|
+
return join(resolved, 'sandbox-agents.json');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
// Throw on configured-but-unsupported, swallow on parse errors
|
|
81
|
+
if (err instanceof Error && err.message.startsWith('sandbox-registry: backend')) {
|
|
82
|
+
throw err;
|
|
83
|
+
}
|
|
84
|
+
// ignore — fall through to default
|
|
85
|
+
}
|
|
86
|
+
return DEFAULT_IDENTITY_STORE_PATH;
|
|
87
|
+
}
|
|
88
|
+
function loadIdentityStore() {
|
|
89
|
+
const path = resolveIdentityStorePath();
|
|
90
|
+
try {
|
|
91
|
+
if (existsSync(path)) {
|
|
92
|
+
const data = JSON.parse(readFileSync(path, 'utf-8'));
|
|
93
|
+
return new Map(data.map((r) => [r.instanceId, r]));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch { /* ignore parse/read errors */ }
|
|
97
|
+
return new Map();
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Save the identity store atomically: write to a temp file in the same
|
|
101
|
+
* directory, then rename onto the live path. Prevents readers from
|
|
102
|
+
* observing a half-written JSON file under concurrent SIGINT.
|
|
103
|
+
*/
|
|
104
|
+
function saveIdentityStore(store) {
|
|
105
|
+
const path = resolveIdentityStorePath();
|
|
106
|
+
try {
|
|
107
|
+
const dir = dirname(path);
|
|
108
|
+
mkdirSync(dir, { recursive: true });
|
|
109
|
+
const tmp = `${path}.tmp.${process.pid}`;
|
|
110
|
+
writeFileSync(tmp, JSON.stringify([...store.values()], null, 2), 'utf-8');
|
|
111
|
+
try {
|
|
112
|
+
renameSync(tmp, path);
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
// Best-effort cleanup of the temp file
|
|
116
|
+
try {
|
|
117
|
+
unlinkSync(tmp);
|
|
118
|
+
}
|
|
119
|
+
catch { /* ignore */ }
|
|
120
|
+
throw err;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch { /* ignore write errors — non-fatal per existing contract */ }
|
|
124
|
+
}
|
|
125
|
+
/** Convenience helper — returns true if the sandbox advertises a feature flag. */
|
|
126
|
+
export function sandboxHasFeature(reg, feature) {
|
|
127
|
+
return reg.wsCapabilities?.features.includes(feature) ?? false;
|
|
128
|
+
}
|
|
129
|
+
/** Returns true if the sandbox supports a given client message type. */
|
|
130
|
+
export function sandboxSupports(reg, msg) {
|
|
131
|
+
return reg.wsCapabilities?.supported_client_messages.includes(msg) ?? false;
|
|
132
|
+
}
|
|
133
|
+
/** Maximum number of samples kept per agent (#911). ~5 min at 5s interval. */
|
|
134
|
+
export const METRICS_HISTORY_MAX = 60;
|
|
135
|
+
// ============================================================
|
|
136
|
+
// Event normalization (#933)
|
|
137
|
+
// ============================================================
|
|
138
|
+
//
|
|
139
|
+
// agentic-sandbox emits SandboxEvent over WS with Serde's
|
|
140
|
+
// `rename_all = "snake_case"` applied to the enum tag and every field.
|
|
141
|
+
// So the wire payload is:
|
|
142
|
+
//
|
|
143
|
+
// { "type": "agent_connected", "agent_id": "agent-01",
|
|
144
|
+
// "agent_instance_id": "01HX...", "loadout": "base", ... }
|
|
145
|
+
//
|
|
146
|
+
// AIWG's registry switch is written in dot-notation + camelCase
|
|
147
|
+
// (`agent.connected`, `event.agentId`). Before #933, only
|
|
148
|
+
// `session_start`/`session_end` were normalized — every `agent_*`
|
|
149
|
+
// and `hitl_*` event was silently dropped and agents never populated
|
|
150
|
+
// the registry, which is why the dashboard reported "0 agents".
|
|
151
|
+
//
|
|
152
|
+
// normalizeSandboxEvent() maps snake_case event types to the dot
|
|
153
|
+
// notation the switch expects and aliases snake_case top-level fields
|
|
154
|
+
// onto their camelCase twins. Nested payloads (metrics, inventory
|
|
155
|
+
// summaries) are left alone — their consumers already read snake_case
|
|
156
|
+
// keys (e.g. metrics.cpu_percent, AgentManifestSummary.content_hash).
|
|
157
|
+
/** Explicit snake_case → dot-notation map for SandboxEventType. */
|
|
158
|
+
const SNAKE_TO_DOT_EVENT_TYPE = {
|
|
159
|
+
agent_connected: 'agent.connected',
|
|
160
|
+
agent_disconnected: 'agent.disconnected',
|
|
161
|
+
agent_ready: 'agent.ready',
|
|
162
|
+
agent_provisioning: 'agent.provisioning',
|
|
163
|
+
session_start: 'session.start',
|
|
164
|
+
session_end: 'session.end',
|
|
165
|
+
hitl_input_required: 'hitl.input_required',
|
|
166
|
+
hitl_responded: 'hitl.responded',
|
|
167
|
+
hitl_timed_out: 'hitl.timed_out',
|
|
168
|
+
agent_inventory_updated: 'agent.inventory_updated',
|
|
169
|
+
agent_metrics_updated: 'agent.metrics_updated',
|
|
170
|
+
agent_provisioning_step: 'agent.provisioning_step',
|
|
171
|
+
agent_provisioning_stalled: 'agent.provisioning_stalled',
|
|
172
|
+
framework_update_available: 'framework.update_available',
|
|
173
|
+
session_screen_updated: 'session.screen_updated',
|
|
174
|
+
task_submitted: 'task.submitted',
|
|
175
|
+
task_started: 'task.started',
|
|
176
|
+
task_progressed: 'task.progressed',
|
|
177
|
+
task_completed: 'task.completed',
|
|
178
|
+
task_failed: 'task.failed',
|
|
179
|
+
aiwg_log: 'aiwg.log',
|
|
180
|
+
agent_sessions: 'agent.sessions', // sandbox#192 — full session inventory replace (#1155)
|
|
181
|
+
};
|
|
182
|
+
/** Top-level field aliases from snake_case payloads → camelCase view. */
|
|
183
|
+
const SNAKE_TO_CAMEL_FIELDS = {
|
|
184
|
+
agent_id: 'agentId',
|
|
185
|
+
sandbox_id: 'sandboxId',
|
|
186
|
+
session_id: 'sessionId',
|
|
187
|
+
exit_code: 'exitCode',
|
|
188
|
+
hitl_id: 'hitlId',
|
|
189
|
+
agent_instance_id: 'agentInstanceId',
|
|
190
|
+
agent_logical_name: 'agentLogicalName',
|
|
191
|
+
aiwg_frameworks: 'aiwgFrameworks',
|
|
192
|
+
agent_inventory: 'agentInventory',
|
|
193
|
+
command_inventory: 'commandInventory',
|
|
194
|
+
skill_inventory: 'skillInventory',
|
|
195
|
+
step_index: 'stepIndex',
|
|
196
|
+
total_steps: 'totalSteps',
|
|
197
|
+
elapsed_seconds: 'elapsedSeconds',
|
|
198
|
+
stalled_for_seconds: 'stalledForSeconds',
|
|
199
|
+
current_version: 'currentVersion',
|
|
200
|
+
available_version: 'availableVersion',
|
|
201
|
+
days_behind: 'daysBehind',
|
|
202
|
+
screen_hash: 'screenHash',
|
|
203
|
+
changed_lines: 'changedLines',
|
|
204
|
+
task_error: 'taskError',
|
|
205
|
+
output_chunk: 'outputChunk',
|
|
206
|
+
expires_at: 'expiresAt',
|
|
207
|
+
};
|
|
208
|
+
/**
|
|
209
|
+
* Normalize a raw sandbox event payload into the camelCase + dot-notation
|
|
210
|
+
* shape `handleEvent` expects. Accepts payloads in either the legacy
|
|
211
|
+
* snake_case or the newer dot/camelCase shape and is idempotent on the
|
|
212
|
+
* latter, so it is safe to pipe every inbound event through this helper.
|
|
213
|
+
*/
|
|
214
|
+
export function normalizeSandboxEvent(raw) {
|
|
215
|
+
if (!raw || typeof raw !== 'object') {
|
|
216
|
+
// Malformed payload — callers discard anything that fails the switch.
|
|
217
|
+
return { type: 'aiwg.log', sandboxId: '', agentId: '', timestamp: new Date().toISOString() };
|
|
218
|
+
}
|
|
219
|
+
const src = raw;
|
|
220
|
+
const rawType = typeof src.type === 'string' ? src.type : '';
|
|
221
|
+
const type = (SNAKE_TO_DOT_EVENT_TYPE[rawType] ?? rawType);
|
|
222
|
+
// Copy every field onto the output, aliasing snake_case top-level keys
|
|
223
|
+
// to their camelCase equivalents when the camelCase key is not already set.
|
|
224
|
+
const out = { ...src, type };
|
|
225
|
+
for (const [snake, camel] of Object.entries(SNAKE_TO_CAMEL_FIELDS)) {
|
|
226
|
+
if (snake in src && out[camel] === undefined) {
|
|
227
|
+
out[camel] = src[snake];
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
// Ensure timestamp is always ISO string for downstream consumers.
|
|
231
|
+
if (typeof out.timestamp !== 'string') {
|
|
232
|
+
out.timestamp = new Date().toISOString();
|
|
233
|
+
}
|
|
234
|
+
return out;
|
|
235
|
+
}
|
|
236
|
+
// ============================================================
|
|
237
|
+
// Registry
|
|
238
|
+
// ============================================================
|
|
239
|
+
/**
|
|
240
|
+
* Debounce window for re-registrations from the same instance_id.
|
|
241
|
+
* Matches the sandbox's 5 s retry interval — suppressess flicker on rapid restarts.
|
|
242
|
+
*/
|
|
243
|
+
const DEBOUNCE_MS = 5_000;
|
|
244
|
+
export class SandboxRegistry {
|
|
245
|
+
sandboxes = new Map();
|
|
246
|
+
hitlRequests = new Map();
|
|
247
|
+
listeners = new Set();
|
|
248
|
+
/** instance_id → sandbox_id (stable reverse-lookup for sandbox upsert) */
|
|
249
|
+
byInstanceId = new Map();
|
|
250
|
+
/** instance_id → last registration timestamp (ms, for debounce) */
|
|
251
|
+
lastRegistrationTime = new Map();
|
|
252
|
+
/** Timer for HITL expiry checks (#908) */
|
|
253
|
+
expiryTimer = null;
|
|
254
|
+
/** agentInstanceId → { sandboxId, agentId } — cross-restart lookup (#917) */
|
|
255
|
+
byAgentInstanceId = new Map();
|
|
256
|
+
/** logicalName → { sandboxId, agentId } — human-readable alias lookup (#917) */
|
|
257
|
+
byLogicalName = new Map();
|
|
258
|
+
/** Persistent store: agentInstanceId → identity record (#917) */
|
|
259
|
+
identityStore;
|
|
260
|
+
constructor() {
|
|
261
|
+
// Check for expired HITL requests every 60 seconds (#908)
|
|
262
|
+
this.expiryTimer = setInterval(() => this.checkHitlExpiry(), 60_000);
|
|
263
|
+
// Load persistent agent identity from disk (#917)
|
|
264
|
+
this.identityStore = loadIdentityStore();
|
|
265
|
+
// Restore logical names from persisted store
|
|
266
|
+
for (const record of this.identityStore.values()) {
|
|
267
|
+
if (record.logicalName) {
|
|
268
|
+
// Will be indexed properly when agent reconnects; logical names are
|
|
269
|
+
// pre-loaded so aliasAgent() calls can reference them immediately.
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
checkHitlExpiry() {
|
|
274
|
+
const now = new Date().toISOString();
|
|
275
|
+
for (const [hitlId, req] of this.hitlRequests) {
|
|
276
|
+
if (req.expiresAt && req.expiresAt <= now) {
|
|
277
|
+
this.hitlRequests.delete(hitlId);
|
|
278
|
+
this.emit({
|
|
279
|
+
type: 'hitl.timed_out',
|
|
280
|
+
sandboxId: req.sandboxId,
|
|
281
|
+
agentId: req.agentId,
|
|
282
|
+
timestamp: new Date().toISOString(),
|
|
283
|
+
hitlId,
|
|
284
|
+
sessionId: req.sessionId,
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Register a sandbox instance.
|
|
291
|
+
*
|
|
292
|
+
* When the request includes a stable `instance_id`:
|
|
293
|
+
* - **Debounce**: if a registration for the same instance_id arrived within
|
|
294
|
+
* DEBOUNCE_MS, return the existing sandbox_id + token without touching state.
|
|
295
|
+
* - **Upsert**: if outside the debounce window, update the existing entry's
|
|
296
|
+
* endpoints, version, and lastRegisteredAt in-place. The sandbox_id and token
|
|
297
|
+
* are preserved so in-flight WS connections stay authenticated.
|
|
298
|
+
*
|
|
299
|
+
* When no instance_id is provided, a new entry is always created (legacy behaviour).
|
|
300
|
+
*/
|
|
301
|
+
register(req) {
|
|
302
|
+
const instanceId = req.instance_id;
|
|
303
|
+
const now = Date.now();
|
|
304
|
+
if (instanceId) {
|
|
305
|
+
const lastTime = this.lastRegistrationTime.get(instanceId);
|
|
306
|
+
const existingId = this.byInstanceId.get(instanceId);
|
|
307
|
+
// Debounce: suppress rapid re-registrations within the window
|
|
308
|
+
if (lastTime !== undefined && (now - lastTime) < DEBOUNCE_MS && existingId) {
|
|
309
|
+
const existing = this.sandboxes.get(existingId);
|
|
310
|
+
if (existing) {
|
|
311
|
+
return { sandbox_id: existingId, token: existing.token };
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
// Upsert: same instance, update endpoints in-place
|
|
315
|
+
if (existingId) {
|
|
316
|
+
const existing = this.sandboxes.get(existingId);
|
|
317
|
+
if (existing) {
|
|
318
|
+
existing.name = req.name;
|
|
319
|
+
existing.grpcEndpoint = req.grpc_endpoint;
|
|
320
|
+
existing.wsEndpoint = req.ws_endpoint;
|
|
321
|
+
existing.httpEndpoint = req.http_endpoint;
|
|
322
|
+
existing.capabilities = req.capabilities ?? existing.capabilities;
|
|
323
|
+
existing.version = req.version ?? existing.version;
|
|
324
|
+
existing.lastRegisteredAt = new Date().toISOString();
|
|
325
|
+
existing.connected = false; // WS will update this when it (re-)connects
|
|
326
|
+
// Refresh sandbox-level inventory if provided (#906)
|
|
327
|
+
if (req.agent_inventory || req.command_inventory || req.skill_inventory) {
|
|
328
|
+
existing.sandboxInventory = {
|
|
329
|
+
agents: req.agent_inventory ?? existing.sandboxInventory?.agents ?? [],
|
|
330
|
+
commands: req.command_inventory ?? existing.sandboxInventory?.commands ?? [],
|
|
331
|
+
skills: req.skill_inventory ?? existing.sandboxInventory?.skills ?? [],
|
|
332
|
+
last_updated: new Date().toISOString(),
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
// Refresh WS capabilities if provided (#912)
|
|
336
|
+
if (req.ws_capabilities) {
|
|
337
|
+
existing.wsCapabilities = req.ws_capabilities;
|
|
338
|
+
}
|
|
339
|
+
this.lastRegistrationTime.set(instanceId, now);
|
|
340
|
+
return { sandbox_id: existingId, token: existing.token };
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
// New registration (no instance_id, or first time seeing this instance_id)
|
|
345
|
+
const id = `sandbox-${randomUUID().slice(0, 8)}`;
|
|
346
|
+
const token = randomUUID();
|
|
347
|
+
const now_iso = new Date().toISOString();
|
|
348
|
+
const sandboxInventory = (req.agent_inventory || req.command_inventory || req.skill_inventory)
|
|
349
|
+
? {
|
|
350
|
+
agents: req.agent_inventory ?? [],
|
|
351
|
+
commands: req.command_inventory ?? [],
|
|
352
|
+
skills: req.skill_inventory ?? [],
|
|
353
|
+
last_updated: now_iso,
|
|
354
|
+
}
|
|
355
|
+
: undefined;
|
|
356
|
+
const registration = {
|
|
357
|
+
id,
|
|
358
|
+
name: req.name,
|
|
359
|
+
instanceId,
|
|
360
|
+
grpcEndpoint: req.grpc_endpoint,
|
|
361
|
+
wsEndpoint: req.ws_endpoint,
|
|
362
|
+
httpEndpoint: req.http_endpoint,
|
|
363
|
+
capabilities: req.capabilities ?? [],
|
|
364
|
+
version: req.version ?? 'unknown',
|
|
365
|
+
token,
|
|
366
|
+
registeredAt: now_iso,
|
|
367
|
+
lastRegisteredAt: now_iso,
|
|
368
|
+
lastEventAt: now_iso,
|
|
369
|
+
connected: false,
|
|
370
|
+
agents: new Map(),
|
|
371
|
+
sandboxInventory,
|
|
372
|
+
wsCapabilities: req.ws_capabilities,
|
|
373
|
+
};
|
|
374
|
+
this.sandboxes.set(id, registration);
|
|
375
|
+
if (instanceId) {
|
|
376
|
+
this.byInstanceId.set(instanceId, id);
|
|
377
|
+
this.lastRegistrationTime.set(instanceId, now);
|
|
378
|
+
}
|
|
379
|
+
return { sandbox_id: id, token };
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Remove all disconnected sandboxes from the registry.
|
|
383
|
+
* Forces re-registration on next sandbox startup.
|
|
384
|
+
* Returns the number of entries removed.
|
|
385
|
+
*/
|
|
386
|
+
clearOffline() {
|
|
387
|
+
const toRemove = [];
|
|
388
|
+
for (const [id, sandbox] of this.sandboxes) {
|
|
389
|
+
if (!sandbox.connected)
|
|
390
|
+
toRemove.push(id);
|
|
391
|
+
}
|
|
392
|
+
for (const id of toRemove) {
|
|
393
|
+
this.deregister(id);
|
|
394
|
+
}
|
|
395
|
+
return toRemove.length;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Deregister a sandbox (on shutdown or explicit delete).
|
|
399
|
+
*/
|
|
400
|
+
deregister(id) {
|
|
401
|
+
const sandbox = this.sandboxes.get(id);
|
|
402
|
+
if (sandbox?.instanceId) {
|
|
403
|
+
this.byInstanceId.delete(sandbox.instanceId);
|
|
404
|
+
this.lastRegistrationTime.delete(sandbox.instanceId);
|
|
405
|
+
}
|
|
406
|
+
return this.sandboxes.delete(id);
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Get a sandbox by ID.
|
|
410
|
+
*/
|
|
411
|
+
get(id) {
|
|
412
|
+
return this.sandboxes.get(id);
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Validate the auth token for a sandbox.
|
|
416
|
+
*/
|
|
417
|
+
authenticate(id, token) {
|
|
418
|
+
const sandbox = this.sandboxes.get(id);
|
|
419
|
+
return sandbox !== undefined && sandbox.token === token;
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Mark the event push WebSocket as connected/disconnected.
|
|
423
|
+
*/
|
|
424
|
+
setConnected(id, connected) {
|
|
425
|
+
const sandbox = this.sandboxes.get(id);
|
|
426
|
+
if (!sandbox)
|
|
427
|
+
return;
|
|
428
|
+
sandbox.connected = connected;
|
|
429
|
+
if (!connected)
|
|
430
|
+
sandbox.disconnectedAt = new Date().toISOString();
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* List all registered sandboxes (serializable).
|
|
434
|
+
*/
|
|
435
|
+
list() {
|
|
436
|
+
return [...this.sandboxes.values()].map(toSummary);
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Get a sandbox summary by ID (serializable).
|
|
440
|
+
*/
|
|
441
|
+
getSummary(id) {
|
|
442
|
+
const sandbox = this.sandboxes.get(id);
|
|
443
|
+
return sandbox ? toSummary(sandbox) : undefined;
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Process an event pushed from a sandbox.
|
|
447
|
+
* Updates internal agent inventory and notifies listeners.
|
|
448
|
+
*/
|
|
449
|
+
handleEvent(event) {
|
|
450
|
+
const sandbox = this.sandboxes.get(event.sandboxId);
|
|
451
|
+
if (!sandbox)
|
|
452
|
+
return;
|
|
453
|
+
sandbox.lastEventAt = event.timestamp || new Date().toISOString();
|
|
454
|
+
// Normalize the two underscore variants the sandbox emits for session events.
|
|
455
|
+
// Other event types (agent.connected, hitl.input_required, etc.) use dot notation
|
|
456
|
+
// already and must not be altered.
|
|
457
|
+
const rawType = event.type;
|
|
458
|
+
const eventType = (rawType === 'session_start' ? 'session.start'
|
|
459
|
+
: rawType === 'session_end' ? 'session.end'
|
|
460
|
+
: rawType);
|
|
461
|
+
// Update agent inventory based on event type
|
|
462
|
+
switch (eventType) {
|
|
463
|
+
case 'agent.connected': {
|
|
464
|
+
// Resolve persistent logical name from identity store (#917)
|
|
465
|
+
const agentInstanceId = event.agentInstanceId;
|
|
466
|
+
let logicalName = event.agentLogicalName;
|
|
467
|
+
if (agentInstanceId) {
|
|
468
|
+
const record = this.identityStore.get(agentInstanceId);
|
|
469
|
+
if (record) {
|
|
470
|
+
logicalName = logicalName ?? record.logicalName;
|
|
471
|
+
// Update record with current location
|
|
472
|
+
record.lastAgentId = event.agentId;
|
|
473
|
+
record.lastSandboxId = event.sandboxId;
|
|
474
|
+
record.lastSeenAt = event.timestamp;
|
|
475
|
+
if (!record.logicalName && logicalName)
|
|
476
|
+
record.logicalName = logicalName;
|
|
477
|
+
}
|
|
478
|
+
else {
|
|
479
|
+
this.identityStore.set(agentInstanceId, {
|
|
480
|
+
instanceId: agentInstanceId,
|
|
481
|
+
logicalName,
|
|
482
|
+
lastAgentId: event.agentId,
|
|
483
|
+
lastSandboxId: event.sandboxId,
|
|
484
|
+
lastSeenAt: event.timestamp,
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
saveIdentityStore(this.identityStore);
|
|
488
|
+
this.byAgentInstanceId.set(agentInstanceId, { sandboxId: event.sandboxId, agentId: event.agentId });
|
|
489
|
+
}
|
|
490
|
+
if (logicalName) {
|
|
491
|
+
this.byLogicalName.set(logicalName, { sandboxId: event.sandboxId, agentId: event.agentId });
|
|
492
|
+
}
|
|
493
|
+
sandbox.agents.set(event.agentId, {
|
|
494
|
+
agentId: event.agentId,
|
|
495
|
+
status: 'ready',
|
|
496
|
+
loadout: event.loadout,
|
|
497
|
+
aiwgFrameworks: event.aiwgFrameworks,
|
|
498
|
+
connectedAt: event.timestamp,
|
|
499
|
+
lastHeartbeat: event.timestamp,
|
|
500
|
+
instanceId: agentInstanceId,
|
|
501
|
+
logicalName,
|
|
502
|
+
});
|
|
503
|
+
break;
|
|
504
|
+
}
|
|
505
|
+
case 'agent.disconnected': {
|
|
506
|
+
const agent = sandbox.agents.get(event.agentId);
|
|
507
|
+
if (agent)
|
|
508
|
+
agent.status = 'disconnected';
|
|
509
|
+
break;
|
|
510
|
+
}
|
|
511
|
+
case 'agent.provisioning': {
|
|
512
|
+
sandbox.agents.set(event.agentId, {
|
|
513
|
+
agentId: event.agentId,
|
|
514
|
+
status: 'provisioning',
|
|
515
|
+
loadout: event.loadout,
|
|
516
|
+
lastHeartbeat: event.timestamp,
|
|
517
|
+
});
|
|
518
|
+
break;
|
|
519
|
+
}
|
|
520
|
+
case 'agent.ready': {
|
|
521
|
+
const existing = sandbox.agents.get(event.agentId);
|
|
522
|
+
if (existing) {
|
|
523
|
+
existing.status = 'ready';
|
|
524
|
+
existing.lastHeartbeat = event.timestamp;
|
|
525
|
+
}
|
|
526
|
+
break;
|
|
527
|
+
}
|
|
528
|
+
case 'session.start': {
|
|
529
|
+
const agent = sandbox.agents.get(event.agentId);
|
|
530
|
+
if (agent) {
|
|
531
|
+
agent.status = 'busy';
|
|
532
|
+
agent.sessionCount = (agent.sessionCount ?? 0) + 1;
|
|
533
|
+
agent.lastHeartbeat = event.timestamp;
|
|
534
|
+
}
|
|
535
|
+
break;
|
|
536
|
+
}
|
|
537
|
+
case 'session.end': {
|
|
538
|
+
const agent = sandbox.agents.get(event.agentId);
|
|
539
|
+
if (agent) {
|
|
540
|
+
if (agent.status === 'busy')
|
|
541
|
+
agent.status = 'ready';
|
|
542
|
+
if (agent.sessionCount)
|
|
543
|
+
agent.sessionCount = Math.max(0, agent.sessionCount - 1);
|
|
544
|
+
agent.lastHeartbeat = event.timestamp;
|
|
545
|
+
}
|
|
546
|
+
break;
|
|
547
|
+
}
|
|
548
|
+
case 'agent.sessions': {
|
|
549
|
+
// Full inventory replace (#1151). The sandbox is authoritative for
|
|
550
|
+
// session state — replacing wholesale (rather than merging) means a
|
|
551
|
+
// missed session.start / session.end can't permanently desync the
|
|
552
|
+
// count. sessionCount is also resynced from the new array length so
|
|
553
|
+
// the legacy approximate-count consumers stay accurate.
|
|
554
|
+
const agent = sandbox.agents.get(event.agentId);
|
|
555
|
+
if (agent && Array.isArray(event.sessions)) {
|
|
556
|
+
agent.sessions = event.sessions;
|
|
557
|
+
agent.sessionCount = event.sessions.length;
|
|
558
|
+
agent.lastHeartbeat = event.timestamp;
|
|
559
|
+
}
|
|
560
|
+
break;
|
|
561
|
+
}
|
|
562
|
+
case 'hitl.input_required': {
|
|
563
|
+
if (event.hitlId && event.sessionId) {
|
|
564
|
+
this.hitlRequests.set(event.hitlId, {
|
|
565
|
+
id: event.hitlId,
|
|
566
|
+
sandboxId: event.sandboxId,
|
|
567
|
+
agentId: event.agentId,
|
|
568
|
+
sessionId: event.sessionId,
|
|
569
|
+
timestamp: event.timestamp,
|
|
570
|
+
prompt: event.prompt ?? '',
|
|
571
|
+
context: event.context ?? '',
|
|
572
|
+
expiresAt: event.expiresAt,
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
break;
|
|
576
|
+
}
|
|
577
|
+
case 'agent.inventory_updated': {
|
|
578
|
+
// Update the agent's manifest inventory (#906)
|
|
579
|
+
const agent = sandbox.agents.get(event.agentId);
|
|
580
|
+
if (agent && (event.agentInventory || event.commandInventory || event.skillInventory)) {
|
|
581
|
+
agent.inventory = {
|
|
582
|
+
agents: event.agentInventory ?? agent.inventory?.agents ?? [],
|
|
583
|
+
commands: event.commandInventory ?? agent.inventory?.commands ?? [],
|
|
584
|
+
skills: event.skillInventory ?? agent.inventory?.skills ?? [],
|
|
585
|
+
last_updated: event.timestamp,
|
|
586
|
+
};
|
|
587
|
+
agent.lastHeartbeat = event.timestamp;
|
|
588
|
+
}
|
|
589
|
+
break;
|
|
590
|
+
}
|
|
591
|
+
case 'agent.metrics_updated': {
|
|
592
|
+
// Store latest metrics + rolling history (#911)
|
|
593
|
+
if (event.metrics) {
|
|
594
|
+
const agent = sandbox.agents.get(event.agentId);
|
|
595
|
+
if (agent) {
|
|
596
|
+
agent.latestMetrics = event.metrics;
|
|
597
|
+
const sample = {
|
|
598
|
+
cpu_percent: event.metrics.cpu_percent,
|
|
599
|
+
memory_percent: event.metrics.memory_total_bytes > 0
|
|
600
|
+
? (event.metrics.memory_used_bytes / event.metrics.memory_total_bytes) * 100
|
|
601
|
+
: 0,
|
|
602
|
+
ts: event.metrics.ts,
|
|
603
|
+
};
|
|
604
|
+
if (!agent.metricsHistory)
|
|
605
|
+
agent.metricsHistory = [];
|
|
606
|
+
agent.metricsHistory.push(sample);
|
|
607
|
+
if (agent.metricsHistory.length > METRICS_HISTORY_MAX) {
|
|
608
|
+
agent.metricsHistory = agent.metricsHistory.slice(-METRICS_HISTORY_MAX);
|
|
609
|
+
}
|
|
610
|
+
agent.lastHeartbeat = event.timestamp;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
break;
|
|
614
|
+
}
|
|
615
|
+
case 'agent.provisioning_step': {
|
|
616
|
+
// Store current provisioning step (#911)
|
|
617
|
+
const agent = sandbox.agents.get(event.agentId);
|
|
618
|
+
if (agent && event.step) {
|
|
619
|
+
agent.provisioningStep = {
|
|
620
|
+
step: event.step,
|
|
621
|
+
step_index: event.stepIndex,
|
|
622
|
+
total_steps: event.totalSteps,
|
|
623
|
+
elapsed_seconds: event.elapsedSeconds,
|
|
624
|
+
ts: event.timestamp,
|
|
625
|
+
};
|
|
626
|
+
agent.provisioningStalled = false;
|
|
627
|
+
agent.lastHeartbeat = event.timestamp;
|
|
628
|
+
}
|
|
629
|
+
break;
|
|
630
|
+
}
|
|
631
|
+
case 'agent.provisioning_stalled': {
|
|
632
|
+
// Mark provisioning as stalled (#911)
|
|
633
|
+
const agent = sandbox.agents.get(event.agentId);
|
|
634
|
+
if (agent) {
|
|
635
|
+
agent.provisioningStalled = true;
|
|
636
|
+
agent.lastHeartbeat = event.timestamp;
|
|
637
|
+
}
|
|
638
|
+
break;
|
|
639
|
+
}
|
|
640
|
+
// Task lifecycle events — no local state update, listeners handle display (#907)
|
|
641
|
+
case 'task.submitted':
|
|
642
|
+
case 'task.started':
|
|
643
|
+
case 'task.progressed':
|
|
644
|
+
case 'task.completed':
|
|
645
|
+
case 'task.failed':
|
|
646
|
+
// Pass-through events — no AIWG state to update (#910 #913 #914)
|
|
647
|
+
case 'framework.update_available':
|
|
648
|
+
case 'session.screen_updated':
|
|
649
|
+
case 'aiwg.log':
|
|
650
|
+
// Synthetic HITL events — emitted by aiwg serve, no state to update (#908)
|
|
651
|
+
case 'hitl.responded':
|
|
652
|
+
case 'hitl.timed_out':
|
|
653
|
+
break;
|
|
654
|
+
default: {
|
|
655
|
+
// Unknown event type — likely a wire-protocol drift between
|
|
656
|
+
// agentic-sandbox and AIWG. See #933 for the snake_case fix that
|
|
657
|
+
// started tracking this. Log so future mismatches surface loudly
|
|
658
|
+
// instead of silently dropping dashboard state.
|
|
659
|
+
if (process.env.AIWG_SERVE_DEBUG === '1') {
|
|
660
|
+
console.warn(`[sandbox-registry] unknown event type "${String(eventType)}" from sandbox ${event.sandboxId} — ignored. Payload keys:`, Object.keys(event));
|
|
661
|
+
}
|
|
662
|
+
break;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
// Notify listeners (browser push, telemetry, etc.)
|
|
666
|
+
this.emit(event);
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* Emit a synthetic event to all listeners without modifying internal state.
|
|
670
|
+
* Used by serve.ts to push server-side events (e.g. hitl.responded) to the browser.
|
|
671
|
+
*/
|
|
672
|
+
emit(event) {
|
|
673
|
+
for (const listener of this.listeners) {
|
|
674
|
+
try {
|
|
675
|
+
listener(event);
|
|
676
|
+
}
|
|
677
|
+
catch { /* ignore listener errors */ }
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
/**
|
|
681
|
+
* Get all agents across all sandboxes.
|
|
682
|
+
*/
|
|
683
|
+
allAgents() {
|
|
684
|
+
const result = [];
|
|
685
|
+
for (const sandbox of this.sandboxes.values()) {
|
|
686
|
+
for (const agent of sandbox.agents.values()) {
|
|
687
|
+
result.push({ ...agent, sandboxId: sandbox.id, sandboxName: sandbox.name });
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
return result;
|
|
691
|
+
}
|
|
692
|
+
/**
|
|
693
|
+
* Resolve an agent reference by agentId → instanceId → logicalName (#917).
|
|
694
|
+
* Returns the sandbox registration and agent, or undefined if not found.
|
|
695
|
+
*/
|
|
696
|
+
resolveAgent(ref) {
|
|
697
|
+
// 1. Direct agentId lookup
|
|
698
|
+
for (const sandbox of this.sandboxes.values()) {
|
|
699
|
+
const agent = sandbox.agents.get(ref);
|
|
700
|
+
if (agent)
|
|
701
|
+
return { sandbox, agent };
|
|
702
|
+
}
|
|
703
|
+
// 2. agentInstanceId lookup
|
|
704
|
+
const byInstance = this.byAgentInstanceId.get(ref);
|
|
705
|
+
if (byInstance) {
|
|
706
|
+
const sandbox = this.sandboxes.get(byInstance.sandboxId);
|
|
707
|
+
const agent = sandbox?.agents.get(byInstance.agentId);
|
|
708
|
+
if (sandbox && agent)
|
|
709
|
+
return { sandbox, agent };
|
|
710
|
+
}
|
|
711
|
+
// 3. logicalName lookup
|
|
712
|
+
const byName = this.byLogicalName.get(ref);
|
|
713
|
+
if (byName) {
|
|
714
|
+
const sandbox = this.sandboxes.get(byName.sandboxId);
|
|
715
|
+
const agent = sandbox?.agents.get(byName.agentId);
|
|
716
|
+
if (sandbox && agent)
|
|
717
|
+
return { sandbox, agent };
|
|
718
|
+
}
|
|
719
|
+
return undefined;
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* Assign a stable logical name to an agent (#917).
|
|
723
|
+
* Persists the mapping to ~/.config/aiwg/sandbox-agents.json.
|
|
724
|
+
*/
|
|
725
|
+
aliasAgent(sandboxId, agentId, logicalName) {
|
|
726
|
+
const sandbox = this.sandboxes.get(sandboxId);
|
|
727
|
+
const agent = sandbox?.agents.get(agentId);
|
|
728
|
+
if (!sandbox || !agent)
|
|
729
|
+
return false;
|
|
730
|
+
// Remove old logical name index if any
|
|
731
|
+
if (agent.logicalName && agent.logicalName !== logicalName) {
|
|
732
|
+
this.byLogicalName.delete(agent.logicalName);
|
|
733
|
+
}
|
|
734
|
+
agent.logicalName = logicalName;
|
|
735
|
+
this.byLogicalName.set(logicalName, { sandboxId, agentId });
|
|
736
|
+
// Persist to store
|
|
737
|
+
const instanceId = agent.instanceId;
|
|
738
|
+
if (instanceId) {
|
|
739
|
+
const record = this.identityStore.get(instanceId) ?? {
|
|
740
|
+
instanceId,
|
|
741
|
+
lastAgentId: agentId,
|
|
742
|
+
lastSandboxId: sandboxId,
|
|
743
|
+
lastSeenAt: new Date().toISOString(),
|
|
744
|
+
};
|
|
745
|
+
record.logicalName = logicalName;
|
|
746
|
+
this.identityStore.set(instanceId, record);
|
|
747
|
+
saveIdentityStore(this.identityStore);
|
|
748
|
+
}
|
|
749
|
+
return true;
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* List known agent identities from the persistent store (#917).
|
|
753
|
+
*/
|
|
754
|
+
knownAgentIdentities() {
|
|
755
|
+
return [...this.identityStore.values()];
|
|
756
|
+
}
|
|
757
|
+
// ---- HITL ----
|
|
758
|
+
/**
|
|
759
|
+
* List pending HITL requests.
|
|
760
|
+
*/
|
|
761
|
+
pendingHitl() {
|
|
762
|
+
return [...this.hitlRequests.values()];
|
|
763
|
+
}
|
|
764
|
+
/**
|
|
765
|
+
* Get a specific HITL request.
|
|
766
|
+
*/
|
|
767
|
+
getHitl(hitlId) {
|
|
768
|
+
return this.hitlRequests.get(hitlId);
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* Remove a HITL request (after response or dismissal).
|
|
772
|
+
*/
|
|
773
|
+
resolveHitl(hitlId) {
|
|
774
|
+
const req = this.hitlRequests.get(hitlId);
|
|
775
|
+
this.hitlRequests.delete(hitlId);
|
|
776
|
+
return req;
|
|
777
|
+
}
|
|
778
|
+
// ---- Event subscription ----
|
|
779
|
+
/**
|
|
780
|
+
* Subscribe to sandbox events (returns unsubscribe fn).
|
|
781
|
+
*/
|
|
782
|
+
subscribe(listener) {
|
|
783
|
+
this.listeners.add(listener);
|
|
784
|
+
return () => { this.listeners.delete(listener); };
|
|
785
|
+
}
|
|
786
|
+
/**
|
|
787
|
+
* Total registered sandbox count.
|
|
788
|
+
*/
|
|
789
|
+
get size() {
|
|
790
|
+
return this.sandboxes.size;
|
|
791
|
+
}
|
|
792
|
+
/**
|
|
793
|
+
* Shut down — clear all state and stop background timers.
|
|
794
|
+
*/
|
|
795
|
+
shutdown() {
|
|
796
|
+
if (this.expiryTimer !== null) {
|
|
797
|
+
clearInterval(this.expiryTimer);
|
|
798
|
+
this.expiryTimer = null;
|
|
799
|
+
}
|
|
800
|
+
this.sandboxes.clear();
|
|
801
|
+
this.hitlRequests.clear();
|
|
802
|
+
this.listeners.clear();
|
|
803
|
+
this.byInstanceId.clear();
|
|
804
|
+
this.lastRegistrationTime.clear();
|
|
805
|
+
this.byAgentInstanceId.clear();
|
|
806
|
+
this.byLogicalName.clear();
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
function toSummary(s) {
|
|
810
|
+
return {
|
|
811
|
+
id: s.id,
|
|
812
|
+
instanceId: s.instanceId,
|
|
813
|
+
name: s.name,
|
|
814
|
+
grpcEndpoint: s.grpcEndpoint,
|
|
815
|
+
wsEndpoint: s.wsEndpoint,
|
|
816
|
+
httpEndpoint: s.httpEndpoint,
|
|
817
|
+
capabilities: s.capabilities,
|
|
818
|
+
version: s.version,
|
|
819
|
+
registeredAt: s.registeredAt,
|
|
820
|
+
lastRegisteredAt: s.lastRegisteredAt,
|
|
821
|
+
lastEventAt: s.lastEventAt,
|
|
822
|
+
connected: s.connected,
|
|
823
|
+
disconnectedAt: s.disconnectedAt,
|
|
824
|
+
agentCount: s.agents.size,
|
|
825
|
+
agents: [...s.agents.values()],
|
|
826
|
+
sandboxInventory: s.sandboxInventory,
|
|
827
|
+
wsCapabilities: s.wsCapabilities,
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
// Singleton instance
|
|
831
|
+
export const sandboxRegistry = new SandboxRegistry();
|
|
832
|
+
//# sourceMappingURL=sandbox-registry.js.map
|