scene-capability-engine 3.0.0
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/CHANGELOG.md +2513 -0
- package/LICENSE +21 -0
- package/README.md +765 -0
- package/README.zh.md +630 -0
- package/bin/kiro-spec-engine.js +796 -0
- package/bin/kse.js +3 -0
- package/bin/sce.js +3 -0
- package/bin/sco.js +3 -0
- package/docs/331-poc-adaptation-roadmap.md +156 -0
- package/docs/331-poc-dual-track-integration-guide.md +120 -0
- package/docs/331-poc-weekly-delivery-checklist.md +52 -0
- package/docs/OFFLINE_INSTALL.md +96 -0
- package/docs/README.md +279 -0
- package/docs/adopt-migration-guide.md +599 -0
- package/docs/adoption-guide.md +616 -0
- package/docs/agent-hooks-analysis.md +815 -0
- package/docs/architecture.md +733 -0
- package/docs/articles/ai-driven-development-philosophy-and-practice-review.md +208 -0
- package/docs/articles/ai-driven-development-philosophy-and-practice.en.md +459 -0
- package/docs/articles/ai-driven-development-philosophy-and-practice.md +492 -0
- package/docs/autonomous-control-guide.md +851 -0
- package/docs/command-reference.md +1368 -0
- package/docs/community.md +115 -0
- package/docs/cross-tool-guide.md +555 -0
- package/docs/developer-guide.md +619 -0
- package/docs/document-governance.md +865 -0
- package/docs/environment-management-guide.md +526 -0
- package/docs/examples/add-export-command/design.md +194 -0
- package/docs/examples/add-export-command/requirements.md +110 -0
- package/docs/examples/add-export-command/tasks.md +88 -0
- package/docs/examples/add-rest-api/design.md +855 -0
- package/docs/examples/add-rest-api/requirements.md +323 -0
- package/docs/examples/add-rest-api/tasks.md +355 -0
- package/docs/examples/add-user-dashboard/design.md +192 -0
- package/docs/examples/add-user-dashboard/requirements.md +143 -0
- package/docs/examples/add-user-dashboard/tasks.md +91 -0
- package/docs/faq.md +697 -0
- package/docs/handoffs/evidence/ontology/moqui-template-baseline-2026-02-17-232922.json +156 -0
- package/docs/handoffs/evidence/ontology/moqui-template-baseline-2026-02-17-232922.md +24 -0
- package/docs/images/wechat-qr.png +0 -0
- package/docs/integration-modes.md +529 -0
- package/docs/integration-philosophy.md +313 -0
- package/docs/knowledge-management-guide.md +263 -0
- package/docs/manual-workflows-guide.md +418 -0
- package/docs/moqui-capability-matrix.md +73 -0
- package/docs/moqui-template-core-library-playbook.md +109 -0
- package/docs/multi-agent-coordination-guide.md +553 -0
- package/docs/multi-repo-management-guide.md +1344 -0
- package/docs/quick-start-with-ai-tools.md +375 -0
- package/docs/quick-start.md +146 -0
- package/docs/release-checklist.md +121 -0
- package/docs/releases/README.md +13 -0
- package/docs/releases/v1.46.2-validation.md +45 -0
- package/docs/releases/v1.46.2.md +50 -0
- package/docs/scene-runtime-guide.md +347 -0
- package/docs/spec-collaboration-guide.md +369 -0
- package/docs/spec-locking-guide.md +225 -0
- package/docs/spec-numbering-guide.md +348 -0
- package/docs/spec-workflow.md +519 -0
- package/docs/steering-strategy-guide.md +196 -0
- package/docs/team-collaboration-guide.md +465 -0
- package/docs/testing-strategy.md +272 -0
- package/docs/tools/claude-guide.md +654 -0
- package/docs/tools/cursor-guide.md +706 -0
- package/docs/tools/generic-guide.md +446 -0
- package/docs/tools/kiro-guide.md +308 -0
- package/docs/tools/vscode-guide.md +445 -0
- package/docs/tools/windsurf-guide.md +391 -0
- package/docs/troubleshooting.md +1135 -0
- package/docs/upgrade-guide.md +639 -0
- package/docs/value-observability-guide.md +127 -0
- package/docs/zh/README.md +341 -0
- package/docs/zh/quick-start.md +764 -0
- package/docs/zh/release-checklist.md +121 -0
- package/docs/zh/releases/README.md +13 -0
- package/docs/zh/releases/v1.46.2-validation.md +45 -0
- package/docs/zh/releases/v1.46.2.md +50 -0
- package/docs/zh/spec-numbering-guide.md +348 -0
- package/docs/zh/tools/claude-guide.md +349 -0
- package/docs/zh/tools/cursor-guide.md +281 -0
- package/docs/zh/tools/generic-guide.md +499 -0
- package/docs/zh/tools/kiro-guide.md +342 -0
- package/docs/zh/tools/vscode-guide.md +449 -0
- package/docs/zh/tools/windsurf-guide.md +378 -0
- package/docs/zh/value-observability-guide.md +127 -0
- package/docs//344/272/244/344/273/230/346/270/205/345/215/225.md +75 -0
- package/lib/adoption/adoption-logger.js +487 -0
- package/lib/adoption/adoption-strategy.js +538 -0
- package/lib/adoption/backup-manager.js +420 -0
- package/lib/adoption/conflict-resolver.js +410 -0
- package/lib/adoption/detection-engine.js +275 -0
- package/lib/adoption/diff-viewer.js +226 -0
- package/lib/adoption/error-formatter.js +509 -0
- package/lib/adoption/file-classifier.js +385 -0
- package/lib/adoption/progress-reporter.js +534 -0
- package/lib/adoption/smart-orchestrator.js +470 -0
- package/lib/adoption/strategy-selector.js +218 -0
- package/lib/adoption/summary-generator.js +493 -0
- package/lib/adoption/template-sync.js +605 -0
- package/lib/auto/autonomous-engine.js +485 -0
- package/lib/auto/checkpoint-manager.js +300 -0
- package/lib/auto/close-loop-runner.js +2476 -0
- package/lib/auto/config-schema.js +176 -0
- package/lib/auto/decision-engine.js +344 -0
- package/lib/auto/error-recovery-manager.js +580 -0
- package/lib/auto/goal-decomposer.js +278 -0
- package/lib/auto/progress-tracker.js +502 -0
- package/lib/auto/safety-manager.js +186 -0
- package/lib/auto/semantic-decomposer.js +137 -0
- package/lib/auto/state-manager.js +126 -0
- package/lib/auto/task-queue-manager.js +340 -0
- package/lib/backup/backup-system.js +372 -0
- package/lib/backup/selective-backup.js +207 -0
- package/lib/collab/agent-registry.js +240 -0
- package/lib/collab/collab-manager.js +285 -0
- package/lib/collab/contract-manager.js +320 -0
- package/lib/collab/coordinator.js +370 -0
- package/lib/collab/dependency-manager.js +280 -0
- package/lib/collab/index.js +20 -0
- package/lib/collab/integration-manager.js +202 -0
- package/lib/collab/merge-coordinator.js +252 -0
- package/lib/collab/metadata-manager.js +233 -0
- package/lib/collab/multi-agent-config.js +120 -0
- package/lib/collab/spec-lifecycle-manager.js +304 -0
- package/lib/collab/sync-barrier.js +88 -0
- package/lib/collab/visualizer.js +208 -0
- package/lib/commands/adopt.js +749 -0
- package/lib/commands/auto.js +19559 -0
- package/lib/commands/collab.js +275 -0
- package/lib/commands/context.js +99 -0
- package/lib/commands/docs.js +808 -0
- package/lib/commands/doctor.js +273 -0
- package/lib/commands/env.js +420 -0
- package/lib/commands/knowledge.js +309 -0
- package/lib/commands/lock.js +235 -0
- package/lib/commands/ops.js +409 -0
- package/lib/commands/orchestrate.js +446 -0
- package/lib/commands/prompt.js +105 -0
- package/lib/commands/repo.js +118 -0
- package/lib/commands/rollback.js +219 -0
- package/lib/commands/scene.js +15549 -0
- package/lib/commands/spec-bootstrap.js +147 -0
- package/lib/commands/spec-gate.js +157 -0
- package/lib/commands/spec-pipeline.js +205 -0
- package/lib/commands/status.js +321 -0
- package/lib/commands/task.js +199 -0
- package/lib/commands/templates.js +654 -0
- package/lib/commands/upgrade.js +231 -0
- package/lib/commands/value.js +569 -0
- package/lib/commands/watch.js +684 -0
- package/lib/commands/workflows.js +240 -0
- package/lib/commands/workspace-multi.js +325 -0
- package/lib/commands/workspace.js +189 -0
- package/lib/context/context-exporter.js +378 -0
- package/lib/context/prompt-generator.js +482 -0
- package/lib/data/moqui-capability-lexicon.json +45 -0
- package/lib/environment/backup-system.js +189 -0
- package/lib/environment/environment-manager.js +379 -0
- package/lib/environment/environment-registry.js +168 -0
- package/lib/gitignore/gitignore-backup.js +229 -0
- package/lib/gitignore/gitignore-detector.js +239 -0
- package/lib/gitignore/gitignore-integration.js +267 -0
- package/lib/gitignore/gitignore-transformer.js +193 -0
- package/lib/gitignore/layered-rules-template.js +42 -0
- package/lib/governance/archive-tool.js +284 -0
- package/lib/governance/cleanup-tool.js +237 -0
- package/lib/governance/config-manager.js +186 -0
- package/lib/governance/diagnostic-engine.js +271 -0
- package/lib/governance/doc-reference-checker.js +200 -0
- package/lib/governance/execution-logger.js +243 -0
- package/lib/governance/file-scanner.js +285 -0
- package/lib/governance/hooks-manager.js +333 -0
- package/lib/governance/reporter.js +337 -0
- package/lib/governance/validation-engine.js +181 -0
- package/lib/i18n.js +79 -0
- package/lib/knowledge/entry-manager.js +208 -0
- package/lib/knowledge/index-manager.js +261 -0
- package/lib/knowledge/knowledge-manager.js +273 -0
- package/lib/knowledge/template-manager.js +191 -0
- package/lib/lock/index.js +21 -0
- package/lib/lock/lock-file.js +192 -0
- package/lib/lock/lock-manager.js +321 -0
- package/lib/lock/machine-identifier.js +135 -0
- package/lib/lock/steering-file-lock.js +207 -0
- package/lib/lock/task-lock-manager.js +345 -0
- package/lib/operations/audit-logger.js +293 -0
- package/lib/operations/feedback-manager.js +1147 -0
- package/lib/operations/index.js +23 -0
- package/lib/operations/models/index.js +170 -0
- package/lib/operations/operations-manager.js +151 -0
- package/lib/operations/operations-validator.js +280 -0
- package/lib/operations/permission-manager.js +354 -0
- package/lib/operations/template-loader.js +143 -0
- package/lib/orchestrator/agent-spawner.js +629 -0
- package/lib/orchestrator/bootstrap-prompt-builder.js +236 -0
- package/lib/orchestrator/index.js +19 -0
- package/lib/orchestrator/orchestration-engine.js +1270 -0
- package/lib/orchestrator/orchestrator-config.js +173 -0
- package/lib/orchestrator/status-monitor.js +591 -0
- package/lib/python-checker.js +209 -0
- package/lib/repo/config-manager.js +580 -0
- package/lib/repo/errors/config-error.js +13 -0
- package/lib/repo/errors/git-error.js +15 -0
- package/lib/repo/errors/repo-error.js +14 -0
- package/lib/repo/git-operations.js +181 -0
- package/lib/repo/handlers/.gitkeep +1 -0
- package/lib/repo/handlers/exec-handler.js +155 -0
- package/lib/repo/handlers/health-handler.js +169 -0
- package/lib/repo/handlers/init-handler.js +197 -0
- package/lib/repo/handlers/status-handler.js +176 -0
- package/lib/repo/output-formatter.js +184 -0
- package/lib/repo/path-resolver.js +178 -0
- package/lib/repo/repo-manager.js +514 -0
- package/lib/scene-runtime/audit-emitter.js +59 -0
- package/lib/scene-runtime/binding-plugin-loader.js +351 -0
- package/lib/scene-runtime/binding-registry.js +349 -0
- package/lib/scene-runtime/eval-bridge.js +44 -0
- package/lib/scene-runtime/index.js +19 -0
- package/lib/scene-runtime/moqui-adapter.js +620 -0
- package/lib/scene-runtime/moqui-client.js +606 -0
- package/lib/scene-runtime/moqui-extractor.js +2029 -0
- package/lib/scene-runtime/plan-compiler.js +208 -0
- package/lib/scene-runtime/policy-gate.js +58 -0
- package/lib/scene-runtime/runtime-executor.js +358 -0
- package/lib/scene-runtime/scene-loader.js +96 -0
- package/lib/scene-runtime/scene-ontology.js +959 -0
- package/lib/scene-runtime/scene-template-linter.js +852 -0
- package/lib/scene-runtime/templates/scene-template-erp-query-v0.1.yaml +28 -0
- package/lib/scene-runtime/templates/scene-template-hybrid-shadow-v0.1.yaml +34 -0
- package/lib/spec/bootstrap/context-collector.js +48 -0
- package/lib/spec/bootstrap/draft-generator.js +158 -0
- package/lib/spec/bootstrap/questionnaire-engine.js +70 -0
- package/lib/spec/bootstrap/trace-emitter.js +59 -0
- package/lib/spec/multi-spec-orchestrate.js +93 -0
- package/lib/spec/pipeline/constants.js +6 -0
- package/lib/spec/pipeline/stage-adapters.js +118 -0
- package/lib/spec/pipeline/stage-runner.js +146 -0
- package/lib/spec/pipeline/state-store.js +119 -0
- package/lib/spec-gate/engine/gate-engine.js +165 -0
- package/lib/spec-gate/policy/default-policy.js +22 -0
- package/lib/spec-gate/policy/policy-loader.js +103 -0
- package/lib/spec-gate/result-emitter.js +81 -0
- package/lib/spec-gate/rules/default-rules.js +156 -0
- package/lib/spec-gate/rules/rule-registry.js +51 -0
- package/lib/steering/adoption-config.js +164 -0
- package/lib/steering/compliance-auto-fixer.js +204 -0
- package/lib/steering/compliance-cache.js +99 -0
- package/lib/steering/compliance-error-reporter.js +70 -0
- package/lib/steering/context-sync-manager.js +273 -0
- package/lib/steering/index.js +92 -0
- package/lib/steering/spec-steering.js +230 -0
- package/lib/steering/steering-compliance-checker.js +73 -0
- package/lib/steering/steering-loader.js +144 -0
- package/lib/steering/steering-manager.js +289 -0
- package/lib/task/index.js +12 -0
- package/lib/task/task-claimer.js +489 -0
- package/lib/task/task-status-store.js +418 -0
- package/lib/templates/cache-manager.js +440 -0
- package/lib/templates/content-generalizer.js +247 -0
- package/lib/templates/frontmatter-generator.js +128 -0
- package/lib/templates/git-handler.js +471 -0
- package/lib/templates/metadata-collector.js +328 -0
- package/lib/templates/path-utils.js +144 -0
- package/lib/templates/registry-parser.js +505 -0
- package/lib/templates/spec-reader.js +216 -0
- package/lib/templates/template-applicator.js +249 -0
- package/lib/templates/template-creator.js +256 -0
- package/lib/templates/template-error.js +143 -0
- package/lib/templates/template-exporter.js +502 -0
- package/lib/templates/template-manager.js +782 -0
- package/lib/templates/template-validator.js +361 -0
- package/lib/upgrade/migration-engine.js +382 -0
- package/lib/upgrade/migrations/.gitkeep +52 -0
- package/lib/upgrade/migrations/1.0.0-to-1.1.0.js +78 -0
- package/lib/utils/file-diff.js +177 -0
- package/lib/utils/fs-utils.js +274 -0
- package/lib/utils/tool-detector.js +383 -0
- package/lib/utils/validation.js +324 -0
- package/lib/value/gate-summary-emitter.js +99 -0
- package/lib/value/metric-contract-loader.js +210 -0
- package/lib/value/risk-evaluator.js +117 -0
- package/lib/value/weekly-snapshot-builder.js +61 -0
- package/lib/version/version-checker.js +156 -0
- package/lib/version/version-manager.js +327 -0
- package/lib/watch/action-executor.js +458 -0
- package/lib/watch/event-debouncer.js +323 -0
- package/lib/watch/execution-logger.js +550 -0
- package/lib/watch/file-watcher.js +499 -0
- package/lib/watch/presets.js +266 -0
- package/lib/watch/watch-manager.js +533 -0
- package/lib/workspace/multi/global-config.js +150 -0
- package/lib/workspace/multi/index.js +22 -0
- package/lib/workspace/multi/path-utils.js +173 -0
- package/lib/workspace/multi/workspace-context-resolver.js +244 -0
- package/lib/workspace/multi/workspace-registry.js +196 -0
- package/lib/workspace/multi/workspace-state-manager.js +537 -0
- package/lib/workspace/multi/workspace.js +90 -0
- package/lib/workspace/workspace-manager.js +370 -0
- package/lib/workspace/workspace-sync.js +356 -0
- package/locales/en.json +114 -0
- package/locales/zh.json +114 -0
- package/package.json +102 -0
- package/template/.kiro/README.md +247 -0
- package/template/.kiro/hooks/check-spec-on-create.kiro.hook +17 -0
- package/template/.kiro/hooks/run-tests-on-save.kiro.hook +13 -0
- package/template/.kiro/hooks/sync-tasks-on-edit.kiro.hook +16 -0
- package/template/.kiro/specs/SPEC_WORKFLOW_GUIDE.md +134 -0
- package/template/.kiro/steering/CORE_PRINCIPLES.md +133 -0
- package/template/.kiro/steering/CURRENT_CONTEXT.md +30 -0
- package/template/.kiro/steering/ENVIRONMENT.md +35 -0
- package/template/.kiro/steering/RULES_GUIDE.md +46 -0
- package/template/.kiro/templates/operations/default/change-impact.md +112 -0
- package/template/.kiro/templates/operations/default/deployment.md +91 -0
- package/template/.kiro/templates/operations/default/feedback-response.md +269 -0
- package/template/.kiro/templates/operations/default/migration-plan.md +172 -0
- package/template/.kiro/templates/operations/default/monitoring.md +135 -0
- package/template/.kiro/templates/operations/default/operations.md +135 -0
- package/template/.kiro/templates/operations/default/rollback.md +143 -0
- package/template/.kiro/templates/operations/default/tools.yaml +364 -0
- package/template/.kiro/templates/operations/default/troubleshooting.md +123 -0
- package/template/.kiro/tools/backup_manager.py +295 -0
- package/template/.kiro/tools/configuration_manager.py +218 -0
- package/template/.kiro/tools/document_evaluator.py +550 -0
- package/template/.kiro/tools/enhancement_logger.py +168 -0
- package/template/.kiro/tools/error_handler.py +335 -0
- package/template/.kiro/tools/improvement_identifier.py +444 -0
- package/template/.kiro/tools/modification_applicator.py +737 -0
- package/template/.kiro/tools/quality_gate_enforcer.py +207 -0
- package/template/.kiro/tools/quality_scorer.py +305 -0
- package/template/.kiro/tools/report_generator.py +154 -0
- package/template/.kiro/tools/ultrawork_enhancer.py +676 -0
- package/template/.kiro/tools/ultrawork_enhancer_refactored.py +0 -0
- package/template/.kiro/tools/ultrawork_enhancer_v2.py +463 -0
- package/template/.kiro/tools/ultrawork_enhancer_v3.py +606 -0
- package/template/.kiro/tools/workflow_quality_gate.py +100 -0
- package/template/README.md +111 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Registry - Manages Agent registration, heartbeat, and lifecycle
|
|
3
|
+
*
|
|
4
|
+
* Stores agent records in `.kiro/config/agent-registry.json`.
|
|
5
|
+
* Uses MachineIdentifier for unique Agent ID generation ({machineId}:{instanceIndex}).
|
|
6
|
+
* All write operations use atomic writes via fs-utils.
|
|
7
|
+
*
|
|
8
|
+
* Requirements: 1.1, 1.2, 1.3, 1.5, 1.6, 1.7
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const fsUtils = require('../utils/fs-utils');
|
|
13
|
+
const { MultiAgentConfig } = require('./multi-agent-config');
|
|
14
|
+
|
|
15
|
+
const REGISTRY_FILENAME = 'agent-registry.json';
|
|
16
|
+
const CONFIG_DIR = '.kiro/config';
|
|
17
|
+
|
|
18
|
+
const EMPTY_REGISTRY = Object.freeze({
|
|
19
|
+
version: '1.0.0',
|
|
20
|
+
agents: {},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
class AgentRegistry {
|
|
24
|
+
/**
|
|
25
|
+
* @param {string} workspaceRoot - Absolute path to the project root
|
|
26
|
+
* @param {import('../lock/machine-identifier').MachineIdentifier} machineIdentifier
|
|
27
|
+
* @param {import('../lock/task-lock-manager').TaskLockManager|null} [taskLockManager=null] - Optional, injected to avoid circular deps
|
|
28
|
+
*/
|
|
29
|
+
constructor(workspaceRoot, machineIdentifier, taskLockManager = null) {
|
|
30
|
+
this._workspaceRoot = workspaceRoot;
|
|
31
|
+
this._machineIdentifier = machineIdentifier;
|
|
32
|
+
this._taskLockManager = taskLockManager;
|
|
33
|
+
this._registryPath = path.join(workspaceRoot, CONFIG_DIR, REGISTRY_FILENAME);
|
|
34
|
+
this._configDir = path.join(workspaceRoot, CONFIG_DIR);
|
|
35
|
+
this._multiAgentConfig = new MultiAgentConfig(workspaceRoot);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Read the registry file. Auto-creates an empty registry if it doesn't exist (Req 1.7).
|
|
40
|
+
* @returns {Promise<object>}
|
|
41
|
+
* @private
|
|
42
|
+
*/
|
|
43
|
+
async _readRegistry() {
|
|
44
|
+
const exists = await fsUtils.pathExists(this._registryPath);
|
|
45
|
+
if (!exists) {
|
|
46
|
+
return { ...EMPTY_REGISTRY, agents: {} };
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
const data = await fsUtils.readJSON(this._registryPath);
|
|
50
|
+
if (!data || typeof data.agents !== 'object') {
|
|
51
|
+
return { ...EMPTY_REGISTRY, agents: {} };
|
|
52
|
+
}
|
|
53
|
+
return data;
|
|
54
|
+
} catch (_err) {
|
|
55
|
+
// Corrupted file – rebuild empty registry
|
|
56
|
+
return { ...EMPTY_REGISTRY, agents: {} };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Persist the registry atomically.
|
|
62
|
+
* Ensures the config directory exists before writing (Req 1.7).
|
|
63
|
+
* @param {object} registry
|
|
64
|
+
* @returns {Promise<void>}
|
|
65
|
+
* @private
|
|
66
|
+
*/
|
|
67
|
+
async _writeRegistry(registry) {
|
|
68
|
+
await fsUtils.ensureDirectory(this._configDir);
|
|
69
|
+
await fsUtils.writeJSON(this._registryPath, registry);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Find the next available instanceIndex for a given machineId.
|
|
74
|
+
* Scans existing agents with the same machineId and picks the lowest unused index.
|
|
75
|
+
* @param {object} agents - Current agents map
|
|
76
|
+
* @param {string} machineId
|
|
77
|
+
* @returns {number}
|
|
78
|
+
* @private
|
|
79
|
+
*/
|
|
80
|
+
_nextInstanceIndex(agents, machineId) {
|
|
81
|
+
const usedIndices = new Set();
|
|
82
|
+
for (const record of Object.values(agents)) {
|
|
83
|
+
if (record.machineId === machineId) {
|
|
84
|
+
usedIndices.add(record.instanceIndex);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
let index = 0;
|
|
88
|
+
while (usedIndices.has(index)) {
|
|
89
|
+
index++;
|
|
90
|
+
}
|
|
91
|
+
return index;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Register a new Agent. Generates a unique AgentID based on MachineIdentifier.
|
|
96
|
+
*
|
|
97
|
+
* @param {object} [options={}]
|
|
98
|
+
* @param {object|null} [options.currentTask] - Optional initial task assignment
|
|
99
|
+
* @returns {Promise<{agentId: string, registeredAt: string}>}
|
|
100
|
+
*/
|
|
101
|
+
async register(options = {}) {
|
|
102
|
+
const machineInfo = await this._machineIdentifier.getMachineId();
|
|
103
|
+
const registry = await this._readRegistry();
|
|
104
|
+
|
|
105
|
+
const instanceIndex = this._nextInstanceIndex(registry.agents, machineInfo.id);
|
|
106
|
+
const agentId = `${machineInfo.id}:${instanceIndex}`;
|
|
107
|
+
const now = new Date().toISOString();
|
|
108
|
+
|
|
109
|
+
registry.agents[agentId] = {
|
|
110
|
+
agentId,
|
|
111
|
+
machineId: machineInfo.id,
|
|
112
|
+
instanceIndex,
|
|
113
|
+
hostname: machineInfo.hostname,
|
|
114
|
+
registeredAt: now,
|
|
115
|
+
lastHeartbeat: now,
|
|
116
|
+
status: 'active',
|
|
117
|
+
currentTask: options.currentTask || null,
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
await this._writeRegistry(registry);
|
|
121
|
+
|
|
122
|
+
return { agentId, registeredAt: now };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Deregister an Agent. Removes the record and releases associated resources.
|
|
127
|
+
*
|
|
128
|
+
* @param {string} agentId
|
|
129
|
+
* @returns {Promise<{success: boolean, releasedLocks: Array<{specName: string, taskId: string}>}>}
|
|
130
|
+
*/
|
|
131
|
+
async deregister(agentId) {
|
|
132
|
+
const registry = await this._readRegistry();
|
|
133
|
+
|
|
134
|
+
if (!registry.agents[agentId]) {
|
|
135
|
+
return { success: false, releasedLocks: [] };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
delete registry.agents[agentId];
|
|
139
|
+
await this._writeRegistry(registry);
|
|
140
|
+
|
|
141
|
+
// Release all task locks held by this agent (Req 1.6)
|
|
142
|
+
let releasedLocks = [];
|
|
143
|
+
if (this._taskLockManager) {
|
|
144
|
+
const result = await this._taskLockManager.releaseAllLocks(agentId);
|
|
145
|
+
releasedLocks = result.released;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return { success: true, releasedLocks };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Update heartbeat timestamp for an Agent.
|
|
153
|
+
*
|
|
154
|
+
* @param {string} agentId
|
|
155
|
+
* @returns {Promise<{success: boolean, lastHeartbeat: string|null}>}
|
|
156
|
+
*/
|
|
157
|
+
async heartbeat(agentId) {
|
|
158
|
+
const registry = await this._readRegistry();
|
|
159
|
+
const agent = registry.agents[agentId];
|
|
160
|
+
|
|
161
|
+
if (!agent) {
|
|
162
|
+
return { success: false, lastHeartbeat: null };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const now = new Date().toISOString();
|
|
166
|
+
agent.lastHeartbeat = now;
|
|
167
|
+
agent.status = 'active';
|
|
168
|
+
|
|
169
|
+
await this._writeRegistry(registry);
|
|
170
|
+
|
|
171
|
+
return { success: true, lastHeartbeat: now };
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Get all agents with status 'active'.
|
|
176
|
+
* @returns {Promise<object[]>}
|
|
177
|
+
*/
|
|
178
|
+
async getActiveAgents() {
|
|
179
|
+
const registry = await this._readRegistry();
|
|
180
|
+
return Object.values(registry.agents).filter((a) => a.status === 'active');
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Get a specific Agent record by ID.
|
|
185
|
+
* @param {string} agentId
|
|
186
|
+
* @returns {Promise<object|null>}
|
|
187
|
+
*/
|
|
188
|
+
async getAgent(agentId) {
|
|
189
|
+
const registry = await this._readRegistry();
|
|
190
|
+
return registry.agents[agentId] || null;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Detect and clean up inactive Agents whose heartbeat has timed out.
|
|
195
|
+
* Uses heartbeatTimeoutMs from MultiAgentConfig (default 180 000 ms).
|
|
196
|
+
* Releases all task locks held by each inactive Agent (Req 1.4, 2.4).
|
|
197
|
+
*
|
|
198
|
+
* @returns {Promise<{cleaned: string[], releasedLocks: Array<{specName: string, taskId: string}>}>}
|
|
199
|
+
*/
|
|
200
|
+
async cleanupInactive() {
|
|
201
|
+
const config = await this._multiAgentConfig.getConfig();
|
|
202
|
+
const timeoutMs = config.heartbeatTimeoutMs;
|
|
203
|
+
const now = Date.now();
|
|
204
|
+
|
|
205
|
+
const registry = await this._readRegistry();
|
|
206
|
+
const cleaned = [];
|
|
207
|
+
|
|
208
|
+
for (const agent of Object.values(registry.agents)) {
|
|
209
|
+
if (agent.status !== 'active') continue;
|
|
210
|
+
|
|
211
|
+
const lastBeat = new Date(agent.lastHeartbeat).getTime();
|
|
212
|
+
if (now - lastBeat > timeoutMs) {
|
|
213
|
+
agent.status = 'inactive';
|
|
214
|
+
cleaned.push(agent.agentId);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (cleaned.length > 0) {
|
|
219
|
+
await this._writeRegistry(registry);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Release all task locks for each cleaned agent (Req 1.4, 2.4)
|
|
223
|
+
const releasedLocks = [];
|
|
224
|
+
if (this._taskLockManager && cleaned.length > 0) {
|
|
225
|
+
for (const agentId of cleaned) {
|
|
226
|
+
const result = await this._taskLockManager.releaseAllLocks(agentId);
|
|
227
|
+
releasedLocks.push(...result.released);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return { cleaned, releasedLocks };
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/** Absolute path to the registry file (useful for tests / diagnostics). */
|
|
235
|
+
get registryPath() {
|
|
236
|
+
return this._registryPath;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
module.exports = { AgentRegistry, EMPTY_REGISTRY };
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
const MetadataManager = require('./metadata-manager');
|
|
2
|
+
const DependencyManager = require('./dependency-manager');
|
|
3
|
+
const ContractManager = require('./contract-manager');
|
|
4
|
+
const IntegrationManager = require('./integration-manager');
|
|
5
|
+
const Visualizer = require('./visualizer');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* CollaborationManager orchestrates all collaboration operations
|
|
9
|
+
*/
|
|
10
|
+
class CollaborationManager {
|
|
11
|
+
constructor(workspaceRoot) {
|
|
12
|
+
this.workspaceRoot = workspaceRoot;
|
|
13
|
+
|
|
14
|
+
// Initialize managers
|
|
15
|
+
this.metadataManager = new MetadataManager(workspaceRoot);
|
|
16
|
+
this.dependencyManager = new DependencyManager(this.metadataManager);
|
|
17
|
+
this.contractManager = new ContractManager(workspaceRoot, this.metadataManager);
|
|
18
|
+
this.integrationManager = new IntegrationManager(workspaceRoot, this.metadataManager);
|
|
19
|
+
this.visualizer = new Visualizer();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Initialize a Master Spec with Sub-Specs
|
|
24
|
+
* @param {string} masterName - Name of the master spec
|
|
25
|
+
* @param {Array<Object>} subSpecs - Array of {name, dependencies}
|
|
26
|
+
* @param {Object} options - Additional options
|
|
27
|
+
* @returns {Promise<Object>} Creation result
|
|
28
|
+
*/
|
|
29
|
+
async initMasterSpec(masterName, subSpecs, options = {}) {
|
|
30
|
+
// Create master spec metadata
|
|
31
|
+
const masterMetadata = {
|
|
32
|
+
version: '1.0.0',
|
|
33
|
+
type: 'master',
|
|
34
|
+
subSpecs: subSpecs.map(s => s.name),
|
|
35
|
+
dependencies: [],
|
|
36
|
+
status: {
|
|
37
|
+
current: 'in-progress',
|
|
38
|
+
updatedAt: new Date().toISOString()
|
|
39
|
+
},
|
|
40
|
+
interfaces: {
|
|
41
|
+
provides: [],
|
|
42
|
+
consumes: []
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
await this.metadataManager.writeMetadata(masterName, masterMetadata);
|
|
47
|
+
|
|
48
|
+
// Create sub-spec metadata
|
|
49
|
+
const created = [];
|
|
50
|
+
for (const subSpec of subSpecs) {
|
|
51
|
+
const subMetadata = {
|
|
52
|
+
version: '1.0.0',
|
|
53
|
+
type: 'sub',
|
|
54
|
+
masterSpec: masterName,
|
|
55
|
+
dependencies: subSpec.dependencies || [],
|
|
56
|
+
status: {
|
|
57
|
+
current: 'not-started',
|
|
58
|
+
updatedAt: new Date().toISOString()
|
|
59
|
+
},
|
|
60
|
+
interfaces: {
|
|
61
|
+
provides: [],
|
|
62
|
+
consumes: []
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
await this.metadataManager.writeMetadata(subSpec.name, subMetadata);
|
|
67
|
+
created.push(subSpec.name);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Validate dependencies
|
|
71
|
+
const graph = await this.dependencyManager.buildDependencyGraph();
|
|
72
|
+
const cycle = this.dependencyManager.detectCircularDependencies(graph);
|
|
73
|
+
|
|
74
|
+
if (cycle) {
|
|
75
|
+
return {
|
|
76
|
+
success: false,
|
|
77
|
+
error: `Circular dependency detected: ${cycle.join(' → ')}`,
|
|
78
|
+
created: [masterName, ...created]
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
success: true,
|
|
84
|
+
master: masterName,
|
|
85
|
+
subSpecs: created,
|
|
86
|
+
message: `Created master spec '${masterName}' with ${created.length} sub-specs`
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Get collaboration status for all specs or a specific spec
|
|
92
|
+
* @param {string} specName - Optional spec name
|
|
93
|
+
* @returns {Promise<Object>} Status information
|
|
94
|
+
*/
|
|
95
|
+
async getCollaborationStatus(specName = null) {
|
|
96
|
+
if (specName) {
|
|
97
|
+
const metadata = await this.metadataManager.readMetadata(specName);
|
|
98
|
+
if (!metadata) {
|
|
99
|
+
return {
|
|
100
|
+
found: false,
|
|
101
|
+
error: `Spec '${specName}' not found`
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
found: true,
|
|
107
|
+
spec: specName,
|
|
108
|
+
metadata
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Get all specs
|
|
113
|
+
const allSpecs = await this.metadataManager.listAllMetadata();
|
|
114
|
+
const graph = await this.dependencyManager.buildDependencyGraph();
|
|
115
|
+
const ready = this.dependencyManager.getReadySpecs(graph);
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
total: allSpecs.length,
|
|
119
|
+
specs: allSpecs,
|
|
120
|
+
ready,
|
|
121
|
+
graph
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Assign a spec to a Kiro instance
|
|
127
|
+
* @param {string} specName - Name of the spec
|
|
128
|
+
* @param {string} kiroInstance - Kiro instance identifier
|
|
129
|
+
* @returns {Promise<Object>} Assignment result
|
|
130
|
+
*/
|
|
131
|
+
async assignSpec(specName, kiroInstance) {
|
|
132
|
+
const metadata = await this.metadataManager.readMetadata(specName);
|
|
133
|
+
|
|
134
|
+
if (!metadata) {
|
|
135
|
+
return {
|
|
136
|
+
success: false,
|
|
137
|
+
error: `Spec '${specName}' not found`
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Check if blocked
|
|
142
|
+
if (metadata.status.current === 'blocked') {
|
|
143
|
+
return {
|
|
144
|
+
success: false,
|
|
145
|
+
error: `Cannot assign blocked spec (reason: ${metadata.status.blockReason || 'unknown'})`
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Update assignment
|
|
150
|
+
const updated = await this.metadataManager.atomicUpdate(specName, (meta) => {
|
|
151
|
+
meta.assignment = {
|
|
152
|
+
kiroInstance,
|
|
153
|
+
assignedAt: new Date().toISOString()
|
|
154
|
+
};
|
|
155
|
+
return meta;
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
return {
|
|
159
|
+
success: true,
|
|
160
|
+
spec: specName,
|
|
161
|
+
kiroInstance,
|
|
162
|
+
message: `Assigned '${specName}' to '${kiroInstance}'`
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Update spec status
|
|
168
|
+
* @param {string} specName - Name of the spec
|
|
169
|
+
* @param {string} status - New status
|
|
170
|
+
* @param {string} reason - Optional reason (for blocked status)
|
|
171
|
+
* @returns {Promise<Object>} Update result
|
|
172
|
+
*/
|
|
173
|
+
async updateSpecStatus(specName, status, reason = null) {
|
|
174
|
+
const validStatuses = ['not-started', 'in-progress', 'completed', 'blocked'];
|
|
175
|
+
|
|
176
|
+
if (!validStatuses.includes(status)) {
|
|
177
|
+
return {
|
|
178
|
+
success: false,
|
|
179
|
+
error: `Invalid status: ${status}`
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const updated = await this.metadataManager.atomicUpdate(specName, (meta) => {
|
|
184
|
+
meta.status = {
|
|
185
|
+
current: status,
|
|
186
|
+
updatedAt: new Date().toISOString()
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
if (status === 'blocked' && reason) {
|
|
190
|
+
meta.status.blockReason = reason;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return meta;
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// If completed, update dependent specs
|
|
197
|
+
if (status === 'completed') {
|
|
198
|
+
const nowReady = await this.dependencyManager.updateDependentSpecs(specName);
|
|
199
|
+
return {
|
|
200
|
+
success: true,
|
|
201
|
+
spec: specName,
|
|
202
|
+
status,
|
|
203
|
+
nowReady,
|
|
204
|
+
message: `Updated '${specName}' to '${status}'. ${nowReady.length} specs now ready.`
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
success: true,
|
|
210
|
+
spec: specName,
|
|
211
|
+
status,
|
|
212
|
+
message: `Updated '${specName}' to '${status}'`
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Verify contracts for a spec
|
|
218
|
+
* @param {string} specName - Name of the spec
|
|
219
|
+
* @returns {Promise<Object>} Verification result
|
|
220
|
+
*/
|
|
221
|
+
async verifyContracts(specName) {
|
|
222
|
+
return await this.contractManager.verifyImplementation(specName);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Run integration tests
|
|
227
|
+
* @param {Array<string>} specNames - Specs to test
|
|
228
|
+
* @returns {Promise<Object>} Test results
|
|
229
|
+
*/
|
|
230
|
+
async runIntegrationTests(specNames) {
|
|
231
|
+
return await this.integrationManager.runAllTests(specNames);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Generate dependency graph visualization
|
|
236
|
+
* @param {string} format - Format ('text' or 'mermaid')
|
|
237
|
+
* @param {Object} options - Visualization options
|
|
238
|
+
* @returns {Promise<string>} Graph visualization
|
|
239
|
+
*/
|
|
240
|
+
async generateDependencyGraph(format = 'text', options = {}) {
|
|
241
|
+
const graph = await this.dependencyManager.buildDependencyGraph();
|
|
242
|
+
|
|
243
|
+
if (format === 'mermaid') {
|
|
244
|
+
return this.visualizer.generateMermaidGraph(graph);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return this.visualizer.generateTextGraph(graph, options);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Validate all dependencies
|
|
252
|
+
* @param {string} specName - Optional spec name to validate
|
|
253
|
+
* @returns {Promise<Object>} Validation result
|
|
254
|
+
*/
|
|
255
|
+
async validateDependencies(specName = null) {
|
|
256
|
+
const graph = await this.dependencyManager.buildDependencyGraph(
|
|
257
|
+
specName ? [specName] : null
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
const cycle = this.dependencyManager.detectCircularDependencies(graph);
|
|
261
|
+
|
|
262
|
+
if (cycle) {
|
|
263
|
+
return {
|
|
264
|
+
valid: false,
|
|
265
|
+
error: `Circular dependency detected: ${cycle.join(' → ')}`
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return {
|
|
270
|
+
valid: true,
|
|
271
|
+
message: 'All dependencies are valid'
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Get ready specs (specs that can be started)
|
|
277
|
+
* @returns {Promise<Array<string>>} List of ready spec names
|
|
278
|
+
*/
|
|
279
|
+
async getReadySpecs() {
|
|
280
|
+
const graph = await this.dependencyManager.buildDependencyGraph();
|
|
281
|
+
return this.dependencyManager.getReadySpecs(graph);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
module.exports = CollaborationManager;
|