xcoder-dna 0.0.0-stage → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +87 -2
- package/dist/agents/ai-chat-debate.d.ts +36 -0
- package/dist/agents/ai-chat-debate.js +300 -0
- package/dist/agents/ai-chat-report-writer.d.ts +7 -0
- package/dist/agents/ai-chat-report-writer.js +100 -0
- package/dist/agents/duplicate-detector.d.ts +41 -0
- package/dist/agents/duplicate-detector.js +65 -0
- package/dist/agents/genesis-agent.d.ts +61 -0
- package/dist/agents/genesis-agent.js +340 -0
- package/dist/agents/samurai-agent.d.ts +53 -0
- package/dist/agents/samurai-agent.js +279 -0
- package/dist/agents/sub-agent.d.ts +56 -0
- package/dist/agents/sub-agent.js +353 -0
- package/dist/backlog/backlog-requirement-validator.d.ts +10 -0
- package/dist/backlog/backlog-requirement-validator.js +60 -0
- package/dist/backlog/backlog-store.d.ts +29 -0
- package/dist/backlog/backlog-store.js +148 -0
- package/dist/backlog/po-agent.d.ts +16 -0
- package/dist/backlog/po-agent.js +121 -0
- package/dist/backlog/types.d.ts +25 -0
- package/dist/backlog/types.js +4 -0
- package/dist/bench/run.d.ts +11 -0
- package/dist/bench/run.js +185 -0
- package/dist/bench/types.d.ts +50 -0
- package/dist/bench/types.js +1 -0
- package/dist/cli/swarm.d.ts +10 -0
- package/dist/cli/swarm.js +100 -0
- package/dist/cli/task.d.ts +14 -0
- package/dist/cli/task.js +121 -0
- package/dist/cli/wbc-arg.d.ts +6 -0
- package/dist/cli/wbc-arg.js +40 -0
- package/dist/cli/wbc.d.ts +45 -0
- package/dist/cli/wbc.js +98 -0
- package/dist/commands/license.d.ts +9 -0
- package/dist/commands/license.js +140 -0
- package/dist/commands/release.d.ts +44 -0
- package/dist/commands/release.js +180 -0
- package/dist/commands/test.d.ts +50 -0
- package/dist/commands/test.js +385 -0
- package/dist/config/loadConfig.d.ts +82 -0
- package/dist/config/loadConfig.js +240 -0
- package/dist/config/secure-mode.d.ts +29 -0
- package/dist/config/secure-mode.js +63 -0
- package/dist/config/user-config.d.ts +39 -0
- package/dist/config/user-config.js +202 -0
- package/dist/engine/reasoning-engine.d.ts +21 -0
- package/dist/engine/reasoning-engine.js +59 -0
- package/dist/events/bus.d.ts +22 -0
- package/dist/events/bus.js +18 -0
- package/dist/index.d.ts +79 -0
- package/dist/index.js +77 -0
- package/dist/indexing/ignoreRules.d.ts +1 -0
- package/dist/indexing/ignoreRules.js +53 -0
- package/dist/instance-swarm/instance-swarm-orchestrator.d.ts +57 -0
- package/dist/instance-swarm/instance-swarm-orchestrator.js +204 -0
- package/dist/instance-swarm/protocol-name-resolver.d.ts +23 -0
- package/dist/instance-swarm/protocol-name-resolver.js +64 -0
- package/dist/license/gate.d.ts +31 -0
- package/dist/license/gate.js +188 -0
- package/dist/license/http-client.d.ts +43 -0
- package/dist/license/http-client.js +195 -0
- package/dist/license/manager.d.ts +39 -0
- package/dist/license/manager.js +175 -0
- package/dist/license/receipt.d.ts +27 -0
- package/dist/license/receipt.js +108 -0
- package/dist/license/state-codec.d.ts +72 -0
- package/dist/license/state-codec.js +218 -0
- package/dist/license/state-paths.d.ts +17 -0
- package/dist/license/state-paths.js +64 -0
- package/dist/license/store.d.ts +44 -0
- package/dist/license/store.js +223 -0
- package/dist/license/trust-anchor.d.ts +24 -0
- package/dist/license/trust-anchor.js +74 -0
- package/dist/license/types.d.ts +34 -0
- package/dist/license/types.js +19 -0
- package/dist/llm/budget.d.ts +23 -0
- package/dist/llm/budget.js +58 -0
- package/dist/llm/client.d.ts +53 -0
- package/dist/llm/client.js +122 -0
- package/dist/llm/factory.d.ts +14 -0
- package/dist/llm/factory.js +32 -0
- package/dist/orchestrator/defect-logger.d.ts +31 -0
- package/dist/orchestrator/defect-logger.js +101 -0
- package/dist/orchestrator/defect-manager.d.ts +118 -0
- package/dist/orchestrator/defect-manager.js +338 -0
- package/dist/orchestrator/defect-migration.d.ts +14 -0
- package/dist/orchestrator/defect-migration.js +174 -0
- package/dist/orchestrator/defect-store.d.ts +48 -0
- package/dist/orchestrator/defect-store.js +76 -0
- package/dist/orchestrator/healing.d.ts +14 -0
- package/dist/orchestrator/healing.js +11 -0
- package/dist/orchestrator/interactive-steering.d.ts +64 -0
- package/dist/orchestrator/interactive-steering.js +107 -0
- package/dist/orchestrator/interrupt-handler.d.ts +30 -0
- package/dist/orchestrator/interrupt-handler.js +70 -0
- package/dist/orchestrator/lesson-manager.d.ts +25 -0
- package/dist/orchestrator/lesson-manager.js +122 -0
- package/dist/orchestrator/progress-summary.d.ts +15 -0
- package/dist/orchestrator/progress-summary.js +106 -0
- package/dist/orchestrator/reasoning-score.d.ts +49 -0
- package/dist/orchestrator/reasoning-score.js +117 -0
- package/dist/orchestrator/swarm.d.ts +36 -0
- package/dist/orchestrator/swarm.js +77 -0
- package/dist/orchestrator/task-factory.d.ts +15 -0
- package/dist/orchestrator/task-factory.js +176 -0
- package/dist/orchestrator/validation-gate.d.ts +23 -0
- package/dist/orchestrator/validation-gate.js +155 -0
- package/dist/protocol/react-contract.d.ts +136 -0
- package/dist/protocol/react-contract.js +698 -0
- package/dist/protocol/wks-protocol-manager.d.ts +22 -0
- package/dist/protocol/wks-protocol-manager.js +72 -0
- package/dist/sdlc-runtime/conversation-runner.d.ts +8 -0
- package/dist/sdlc-runtime/conversation-runner.js +64 -0
- package/dist/sdlc-runtime/dag-utils.d.ts +15 -0
- package/dist/sdlc-runtime/dag-utils.js +67 -0
- package/dist/sdlc-runtime/defect-integration.d.ts +7 -0
- package/dist/sdlc-runtime/defect-integration.js +99 -0
- package/dist/sdlc-runtime/execution-loop.d.ts +38 -0
- package/dist/sdlc-runtime/execution-loop.js +274 -0
- package/dist/sdlc-runtime/lesson-recorder.d.ts +9 -0
- package/dist/sdlc-runtime/lesson-recorder.js +27 -0
- package/dist/sdlc-runtime/plan-initializer.d.ts +47 -0
- package/dist/sdlc-runtime/plan-initializer.js +135 -0
- package/dist/sdlc-runtime/progress-persister.d.ts +10 -0
- package/dist/sdlc-runtime/progress-persister.js +34 -0
- package/dist/sdlc-runtime/protocol-loader.d.ts +10 -0
- package/dist/sdlc-runtime/protocol-loader.js +21 -0
- package/dist/sdlc-runtime/reporting.d.ts +24 -0
- package/dist/sdlc-runtime/reporting.js +68 -0
- package/dist/sdlc-runtime/sdlc-orchestrator.d.ts +59 -0
- package/dist/sdlc-runtime/sdlc-orchestrator.js +170 -0
- package/dist/sdlc-runtime/sdlc-skill.d.ts +44 -0
- package/dist/sdlc-runtime/sdlc-skill.js +148 -0
- package/dist/sdlc-runtime/steering-handler.d.ts +14 -0
- package/dist/sdlc-runtime/steering-handler.js +51 -0
- package/dist/sdlc-runtime/trace-recorder.d.ts +10 -0
- package/dist/sdlc-runtime/trace-recorder.js +7 -0
- package/dist/security/index.d.ts +16 -0
- package/dist/security/index.js +12 -0
- package/dist/security/input-screen.d.ts +30 -0
- package/dist/security/input-screen.js +75 -0
- package/dist/security/tool-call-guard.d.ts +16 -0
- package/dist/security/tool-call-guard.js +163 -0
- package/dist/security/untrusted-content.d.ts +34 -0
- package/dist/security/untrusted-content.js +63 -0
- package/dist/skills/advanced-dfir/SKILL.md +85 -0
- package/dist/skills/advanced-pentest-lab/SKILL.md +88 -0
- package/dist/skills/analyst/SKILL.md +55 -0
- package/dist/skills/architect/SKILL.md +54 -0
- package/dist/skills/aws/SKILL.md +92 -0
- package/dist/skills/azure/SKILL.md +90 -0
- package/dist/skills/bylaw-context.d.ts +45 -0
- package/dist/skills/bylaw-context.js +61 -0
- package/dist/skills/bylaw-review.d.ts +20 -0
- package/dist/skills/bylaw-review.js +101 -0
- package/dist/skills/conversation/SKILL.md +29 -0
- package/dist/skills/design-patterns/SKILL.md +190 -0
- package/dist/skills/devops/SKILL.md +55 -0
- package/dist/skills/directives.d.ts +20 -0
- package/dist/skills/directives.js +313 -0
- package/dist/skills/docker/SKILL.md +76 -0
- package/dist/skills/docker-expert/SKILL.md +56 -0
- package/dist/skills/enterprise-systems-analyst/SKILL.md +83 -0
- package/dist/skills/enterprise-systems-analyst/references/crm.md +41 -0
- package/dist/skills/enterprise-systems-analyst/references/erp.md +40 -0
- package/dist/skills/enterprise-systems-analyst/references/financial-systems.md +35 -0
- package/dist/skills/enterprise-systems-analyst/references/hcm.md +38 -0
- package/dist/skills/enterprise-systems-analyst/references/mrp.md +37 -0
- package/dist/skills/enterprise-systems-analyst/references/scm.md +32 -0
- package/dist/skills/ethical-hacking-methodology/SKILL.md +119 -0
- package/dist/skills/externalSkillLoader.d.ts +25 -0
- package/dist/skills/externalSkillLoader.js +65 -0
- package/dist/skills/externalSkillRegistry.d.ts +33 -0
- package/dist/skills/externalSkillRegistry.js +94 -0
- package/dist/skills/filesystem-management/SKILL.md +61 -0
- package/dist/skills/first-run-seed.d.ts +26 -0
- package/dist/skills/first-run-seed.js +75 -0
- package/dist/skills/git-vcs/SKILL.md +84 -0
- package/dist/skills/kafka/SKILL.md +89 -0
- package/dist/skills/kubernetes/SKILL.md +93 -0
- package/dist/skills/kubernetes-expert/SKILL.md +54 -0
- package/dist/skills/openshift/SKILL.md +93 -0
- package/dist/skills/pentester/SKILL.md +59 -0
- package/dist/skills/performance-tester/SKILL.md +57 -0
- package/dist/skills/playwright-ui-tester/SKILL.md +67 -0
- package/dist/skills/programmer/SKILL.md +58 -0
- package/dist/skills/project-scaffolding/SKILL.md +133 -0
- package/dist/skills/qa-engineer/SKILL.md +91 -0
- package/dist/skills/rca/SKILL.md +58 -0
- package/dist/skills/redhat/SKILL.md +92 -0
- package/dist/skills/rosa/SKILL.md +80 -0
- package/dist/skills/scrum-framework/SKILL.md +74 -0
- package/dist/skills/scrum-framework/references/artifacts_and_quality.md +79 -0
- package/dist/skills/scrum-framework/references/roles_and_events.md +105 -0
- package/dist/skills/scrum-master-agent/SKILL.md +74 -0
- package/dist/skills/scrum-master-agent/references/behaviors.md +56 -0
- package/dist/skills/sdlc-skill.d.ts +1 -0
- package/dist/skills/sdlc-skill.js +4 -0
- package/dist/skills/secops/SKILL.md +52 -0
- package/dist/skills/secure-architect.bylaws.d.ts +68 -0
- package/dist/skills/secure-architect.bylaws.js +525 -0
- package/dist/skills/seed-skills.d.ts +48 -0
- package/dist/skills/seed-skills.js +213 -0
- package/dist/skills/skill-authoring/SKILL.md +123 -0
- package/dist/skills/skill-header.d.ts +51 -0
- package/dist/skills/skill-header.js +163 -0
- package/dist/skills/skill-path-guard.d.ts +41 -0
- package/dist/skills/skill-path-guard.js +95 -0
- package/dist/skills/skillRouter.d.ts +51 -0
- package/dist/skills/skillRouter.js +90 -0
- package/dist/skills/skills-root.d.ts +64 -0
- package/dist/skills/skills-root.js +168 -0
- package/dist/skills/software-architect/SKILL.md +77 -0
- package/dist/skills/software-engineer/SKILL.md +74 -0
- package/dist/skills/solid-principles/SKILL.md +94 -0
- package/dist/skills/task-planning/SKILL.md +115 -0
- package/dist/skills/tester/SKILL.md +54 -0
- package/dist/skills/ubuntu/SKILL.md +87 -0
- package/dist/skills/ui-ux-design/SKILL.md +114 -0
- package/dist/skills/workspace-context/SKILL.md +103 -0
- package/dist/sprint/controller.d.ts +37 -0
- package/dist/sprint/controller.js +220 -0
- package/dist/sprint/dag-builder.d.ts +14 -0
- package/dist/sprint/dag-builder.js +105 -0
- package/dist/sprint/reporter.d.ts +11 -0
- package/dist/sprint/reporter.js +97 -0
- package/dist/sprint/state-store.d.ts +10 -0
- package/dist/sprint/state-store.js +71 -0
- package/dist/sprint/types.d.ts +24 -0
- package/dist/sprint/types.js +4 -0
- package/dist/store/file-version-store.d.ts +24 -0
- package/dist/store/file-version-store.js +73 -0
- package/dist/store/task-store.d.ts +90 -0
- package/dist/store/task-store.js +166 -0
- package/dist/task-ingest/architect-detailer.d.ts +43 -0
- package/dist/task-ingest/architect-detailer.js +141 -0
- package/dist/task-ingest/detail-schema.d.ts +9 -0
- package/dist/task-ingest/detail-schema.js +195 -0
- package/dist/task-ingest/detailed-run.d.ts +36 -0
- package/dist/task-ingest/detailed-run.js +108 -0
- package/dist/task-ingest/extract-id.d.ts +9 -0
- package/dist/task-ingest/extract-id.js +24 -0
- package/dist/task-ingest/index.d.ts +23 -0
- package/dist/task-ingest/index.js +14 -0
- package/dist/task-ingest/ingest.d.ts +45 -0
- package/dist/task-ingest/ingest.js +163 -0
- package/dist/task-ingest/list-ingested.d.ts +13 -0
- package/dist/task-ingest/list-ingested.js +30 -0
- package/dist/task-ingest/pending-filter.d.ts +30 -0
- package/dist/task-ingest/pending-filter.js +59 -0
- package/dist/task-ingest/scanner.d.ts +56 -0
- package/dist/task-ingest/scanner.js +216 -0
- package/dist/task-ingest/source-reader.d.ts +25 -0
- package/dist/task-ingest/source-reader.js +93 -0
- package/dist/task-ingest/spec-builder.d.ts +34 -0
- package/dist/task-ingest/spec-builder.js +89 -0
- package/dist/task-ingest/wbs-extract.d.ts +50 -0
- package/dist/task-ingest/wbs-extract.js +226 -0
- package/dist/task-ingest/wbs-parser.d.ts +36 -0
- package/dist/task-ingest/wbs-parser.js +170 -0
- package/dist/tools/apiTestTool.d.ts +37 -0
- package/dist/tools/apiTestTool.js +128 -0
- package/dist/tools/ast-tools.d.ts +183 -0
- package/dist/tools/ast-tools.js +853 -0
- package/dist/tools/browse-tool.d.ts +105 -0
- package/dist/tools/browse-tool.js +394 -0
- package/dist/tools/credential.d.ts +17 -0
- package/dist/tools/credential.js +32 -0
- package/dist/tools/dependency-graph.d.ts +23 -0
- package/dist/tools/dependency-graph.js +164 -0
- package/dist/tools/edit-tool.d.ts +34 -0
- package/dist/tools/edit-tool.js +95 -0
- package/dist/tools/file-header-manager.d.ts +27 -0
- package/dist/tools/file-header-manager.js +153 -0
- package/dist/tools/fs-tools.d.ts +154 -0
- package/dist/tools/fs-tools.js +337 -0
- package/dist/tools/git-tools.d.ts +79 -0
- package/dist/tools/git-tools.js +348 -0
- package/dist/tools/github-tool.d.ts +48 -0
- package/dist/tools/github-tool.js +147 -0
- package/dist/tools/globTool.d.ts +20 -0
- package/dist/tools/globTool.js +34 -0
- package/dist/tools/grepTool.d.ts +19 -0
- package/dist/tools/grepTool.js +44 -0
- package/dist/tools/index-freshness.d.ts +58 -0
- package/dist/tools/index-freshness.js +190 -0
- package/dist/tools/index-glob.d.ts +48 -0
- package/dist/tools/index-glob.js +175 -0
- package/dist/tools/load-skill-tool.d.ts +15 -0
- package/dist/tools/load-skill-tool.js +114 -0
- package/dist/tools/patch-tools.d.ts +58 -0
- package/dist/tools/patch-tools.js +153 -0
- package/dist/tools/playwright-tool.d.ts +66 -0
- package/dist/tools/playwright-tool.js +121 -0
- package/dist/tools/project-detect.d.ts +20 -0
- package/dist/tools/project-detect.js +87 -0
- package/dist/tools/prompt-guidance.d.ts +22 -0
- package/dist/tools/prompt-guidance.js +23 -0
- package/dist/tools/scheduleTool.d.ts +19 -0
- package/dist/tools/scheduleTool.js +181 -0
- package/dist/tools/search-tools.d.ts +27 -0
- package/dist/tools/search-tools.js +78 -0
- package/dist/tools/sed-tool.d.ts +66 -0
- package/dist/tools/sed-tool.js +402 -0
- package/dist/tools/shell-result.d.ts +11 -0
- package/dist/tools/shell-result.js +1 -0
- package/dist/tools/shell-tool.d.ts +45 -0
- package/dist/tools/shell-tool.js +141 -0
- package/dist/tools/siteCrawlerTool.d.ts +32 -0
- package/dist/tools/siteCrawlerTool.js +205 -0
- package/dist/tools/tool-registry.d.ts +67 -0
- package/dist/tools/tool-registry.js +596 -0
- package/dist/tools/validate-tool.d.ts +23 -0
- package/dist/tools/validate-tool.js +201 -0
- package/dist/tools/workspace-index.d.ts +46 -0
- package/dist/tools/workspace-index.js +173 -0
- package/dist/types.d.ts +222 -0
- package/dist/types.js +7 -0
- package/dist/updater/index.d.ts +14 -0
- package/dist/updater/index.js +120 -0
- package/dist/util/banner.d.ts +25 -0
- package/dist/util/banner.js +140 -0
- package/dist/util/command-suggester.d.ts +6 -0
- package/dist/util/command-suggester.js +25 -0
- package/dist/util/confirm-interrupt.d.ts +10 -0
- package/dist/util/confirm-interrupt.js +31 -0
- package/dist/util/continue-trigger.d.ts +11 -0
- package/dist/util/continue-trigger.js +20 -0
- package/dist/util/env-info.d.ts +18 -0
- package/dist/util/env-info.js +37 -0
- package/dist/util/file-access-log.d.ts +35 -0
- package/dist/util/file-access-log.js +140 -0
- package/dist/util/footer-manager.d.ts +124 -0
- package/dist/util/footer-manager.js +195 -0
- package/dist/util/footer-renderer.d.ts +67 -0
- package/dist/util/footer-renderer.js +319 -0
- package/dist/util/footer-state.d.ts +34 -0
- package/dist/util/footer-state.js +18 -0
- package/dist/util/footer-text.d.ts +51 -0
- package/dist/util/footer-text.js +74 -0
- package/dist/util/ids.d.ts +1 -0
- package/dist/util/ids.js +4 -0
- package/dist/util/levenshtein.d.ts +6 -0
- package/dist/util/levenshtein.js +34 -0
- package/dist/util/logger.d.ts +10 -0
- package/dist/util/logger.js +41 -0
- package/dist/util/logs.d.ts +26 -0
- package/dist/util/logs.js +88 -0
- package/dist/util/output-handler.d.ts +89 -0
- package/dist/util/output-handler.js +193 -0
- package/dist/util/output-interceptor.d.ts +18 -0
- package/dist/util/output-interceptor.js +49 -0
- package/dist/util/output-paths.d.ts +43 -0
- package/dist/util/output-paths.js +121 -0
- package/dist/util/package-json.d.ts +6 -0
- package/dist/util/package-json.js +36 -0
- package/dist/util/process-kill.d.ts +27 -0
- package/dist/util/process-kill.js +148 -0
- package/dist/util/protocol-error-logger.d.ts +33 -0
- package/dist/util/protocol-error-logger.js +73 -0
- package/dist/util/redact.d.ts +25 -0
- package/dist/util/redact.js +103 -0
- package/dist/util/scroll-region-guard.d.ts +33 -0
- package/dist/util/scroll-region-guard.js +63 -0
- package/dist/util/spinner.d.ts +15 -0
- package/dist/util/spinner.js +49 -0
- package/dist/util/terminal-output.d.ts +34 -0
- package/dist/util/terminal-output.js +1 -0
- package/dist/util/terminal-silent.d.ts +6 -0
- package/dist/util/terminal-silent.js +20 -0
- package/dist/util/terminal.d.ts +56 -0
- package/dist/util/terminal.js +124 -0
- package/dist/util/text-sanitize.d.ts +8 -0
- package/dist/util/text-sanitize.js +45 -0
- package/dist/util/thinking-spinner.d.ts +27 -0
- package/dist/util/thinking-spinner.js +189 -0
- package/dist/util/tool-error-logger.d.ts +33 -0
- package/dist/util/tool-error-logger.js +77 -0
- package/dist/util/tty.d.ts +13 -0
- package/dist/util/tty.js +16 -0
- package/dist/util/xcoder-paths.d.ts +56 -0
- package/dist/util/xcoder-paths.js +63 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +4 -0
- package/dist/worker-agent/to-subtask-node.d.ts +35 -0
- package/dist/worker-agent/to-subtask-node.js +41 -0
- package/dist/worker-agent/worker-orchestrator.d.ts +104 -0
- package/dist/worker-agent/worker-orchestrator.js +201 -0
- package/package.json +38 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Neural Node Labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,88 @@
|
|
|
1
|
-
|
|
1
|
+
<!-- xcoder:version 3 | xcoder:task task-295e1f | xcoder:updated 2026-11-04T20:17:09.582Z | xcoder:subtask document-st-dd8fa0 -->
|
|
2
|
+
# xcoder-dna — shared runtime for the Xcoder agents
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
`xcoder-dna` is a **library**, not a CLI. It has no binary and nothing to run directly: it holds the reusable tools, skills, swarm, sub-agent runtime and orchestration primitives that the Xcoder agents are built from. Its public barrel, `src/index.ts`, is the only import path other packages may use.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
npm install xcoder-dna
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Node >= 20 is required. Do not install this package globally — there is no executable to put on your PATH.
|
|
13
|
+
|
|
14
|
+
## Quick start
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { createLlmClient, log, buildIndex, ensureFreshIndex } from "xcoder-dna";
|
|
18
|
+
|
|
19
|
+
const index = buildIndex(process.cwd());
|
|
20
|
+
await ensureFreshIndex(process.cwd());
|
|
21
|
+
log.orchestrator(`indexed ${index.files.length} files`);
|
|
22
|
+
|
|
23
|
+
const llm = createLlmClient("orchestrator", { workspaceRoot: process.cwd() });
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Public API
|
|
27
|
+
|
|
28
|
+
The barrel is grouped by concern. Each identifier below is a real export; import it from the package root, never from a deep path.
|
|
29
|
+
|
|
30
|
+
| Area | Exports |
|
|
31
|
+
|---|---|
|
|
32
|
+
| LLM access | `createLlmClient`, `LlmClient`, `requestScope` |
|
|
33
|
+
| Logging and output | `log`, `getOutputHandler`, `getOutputPaths`, `redactSecrets`, `sanitizeForTerminal` |
|
|
34
|
+
| Workspace index | `buildIndex`, `ensureFreshIndex`, `createXcoderPaths` |
|
|
35
|
+
| Agents and runtime | `SubAgent`, `GenesisReActOrchestrator`, `SamuraiAgent`, `WorkerOrchestrator`, `InstanceSwarmOrchestrator`, `DuplicateActionDetector`, `runDebate`, `writeReport` |
|
|
36
|
+
| Orchestration | `decideHealing`, `getOrchestratorEngine`, `buildProgressSummaryMarkdown`, `resolveLessonFlag`, `loadLessons`, `recordLesson` |
|
|
37
|
+
| Defects | `scanForDefects`, `classifyDefectRouting`, `resolveDefect`, `loadDefectsIndex`, `upsertDefect` |
|
|
38
|
+
| Planning and DAG | `inlineIntoDependents`, `dagSnapshot`, `recomputeReady` |
|
|
39
|
+
| Backlog and sprints | `addBacklogItem`, `listBacklogItems`, `getBacklogItem`, `updateBacklogItem`, `runPoPick` |
|
|
40
|
+
| Benchmarking | `runBenchmark`, `compareReports` |
|
|
41
|
+
| Terminal and spinner | `setSpinnerStyle`, `getSpinnerStyle`, `createSpinner`, `AVAILABLE_SPINNER_STYLES`, `taskIntro`, `taskOutro`, `orchestratorNote`, `printCrash`, `printInterruptSummary` |
|
|
42
|
+
| Events and diagnostics | `xcoderEvents`, `emitXcoderEvent`, `enableProtocolErrorLogging`, `enableToolErrorLogging`, `maybePrintBanner` |
|
|
43
|
+
| Licensing | `requireLicense`, `isLicensedFeature`, `maybeRefreshLicense`, `createDefaultLicenseManager`, `LICENSE_REQUIRED_EXIT_CODE` |
|
|
44
|
+
| Command registrars | `registerTestCommand`, `registerSwarmCommand`, `registerTaskCommand`, `registerLicenseCommand` |
|
|
45
|
+
| Version | `XCODER_VERSION` |
|
|
46
|
+
|
|
47
|
+
Types such as `TaskRun`, `TaskSpec`, `SubtaskNode`, `SubtaskResult`, `LessonEntry`, `AgentRole`, `SdlcStage` and `SpinnerHandle` are exported alongside their values.
|
|
48
|
+
|
|
49
|
+
## Process exit
|
|
50
|
+
|
|
51
|
+
This is a library; it never calls `process.exit` and sets no exit code itself. It does export `LICENSE_REQUIRED_EXIT_CODE` (`4`), which the CLIs relay when a licensed command runs without an active license.
|
|
52
|
+
|
|
53
|
+
## Environment variables
|
|
54
|
+
|
|
55
|
+
`xcoder-dna` reads credentials and provider settings through the host agent's config (`~/.xcoder/config.json` or environment variables such as `XCODER_MODEL`); it never prompts for a key itself. Secrets are redacted by `redactSecrets` before they reach logs.
|
|
56
|
+
|
|
57
|
+
## Dependency direction
|
|
58
|
+
|
|
59
|
+
`xcoder-dna` has **no internal dependencies** — it is the base of the workspace graph and imports no other workspace package. Everyone else depends on it:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
xcoder-dna <- @xcoder/litebro
|
|
63
|
+
<- @xcoder/qa-agent
|
|
64
|
+
<- @xcoder/sdlc-agent
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Build output
|
|
68
|
+
|
|
69
|
+
`npm run build` compiles TypeScript to `dist/` and then copies `skills/` to `dist/skills/`, so the skills catalogue ships inside the package. Only `dist/`, `README.md` and `LICENSE` are published.
|
|
70
|
+
|
|
71
|
+
## Documentation contract
|
|
72
|
+
|
|
73
|
+
This README ships to npm, so it is gated like code by `packages/xcoder-dna/src/doc-readme.test.ts`. It asserts differently from the agent packages because this is a library: there is no bin, so no CLI section and no exit-code table are allowed. Instead every identifier named in the Public API table is checked against the barrel at `src/index.ts` — the single legal import path — so the README cannot claim an export the library does not have. Run it in isolation with:
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
npx vitest run packages/xcoder-dna/src/doc-readme.test.ts
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Related packages
|
|
80
|
+
|
|
81
|
+
- [@xcoder/sdlc-agent](https://github.com/org/xcoder-sdlc/tree/main/packages/sdlc-agent) — the `xcoder` SDLC agent and `ba-v1`.
|
|
82
|
+
- [@xcoder/qa-agent](https://github.com/org/xcoder-sdlc/tree/main/packages/qa-agent) — the `bugfinder` QA agent.
|
|
83
|
+
- [@xcoder/litebro](https://github.com/org/xcoder-sdlc/tree/main/packages/litebro) — the tool-less planner/broker.
|
|
84
|
+
- [blueprint.md](https://github.com/org/xcoder-sdlc/blob/main/docs/blueprint.md) — architecture and component decomposition.
|
|
85
|
+
|
|
86
|
+
## License
|
|
87
|
+
|
|
88
|
+
see [LICENSE](./LICENSE) for details.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { RaoStep, TokenUsage } from "../types.js";
|
|
2
|
+
import { LlmClient } from "../llm/client.js";
|
|
3
|
+
export interface DebateOptions {
|
|
4
|
+
workspaceRoot: string;
|
|
5
|
+
llm: LlmClient;
|
|
6
|
+
topic: string;
|
|
7
|
+
maxExchanges?: number;
|
|
8
|
+
model?: string;
|
|
9
|
+
debateId?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface DebateTurn {
|
|
12
|
+
agent: "Sumurai" | "Ninj";
|
|
13
|
+
turnNumber: number;
|
|
14
|
+
raoTrace: RaoStep[];
|
|
15
|
+
finalAnswer: string | null;
|
|
16
|
+
tokenUsage: TokenUsage;
|
|
17
|
+
}
|
|
18
|
+
export interface DebateResult {
|
|
19
|
+
topic: string;
|
|
20
|
+
turns: DebateTurn[];
|
|
21
|
+
status: "resolved" | "unresolved" | "error";
|
|
22
|
+
errorMessage?: string;
|
|
23
|
+
totalTokenUsage: TokenUsage;
|
|
24
|
+
startedAt: string;
|
|
25
|
+
endedAt: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Orchestrates a turn-based debate between two SamuraiAgent instances
|
|
29
|
+
* (Sumurai and Ninj). Manages the transcript, iteration budget, and
|
|
30
|
+
* convergence detection. Returns a structured debate result regardless
|
|
31
|
+
* of whether the debate completed or failed mid-turn.
|
|
32
|
+
*
|
|
33
|
+
* Execution is sequential: Sumurai speaks first, then Ninj responds,
|
|
34
|
+
* alternating up to maxExchanges each.
|
|
35
|
+
*/
|
|
36
|
+
export declare function runDebate(opts: DebateOptions): Promise<DebateResult>;
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import { SamuraiAgent } from "./samurai-agent.js";
|
|
2
|
+
import { emitXcoderEvent } from "../events/bus.js";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
|
+
/**
|
|
5
|
+
* Orchestrates a turn-based debate between two SamuraiAgent instances
|
|
6
|
+
* (Sumurai and Ninj). Manages the transcript, iteration budget, and
|
|
7
|
+
* convergence detection. Returns a structured debate result regardless
|
|
8
|
+
* of whether the debate completed or failed mid-turn.
|
|
9
|
+
*
|
|
10
|
+
* Execution is sequential: Sumurai speaks first, then Ninj responds,
|
|
11
|
+
* alternating up to maxExchanges each.
|
|
12
|
+
*/
|
|
13
|
+
export async function runDebate(opts) {
|
|
14
|
+
const maxExchanges = opts.maxExchanges ?? 20;
|
|
15
|
+
const debateId = opts.debateId ?? randomUUID();
|
|
16
|
+
const startedAt = new Date().toISOString();
|
|
17
|
+
const turns = [];
|
|
18
|
+
const totalTokenUsage = { inputTokens: 0, outputTokens: 0 };
|
|
19
|
+
// Emit debate:intro
|
|
20
|
+
emitXcoderEvent({
|
|
21
|
+
type: "debate:intro",
|
|
22
|
+
taskId: debateId,
|
|
23
|
+
data: { topic: opts.topic, debateId },
|
|
24
|
+
});
|
|
25
|
+
// Build the debate system prompt context — this is prepended to each
|
|
26
|
+
// agent's goal on every turn so they know their role and the debate rules.
|
|
27
|
+
const debateContextIntro = [
|
|
28
|
+
"# Dual-AI Debate: Sumurai vs Ninj",
|
|
29
|
+
`Topic: ${opts.topic}`,
|
|
30
|
+
"",
|
|
31
|
+
"You are participating in a structured debate. Rules:",
|
|
32
|
+
"1. Each turn you speak, address the topic AND respond to your opponent's last argument.",
|
|
33
|
+
"2. Be substantive — cite evidence from the workspace, files you've read, or logical reasoning.",
|
|
34
|
+
"3. When you believe the debate has reached a natural resolution, include a summary in your final_answer.",
|
|
35
|
+
"4. Keep each response focused — this is a debate, not a monologue.",
|
|
36
|
+
"",
|
|
37
|
+
].join("\n");
|
|
38
|
+
// We create two agents with different system-prompt configurations.
|
|
39
|
+
// They share the same LlmClient and workspace but get distinct agent names.
|
|
40
|
+
const sumuraiAgent = new SamuraiAgent({
|
|
41
|
+
workspaceRoot: opts.workspaceRoot,
|
|
42
|
+
llm: opts.llm,
|
|
43
|
+
maxIterations: 20, // Each turn gets its own ReAct loop
|
|
44
|
+
model: opts.model,
|
|
45
|
+
packageJsonContext: null,
|
|
46
|
+
});
|
|
47
|
+
const ninjAgent = new SamuraiAgent({
|
|
48
|
+
workspaceRoot: opts.workspaceRoot,
|
|
49
|
+
llm: opts.llm,
|
|
50
|
+
maxIterations: 20,
|
|
51
|
+
model: opts.model,
|
|
52
|
+
packageJsonContext: null,
|
|
53
|
+
});
|
|
54
|
+
// Accumulated debate transcript — each agent sees the full history
|
|
55
|
+
let debateTranscript = debateContextIntro;
|
|
56
|
+
try {
|
|
57
|
+
for (let exchange = 0; exchange < maxExchanges; exchange++) {
|
|
58
|
+
// Sumurai's turn
|
|
59
|
+
const sumuraiTurnNumber = exchange * 2 + 1;
|
|
60
|
+
emitXcoderEvent({
|
|
61
|
+
type: "debate:turn-start",
|
|
62
|
+
taskId: debateId,
|
|
63
|
+
data: { agent: "Sumurai", turnNumber: sumuraiTurnNumber, role: exchange === 0 ? "opening" : "response" },
|
|
64
|
+
});
|
|
65
|
+
const sumuraiGoal = buildTurnGoal("Sumurai", opts.topic, debateTranscript, exchange, exchange === 0 ? "opening" : "response");
|
|
66
|
+
let sumuraiResult;
|
|
67
|
+
try {
|
|
68
|
+
sumuraiResult = await sumuraiAgent.runOnce(sumuraiGoal, {
|
|
69
|
+
onStep: (step) => {
|
|
70
|
+
if (step.action) {
|
|
71
|
+
emitXcoderEvent({
|
|
72
|
+
type: "debate:agent-action",
|
|
73
|
+
taskId: debateId,
|
|
74
|
+
data: { agent: "Sumurai", turnNumber: sumuraiTurnNumber, tool: step.action.tool, input: step.action.input },
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
else if (step.observation === "final_answer submitted") {
|
|
78
|
+
emitXcoderEvent({
|
|
79
|
+
type: "debate:agent-final",
|
|
80
|
+
taskId: debateId,
|
|
81
|
+
data: { agent: "Sumurai", turnNumber: sumuraiTurnNumber, summary: step.thought },
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
// Always emit thought
|
|
85
|
+
emitXcoderEvent({
|
|
86
|
+
type: "debate:agent-thought",
|
|
87
|
+
taskId: debateId,
|
|
88
|
+
data: { agent: "Sumurai", turnNumber: sumuraiTurnNumber, thought: step.thought },
|
|
89
|
+
});
|
|
90
|
+
// Emit observation if any
|
|
91
|
+
if (step.action) {
|
|
92
|
+
emitXcoderEvent({
|
|
93
|
+
type: "debate:agent-observation",
|
|
94
|
+
taskId: debateId,
|
|
95
|
+
data: { agent: "Sumurai", turnNumber: sumuraiTurnNumber, ok: step.observation !== undefined, observation: step.observation },
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
onTokens: (cumulative) => {
|
|
100
|
+
emitXcoderEvent({
|
|
101
|
+
type: "debate:agent-tokens",
|
|
102
|
+
taskId: debateId,
|
|
103
|
+
data: { agent: "Sumurai", turnNumber: sumuraiTurnNumber, cumulative },
|
|
104
|
+
});
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
catch (e) {
|
|
109
|
+
emitXcoderEvent({
|
|
110
|
+
type: "debate:outro",
|
|
111
|
+
taskId: debateId,
|
|
112
|
+
data: { status: "error", errorMessage: `Sumurai crashed on exchange ${exchange + 1}: ${e.message}`, totalTokenUsage, turns: turns.length },
|
|
113
|
+
});
|
|
114
|
+
return {
|
|
115
|
+
topic: opts.topic,
|
|
116
|
+
turns,
|
|
117
|
+
status: "error",
|
|
118
|
+
errorMessage: `Sumurai crashed on exchange ${exchange + 1}: ${e.message}`,
|
|
119
|
+
totalTokenUsage,
|
|
120
|
+
startedAt,
|
|
121
|
+
endedAt: new Date().toISOString(),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
totalTokenUsage.inputTokens += sumuraiResult.tokenUsage.inputTokens;
|
|
125
|
+
totalTokenUsage.outputTokens += sumuraiResult.tokenUsage.outputTokens;
|
|
126
|
+
const sumuraiTurn = {
|
|
127
|
+
agent: "Sumurai",
|
|
128
|
+
turnNumber: sumuraiTurnNumber,
|
|
129
|
+
raoTrace: sumuraiResult.raoTrace,
|
|
130
|
+
finalAnswer: sumuraiResult.summary,
|
|
131
|
+
tokenUsage: sumuraiResult.tokenUsage,
|
|
132
|
+
};
|
|
133
|
+
turns.push(sumuraiTurn);
|
|
134
|
+
// Append Sumurai's contribution to debate transcript
|
|
135
|
+
debateTranscript += `\n\n## Sumurai (turn ${sumuraiTurnNumber})\n${sumuraiResult.summary}\n`;
|
|
136
|
+
// Ninj's turn
|
|
137
|
+
const ninjTurnNumber = exchange * 2 + 2;
|
|
138
|
+
emitXcoderEvent({
|
|
139
|
+
type: "debate:turn-start",
|
|
140
|
+
taskId: debateId,
|
|
141
|
+
data: { agent: "Ninj", turnNumber: ninjTurnNumber, role: "response" },
|
|
142
|
+
});
|
|
143
|
+
const ninjGoal = buildTurnGoal("Ninj", opts.topic, debateTranscript, exchange, "response");
|
|
144
|
+
let ninjResult;
|
|
145
|
+
try {
|
|
146
|
+
ninjResult = await ninjAgent.runOnce(ninjGoal, {
|
|
147
|
+
onStep: (step) => {
|
|
148
|
+
if (step.action) {
|
|
149
|
+
emitXcoderEvent({
|
|
150
|
+
type: "debate:agent-action",
|
|
151
|
+
taskId: debateId,
|
|
152
|
+
data: { agent: "Ninj", turnNumber: ninjTurnNumber, tool: step.action.tool, input: step.action.input },
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
else if (step.observation === "final_answer submitted") {
|
|
156
|
+
emitXcoderEvent({
|
|
157
|
+
type: "debate:agent-final",
|
|
158
|
+
taskId: debateId,
|
|
159
|
+
data: { agent: "Ninj", turnNumber: ninjTurnNumber, summary: step.thought },
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
emitXcoderEvent({
|
|
163
|
+
type: "debate:agent-thought",
|
|
164
|
+
taskId: debateId,
|
|
165
|
+
data: { agent: "Ninj", turnNumber: ninjTurnNumber, thought: step.thought },
|
|
166
|
+
});
|
|
167
|
+
if (step.action) {
|
|
168
|
+
emitXcoderEvent({
|
|
169
|
+
type: "debate:agent-observation",
|
|
170
|
+
taskId: debateId,
|
|
171
|
+
data: { agent: "Ninj", turnNumber: ninjTurnNumber, ok: step.observation !== undefined, observation: step.observation },
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
onTokens: (cumulative) => {
|
|
176
|
+
emitXcoderEvent({
|
|
177
|
+
type: "debate:agent-tokens",
|
|
178
|
+
taskId: debateId,
|
|
179
|
+
data: { agent: "Ninj", turnNumber: ninjTurnNumber, cumulative },
|
|
180
|
+
});
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
catch (e) {
|
|
185
|
+
emitXcoderEvent({
|
|
186
|
+
type: "debate:outro",
|
|
187
|
+
taskId: debateId,
|
|
188
|
+
data: { status: "error", errorMessage: `Ninj crashed on exchange ${exchange + 1}: ${e.message}`, totalTokenUsage, turns: turns.length },
|
|
189
|
+
});
|
|
190
|
+
return {
|
|
191
|
+
topic: opts.topic,
|
|
192
|
+
turns,
|
|
193
|
+
status: "error",
|
|
194
|
+
errorMessage: `Ninj crashed on exchange ${exchange + 1}: ${e.message}`,
|
|
195
|
+
totalTokenUsage,
|
|
196
|
+
startedAt,
|
|
197
|
+
endedAt: new Date().toISOString(),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
totalTokenUsage.inputTokens += ninjResult.tokenUsage.inputTokens;
|
|
201
|
+
totalTokenUsage.outputTokens += ninjResult.tokenUsage.outputTokens;
|
|
202
|
+
const ninjTurn = {
|
|
203
|
+
agent: "Ninj",
|
|
204
|
+
turnNumber: ninjTurnNumber,
|
|
205
|
+
raoTrace: ninjResult.raoTrace,
|
|
206
|
+
finalAnswer: ninjResult.summary,
|
|
207
|
+
tokenUsage: ninjResult.tokenUsage,
|
|
208
|
+
};
|
|
209
|
+
turns.push(ninjTurn);
|
|
210
|
+
// Append Ninj's contribution to debate transcript
|
|
211
|
+
debateTranscript += `\n\n## Ninj (turn ${ninjTurnNumber})\n${ninjResult.summary}\n`;
|
|
212
|
+
// Convergence check: do both agents' summaries indicate resolution?
|
|
213
|
+
if (detectConvergence(sumuraiResult.summary, ninjResult.summary)) {
|
|
214
|
+
emitXcoderEvent({
|
|
215
|
+
type: "debate:outro",
|
|
216
|
+
taskId: debateId,
|
|
217
|
+
data: { status: "resolved", totalTokenUsage, turns: turns.length },
|
|
218
|
+
});
|
|
219
|
+
return {
|
|
220
|
+
topic: opts.topic,
|
|
221
|
+
turns,
|
|
222
|
+
status: "resolved",
|
|
223
|
+
totalTokenUsage,
|
|
224
|
+
startedAt,
|
|
225
|
+
endedAt: new Date().toISOString(),
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
// Exhausted max exchanges without convergence
|
|
230
|
+
emitXcoderEvent({
|
|
231
|
+
type: "debate:outro",
|
|
232
|
+
taskId: debateId,
|
|
233
|
+
data: { status: "unresolved", totalTokenUsage, turns: turns.length },
|
|
234
|
+
});
|
|
235
|
+
return {
|
|
236
|
+
topic: opts.topic,
|
|
237
|
+
turns,
|
|
238
|
+
status: "unresolved",
|
|
239
|
+
totalTokenUsage,
|
|
240
|
+
startedAt,
|
|
241
|
+
endedAt: new Date().toISOString(),
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
catch (e) {
|
|
245
|
+
// Catch-all for unexpected errors during the debate orchestration itself
|
|
246
|
+
emitXcoderEvent({
|
|
247
|
+
type: "debate:outro",
|
|
248
|
+
taskId: debateId,
|
|
249
|
+
data: { status: "error", errorMessage: `Debate orchestration failed: ${e.message}`, totalTokenUsage, turns: turns.length },
|
|
250
|
+
});
|
|
251
|
+
return {
|
|
252
|
+
topic: opts.topic,
|
|
253
|
+
turns,
|
|
254
|
+
status: "error",
|
|
255
|
+
errorMessage: `Debate orchestration failed: ${e.message}`,
|
|
256
|
+
totalTokenUsage,
|
|
257
|
+
startedAt,
|
|
258
|
+
endedAt: new Date().toISOString(),
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Builds the goal string for a single debate turn.
|
|
264
|
+
* Includes the full debate transcript so far and instructions specific
|
|
265
|
+
* to whether this is an opening or response turn.
|
|
266
|
+
*/
|
|
267
|
+
function buildTurnGoal(agentName, topic, transcript, exchange, role) {
|
|
268
|
+
const turnInstruction = role === "opening"
|
|
269
|
+
? `You are ${agentName}, opening the debate. Present your initial position on the topic.`
|
|
270
|
+
: `You are ${agentName}, responding in the debate. Address your opponent's last points and strengthen your position.`;
|
|
271
|
+
return [
|
|
272
|
+
turnInstruction,
|
|
273
|
+
"",
|
|
274
|
+
"Debate transcript so far:",
|
|
275
|
+
`${transcript}`,
|
|
276
|
+
"",
|
|
277
|
+
`Exchange ${exchange + 1}: It is your turn to speak as ${agentName}. Provide your argument.`,
|
|
278
|
+
].join("\n");
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Simple heuristic for convergence detection: both agents' final summaries
|
|
282
|
+
* contain keywords indicating they've reached a conclusion.
|
|
283
|
+
*/
|
|
284
|
+
function detectConvergence(sumuraiSummary, ninjSummary) {
|
|
285
|
+
const resolutionKeywords = [
|
|
286
|
+
"summary",
|
|
287
|
+
"conclusion",
|
|
288
|
+
"resolution",
|
|
289
|
+
"agreed",
|
|
290
|
+
"consensus",
|
|
291
|
+
"final",
|
|
292
|
+
"closing",
|
|
293
|
+
"settled",
|
|
294
|
+
];
|
|
295
|
+
const sumuraiLower = sumuraiSummary.toLowerCase();
|
|
296
|
+
const ninjLower = ninjSummary.toLowerCase();
|
|
297
|
+
const sumuraiHasResolution = resolutionKeywords.some((kw) => sumuraiLower.includes(kw));
|
|
298
|
+
const ninjHasResolution = resolutionKeywords.some((kw) => ninjLower.includes(kw));
|
|
299
|
+
return sumuraiHasResolution && ninjHasResolution;
|
|
300
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DebateResult } from "./ai-chat-debate.js";
|
|
2
|
+
/**
|
|
3
|
+
* Formats a DebateResult into a timestamped Markdown report file and writes
|
|
4
|
+
* it to disk. If a partial error occurred, writes whatever turns were
|
|
5
|
+
* completed plus an error note at the end.
|
|
6
|
+
*/
|
|
7
|
+
export declare function writeReport(result: DebateResult, outputDir: string): Promise<string>;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* Formats a DebateResult into a timestamped Markdown report file and writes
|
|
5
|
+
* it to disk. If a partial error occurred, writes whatever turns were
|
|
6
|
+
* completed plus an error note at the end.
|
|
7
|
+
*/
|
|
8
|
+
export async function writeReport(result, outputDir) {
|
|
9
|
+
await fs.mkdir(outputDir, { recursive: true });
|
|
10
|
+
const ts = new Date()
|
|
11
|
+
.toISOString()
|
|
12
|
+
.replace(/[-:]/g, "")
|
|
13
|
+
.replace(/\..+/, "");
|
|
14
|
+
const filename = `ai-chat-report-${ts}.md`;
|
|
15
|
+
const filePath = path.join(outputDir, filename);
|
|
16
|
+
const md = formatReport(result);
|
|
17
|
+
await fs.writeFile(filePath, md, "utf-8");
|
|
18
|
+
return filePath;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Formats a DebateResult into Markdown.
|
|
22
|
+
*/
|
|
23
|
+
function formatReport(result) {
|
|
24
|
+
const lines = [];
|
|
25
|
+
// Header
|
|
26
|
+
lines.push(`# AI Chat Debate Report: ${result.topic}`);
|
|
27
|
+
lines.push("");
|
|
28
|
+
lines.push(`- **Status**: ${result.status}`);
|
|
29
|
+
lines.push(`- **Started**: ${result.startedAt}`);
|
|
30
|
+
lines.push(`- **Ended**: ${result.endedAt}`);
|
|
31
|
+
lines.push(`- **Turns**: ${result.turns.length}`);
|
|
32
|
+
lines.push(`- **Total Token Usage**: ${result.totalTokenUsage.inputTokens} input / ${result.totalTokenUsage.outputTokens} output`);
|
|
33
|
+
if (result.errorMessage) {
|
|
34
|
+
lines.push(`- **Error**: ${result.errorMessage}`);
|
|
35
|
+
}
|
|
36
|
+
lines.push("");
|
|
37
|
+
lines.push("---");
|
|
38
|
+
lines.push("");
|
|
39
|
+
// Transcript
|
|
40
|
+
if (result.turns.length === 0) {
|
|
41
|
+
lines.push("_No debate turns were recorded._");
|
|
42
|
+
lines.push("");
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
lines.push("## Debate Transcript");
|
|
46
|
+
lines.push("");
|
|
47
|
+
for (const turn of result.turns) {
|
|
48
|
+
lines.push(`### ${turn.agent} — Turn ${turn.turnNumber}`);
|
|
49
|
+
lines.push("");
|
|
50
|
+
if (turn.finalAnswer) {
|
|
51
|
+
lines.push(`**Final Answer:** ${turn.finalAnswer}`);
|
|
52
|
+
lines.push("");
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
lines.push(`**Final Answer:** _(no final answer produced)_`);
|
|
56
|
+
lines.push("");
|
|
57
|
+
}
|
|
58
|
+
lines.push(`**Token Usage:** ${turn.tokenUsage.inputTokens} input / ${turn.tokenUsage.outputTokens} output`);
|
|
59
|
+
lines.push("");
|
|
60
|
+
// ReAct trace details
|
|
61
|
+
if (turn.raoTrace.length > 0) {
|
|
62
|
+
lines.push("<details>");
|
|
63
|
+
lines.push("<summary>ReAct Trace (click to expand)</summary>");
|
|
64
|
+
lines.push("");
|
|
65
|
+
lines.push("| # | Thought | Action | Observation |");
|
|
66
|
+
lines.push("|---|---------|--------|-------------|");
|
|
67
|
+
for (let i = 0; i < turn.raoTrace.length; i++) {
|
|
68
|
+
const step = turn.raoTrace[i];
|
|
69
|
+
const thought = escapeMarkdown(truncate(step.thought, 200));
|
|
70
|
+
const action = step.action
|
|
71
|
+
? escapeMarkdown(`${step.action.tool}(${truncate(JSON.stringify(step.action.input), 100)})`)
|
|
72
|
+
: "—";
|
|
73
|
+
const observation = escapeMarkdown(truncate(step.observation, 200));
|
|
74
|
+
lines.push(`| ${i + 1} | ${thought} | ${action} | ${observation} |`);
|
|
75
|
+
}
|
|
76
|
+
lines.push("");
|
|
77
|
+
lines.push("</details>");
|
|
78
|
+
lines.push("");
|
|
79
|
+
}
|
|
80
|
+
lines.push("---");
|
|
81
|
+
lines.push("");
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Error note
|
|
85
|
+
if (result.errorMessage) {
|
|
86
|
+
lines.push("## Error");
|
|
87
|
+
lines.push("");
|
|
88
|
+
lines.push(`The debate did not complete successfully: ${result.errorMessage}`);
|
|
89
|
+
lines.push("");
|
|
90
|
+
}
|
|
91
|
+
return lines.join("\n");
|
|
92
|
+
}
|
|
93
|
+
function escapeMarkdown(text) {
|
|
94
|
+
return text.replace(/[|\\`*_{}[\]()#+\-.!]/g, "\\$&");
|
|
95
|
+
}
|
|
96
|
+
function truncate(text, maxLen) {
|
|
97
|
+
if (text.length <= maxLen)
|
|
98
|
+
return text;
|
|
99
|
+
return text.slice(0, maxLen - 3) + "...";
|
|
100
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built directly from real evidence, not speculation: a production run's
|
|
3
|
+
* `code` subtask re-read the same design document 11 times across its
|
|
4
|
+
* attempts (multiple times WITHIN a single attempt, not just once per
|
|
5
|
+
* fresh retry) and repeatedly re-checked for files it hadn't created yet,
|
|
6
|
+
* leaving almost none of its 25-iteration budget for actual file writing.
|
|
7
|
+
* That pattern — the exact same (thought, action) pair recurring — is
|
|
8
|
+
* cheap to detect and, left unflagged, silently burns the entire
|
|
9
|
+
* iteration budget on zero net progress.
|
|
10
|
+
*
|
|
11
|
+
* Scope: per SubAgent.run() call (one attempt), not persisted across
|
|
12
|
+
* healing retries — a fresh attempt gets a fresh detector, since a brand
|
|
13
|
+
* new transcript legitimately has no memory of the previous attempt's
|
|
14
|
+
* actions anyway (that's `sdlc-orchestrator.ts`'s file-carryover
|
|
15
|
+
* healing hint's job, not this one's).
|
|
16
|
+
*/
|
|
17
|
+
export interface DuplicateCheckResult {
|
|
18
|
+
isDuplicate: boolean;
|
|
19
|
+
priorIterations: number[];
|
|
20
|
+
/** True once total duplicate incidents in this attempt cross the abort threshold — the caller should stop the attempt rather than keep burning budget. */
|
|
21
|
+
stuck: boolean;
|
|
22
|
+
/** Non-null whenever isDuplicate is true — meant to be surfaced back to the model as part of the observation. */
|
|
23
|
+
warning: string | null;
|
|
24
|
+
}
|
|
25
|
+
export declare function actionKey(tool: string, input: unknown): string;
|
|
26
|
+
export declare class DuplicateActionDetector {
|
|
27
|
+
private abortAfterTotalDuplicates;
|
|
28
|
+
private seen;
|
|
29
|
+
private totalDuplicates;
|
|
30
|
+
/**
|
|
31
|
+
* @param abortAfterTotalDuplicates total duplicate incidents (not
|
|
32
|
+
* necessarily of the same action — any repeats, summed) across the
|
|
33
|
+
* whole attempt before it's treated as a stuck loop. 5 is deliberately
|
|
34
|
+
* generous: a couple of legitimate re-checks shouldn't trip this, but
|
|
35
|
+
* the 11-repeat pattern that motivated this class would trip it early
|
|
36
|
+
* instead of running to the full 25-iteration cap.
|
|
37
|
+
*/
|
|
38
|
+
constructor(abortAfterTotalDuplicates?: number);
|
|
39
|
+
check(thought: string, tool: string, input: unknown, iteration: number): DuplicateCheckResult;
|
|
40
|
+
get duplicateCount(): number;
|
|
41
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built directly from real evidence, not speculation: a production run's
|
|
3
|
+
* `code` subtask re-read the same design document 11 times across its
|
|
4
|
+
* attempts (multiple times WITHIN a single attempt, not just once per
|
|
5
|
+
* fresh retry) and repeatedly re-checked for files it hadn't created yet,
|
|
6
|
+
* leaving almost none of its 25-iteration budget for actual file writing.
|
|
7
|
+
* That pattern — the exact same (thought, action) pair recurring — is
|
|
8
|
+
* cheap to detect and, left unflagged, silently burns the entire
|
|
9
|
+
* iteration budget on zero net progress.
|
|
10
|
+
*
|
|
11
|
+
* Scope: per SubAgent.run() call (one attempt), not persisted across
|
|
12
|
+
* healing retries — a fresh attempt gets a fresh detector, since a brand
|
|
13
|
+
* new transcript legitimately has no memory of the previous attempt's
|
|
14
|
+
* actions anyway (that's `sdlc-orchestrator.ts`'s file-carryover
|
|
15
|
+
* healing hint's job, not this one's).
|
|
16
|
+
*/
|
|
17
|
+
/** Recursively sorts object keys before stringifying, so two structurally-identical inputs compare equal regardless of key order the model happened to emit them in. */
|
|
18
|
+
function stableStringify(value) {
|
|
19
|
+
if (value === null || typeof value !== "object")
|
|
20
|
+
return JSON.stringify(value);
|
|
21
|
+
if (Array.isArray(value))
|
|
22
|
+
return `[${value.map(stableStringify).join(",")}]`;
|
|
23
|
+
const keys = Object.keys(value).sort();
|
|
24
|
+
return `{${keys.map((k) => `${JSON.stringify(k)}:${stableStringify(value[k])}`).join(",")}}`;
|
|
25
|
+
}
|
|
26
|
+
function normalizeThought(thought) {
|
|
27
|
+
return thought.trim().toLowerCase().replace(/\s+/g, " ");
|
|
28
|
+
}
|
|
29
|
+
export function actionKey(tool, input) {
|
|
30
|
+
return `${tool}::${stableStringify(input)}`;
|
|
31
|
+
}
|
|
32
|
+
export class DuplicateActionDetector {
|
|
33
|
+
abortAfterTotalDuplicates;
|
|
34
|
+
seen = new Map(); // "thought|||tool::input" -> iteration numbers where it occurred
|
|
35
|
+
totalDuplicates = 0;
|
|
36
|
+
/**
|
|
37
|
+
* @param abortAfterTotalDuplicates total duplicate incidents (not
|
|
38
|
+
* necessarily of the same action — any repeats, summed) across the
|
|
39
|
+
* whole attempt before it's treated as a stuck loop. 5 is deliberately
|
|
40
|
+
* generous: a couple of legitimate re-checks shouldn't trip this, but
|
|
41
|
+
* the 11-repeat pattern that motivated this class would trip it early
|
|
42
|
+
* instead of running to the full 25-iteration cap.
|
|
43
|
+
*/
|
|
44
|
+
constructor(abortAfterTotalDuplicates = 5) {
|
|
45
|
+
this.abortAfterTotalDuplicates = abortAfterTotalDuplicates;
|
|
46
|
+
}
|
|
47
|
+
check(thought, tool, input, iteration) {
|
|
48
|
+
const key = `${normalizeThought(thought)}|||${actionKey(tool, input)}`;
|
|
49
|
+
const prior = this.seen.get(key) ?? [];
|
|
50
|
+
const isDuplicate = prior.length > 0;
|
|
51
|
+
if (isDuplicate)
|
|
52
|
+
this.totalDuplicates++;
|
|
53
|
+
this.seen.set(key, [...prior, iteration]);
|
|
54
|
+
const stuck = this.totalDuplicates >= this.abortAfterTotalDuplicates;
|
|
55
|
+
const warning = isDuplicate
|
|
56
|
+
? `duplicate detected: this exact reasoning + action ("${tool}") was already tried at iteration ${prior.at(-1)}` +
|
|
57
|
+
`${prior.length > 1 ? ` (and ${prior.length - 1} time(s) before that)` : ""} — it produced no new information ` +
|
|
58
|
+
`last time. Try a genuinely different approach instead of repeating it.`
|
|
59
|
+
: null;
|
|
60
|
+
return { isDuplicate, priorIterations: prior, stuck, warning };
|
|
61
|
+
}
|
|
62
|
+
get duplicateCount() {
|
|
63
|
+
return this.totalDuplicates;
|
|
64
|
+
}
|
|
65
|
+
}
|