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
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// xcoder:version 1 | xcoder:task task-edfac1 | xcoder:updated 2026-08-04T09:23:09.377Z | xcoder:subtask code-st-21c578
|
|
2
|
+
/**
|
|
3
|
+
* Cross-platform process tree killer.
|
|
4
|
+
*
|
|
5
|
+
* On Windows: uses `taskkill /F /T /PID <pid>`
|
|
6
|
+
* On Unix: uses `kill(-pid)` to signal the entire process group;
|
|
7
|
+
* falls back to recursive pgrep-based killing for resilience.
|
|
8
|
+
*/
|
|
9
|
+
import { execSync } from "node:child_process";
|
|
10
|
+
/**
|
|
11
|
+
* Kill a process and all of its descendants.
|
|
12
|
+
*
|
|
13
|
+
* @param rootPid - The PID of the root process to kill.
|
|
14
|
+
* @param signal - 'SIGTERM' for graceful, 'SIGKILL' for force.
|
|
15
|
+
* @returns Promise that resolves when all descendants are confirmed dead or after 3s timeout.
|
|
16
|
+
*/
|
|
17
|
+
export function killProcessTree(rootPid, signal = "SIGKILL") {
|
|
18
|
+
return new Promise((resolve) => {
|
|
19
|
+
if (process.platform === "win32") {
|
|
20
|
+
killWindowsTree(rootPid, signal, resolve);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
killUnixTree(rootPid, signal, resolve);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function killWindowsTree(rootPid, signal, resolve) {
|
|
28
|
+
const forceFlag = signal === "SIGKILL" ? " /F" : "";
|
|
29
|
+
try {
|
|
30
|
+
execSync(`taskkill${forceFlag} /T /PID ${rootPid}`, {
|
|
31
|
+
timeout: 3000,
|
|
32
|
+
stdio: "pipe",
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// taskkill may fail if process already exited — that's fine.
|
|
37
|
+
}
|
|
38
|
+
resolve();
|
|
39
|
+
}
|
|
40
|
+
function killUnixTree(rootPid, signal, resolve) {
|
|
41
|
+
const sigNum = signal === "SIGKILL" ? 9 : 15;
|
|
42
|
+
// Try process-group kill first (cleanest).
|
|
43
|
+
try {
|
|
44
|
+
process.kill(-rootPid, sigNum);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Process group may not exist; fall through to recursive kill.
|
|
48
|
+
}
|
|
49
|
+
// Recursive pgrep kill as a fallback to ensure all children are dead.
|
|
50
|
+
try {
|
|
51
|
+
const descendants = getUnixDescendants(rootPid);
|
|
52
|
+
for (const pid of descendants) {
|
|
53
|
+
try {
|
|
54
|
+
process.kill(pid, sigNum);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// process already dead.
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// pgrep may not be available — process-group kill is best-effort.
|
|
63
|
+
}
|
|
64
|
+
// Give a short grace period, then resolve.
|
|
65
|
+
setTimeout(resolve, 500);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Recursively collect all child PIDs under rootPid using `pgrep -P`.
|
|
69
|
+
*/
|
|
70
|
+
function getUnixDescendants(rootPid) {
|
|
71
|
+
const pids = [];
|
|
72
|
+
try {
|
|
73
|
+
const raw = execSync(`pgrep -P ${rootPid}`, {
|
|
74
|
+
timeout: 2000,
|
|
75
|
+
stdio: "pipe",
|
|
76
|
+
encoding: "utf8",
|
|
77
|
+
});
|
|
78
|
+
const children = raw
|
|
79
|
+
.trim()
|
|
80
|
+
.split("\n")
|
|
81
|
+
.filter(Boolean)
|
|
82
|
+
.map(Number)
|
|
83
|
+
.filter((n) => !isNaN(n));
|
|
84
|
+
for (const child of children) {
|
|
85
|
+
pids.push(child);
|
|
86
|
+
// Recurse into grandchildren.
|
|
87
|
+
pids.push(...getUnixDescendants(child));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// pgrep may not be available or already exited.
|
|
92
|
+
}
|
|
93
|
+
return pids;
|
|
94
|
+
}
|
|
95
|
+
// ── Global tracked PIDs ──
|
|
96
|
+
/**
|
|
97
|
+
* A Set of tracked child process PIDs. Used by the signal handler to
|
|
98
|
+
* kill any surviving child processes on forced exit.
|
|
99
|
+
*/
|
|
100
|
+
export const trackedPids = new Set();
|
|
101
|
+
/**
|
|
102
|
+
* Register a pid for cleanup tracking. Safe to call multiple times
|
|
103
|
+
* (Set deduplicates).
|
|
104
|
+
*/
|
|
105
|
+
export function trackPid(pid) {
|
|
106
|
+
trackedPids.add(pid);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Remove a pid from tracking (called when process exits normally).
|
|
110
|
+
*/
|
|
111
|
+
export function untrackPid(pid) {
|
|
112
|
+
trackedPids.delete(pid);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Kill all tracked PIDs and clear the set. Used in process 'exit'
|
|
116
|
+
* handler as a safety net to prevent orphaned processes.
|
|
117
|
+
*/
|
|
118
|
+
export async function killTrackedPids() {
|
|
119
|
+
const pids = Array.from(trackedPids);
|
|
120
|
+
trackedPids.clear();
|
|
121
|
+
for (const pid of pids) {
|
|
122
|
+
await killProcessTree(pid, "SIGKILL");
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Register an exit handler that kills any remaining tracked PIDs.
|
|
126
|
+
process.on("exit", () => {
|
|
127
|
+
// Synchronous cleanup on exit: spawn taskkill/kill synchronously.
|
|
128
|
+
const pids = Array.from(trackedPids);
|
|
129
|
+
trackedPids.clear();
|
|
130
|
+
for (const pid of pids) {
|
|
131
|
+
try {
|
|
132
|
+
if (process.platform === "win32") {
|
|
133
|
+
execSync(`taskkill /F /T /PID ${pid}`, { timeout: 2000, stdio: "ignore" });
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
try {
|
|
137
|
+
process.kill(-pid, 9);
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
// ignore
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// ignore — process already dead.
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Called once at startup by the CLI action handler when --debug-protocol-error
|
|
3
|
+
* or PROTOCOL_ERROR_LOG is active. Sets module-level enabled flag. If logPath
|
|
4
|
+
* is provided, uses it; otherwise defaults to <cwd>/protocol_error.log.
|
|
5
|
+
*/
|
|
6
|
+
export declare function enableProtocolErrorLogging(customPath?: string, opts?: {
|
|
7
|
+
silent?: boolean;
|
|
8
|
+
}): void;
|
|
9
|
+
/** Read-only guard so call sites can conditionally gather data. */
|
|
10
|
+
export declare function isProtocolErrorLoggingEnabled(): boolean;
|
|
11
|
+
/** The data contract for each ndjson line. */
|
|
12
|
+
export interface ProtocolErrorLogEntry {
|
|
13
|
+
ts: string;
|
|
14
|
+
taskId: string;
|
|
15
|
+
agentId: string;
|
|
16
|
+
iteration: number;
|
|
17
|
+
error: string;
|
|
18
|
+
raw: string;
|
|
19
|
+
model: string;
|
|
20
|
+
stopReason: string | null;
|
|
21
|
+
inputTokens: number;
|
|
22
|
+
outputTokens: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Appends one ndjson line to the log file. Never throws — all write
|
|
26
|
+
* failures are silently swallowed. Uses an internal promise-chain mutex to
|
|
27
|
+
* serialise appends without blocking the caller.
|
|
28
|
+
*
|
|
29
|
+
* On the FIRST call, writes a `#`-prefixed header block if the file
|
|
30
|
+
* doesn't already exist (checked via synchronous existsSync — cheap,
|
|
31
|
+
* and only happens on the first error which is rare).
|
|
32
|
+
*/
|
|
33
|
+
export declare function logProtocolError(entry: ProtocolErrorLogEntry): void;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// xcoder:version 1 | xcoder:task task-54c54e | xcoder:updated 2026-08-04T15:30:01.164Z | xcoder:subtask code-st-43fc58
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import { promises as fsp } from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { log } from "./logger.js";
|
|
6
|
+
import { getOutputPaths } from "./output-paths.js";
|
|
7
|
+
// ── Module-level state ──
|
|
8
|
+
let enabled = false;
|
|
9
|
+
let logPath = null;
|
|
10
|
+
/** Serialises writes so parallel agents don't interleave lines. */
|
|
11
|
+
let writeChain = Promise.resolve();
|
|
12
|
+
let headerWritten = false;
|
|
13
|
+
// ── Public API ──
|
|
14
|
+
/**
|
|
15
|
+
* Called once at startup by the CLI action handler when --debug-protocol-error
|
|
16
|
+
* or PROTOCOL_ERROR_LOG is active. Sets module-level enabled flag. If logPath
|
|
17
|
+
* is provided, uses it; otherwise defaults to <cwd>/protocol_error.log.
|
|
18
|
+
*/
|
|
19
|
+
export function enableProtocolErrorLogging(customPath, opts) {
|
|
20
|
+
enabled = true;
|
|
21
|
+
if (customPath) {
|
|
22
|
+
logPath = path.resolve(customPath);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
const outputs = getOutputPaths();
|
|
26
|
+
outputs.ensureGitignore();
|
|
27
|
+
logPath = outputs.protocolErrorLogPath();
|
|
28
|
+
}
|
|
29
|
+
if (!opts?.silent) {
|
|
30
|
+
log.dim(`protocol_error diagnostic log: ${logPath}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** Read-only guard so call sites can conditionally gather data. */
|
|
34
|
+
export function isProtocolErrorLoggingEnabled() {
|
|
35
|
+
return enabled;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Appends one ndjson line to the log file. Never throws — all write
|
|
39
|
+
* failures are silently swallowed. Uses an internal promise-chain mutex to
|
|
40
|
+
* serialise appends without blocking the caller.
|
|
41
|
+
*
|
|
42
|
+
* On the FIRST call, writes a `#`-prefixed header block if the file
|
|
43
|
+
* doesn't already exist (checked via synchronous existsSync — cheap,
|
|
44
|
+
* and only happens on the first error which is rare).
|
|
45
|
+
*/
|
|
46
|
+
export function logProtocolError(entry) {
|
|
47
|
+
if (!enabled || !logPath)
|
|
48
|
+
return;
|
|
49
|
+
writeChain = writeChain.then(async () => {
|
|
50
|
+
try {
|
|
51
|
+
// Write header once, before the first entry.
|
|
52
|
+
if (!headerWritten) {
|
|
53
|
+
const fileExists = fs.existsSync(logPath);
|
|
54
|
+
if (!fileExists) {
|
|
55
|
+
const header = [
|
|
56
|
+
"# Xcoder SDLC protocol_error diagnostic log",
|
|
57
|
+
`# Created: ${new Date().toISOString()}`,
|
|
58
|
+
"# Fields: ts, taskId, agentId, iteration, error, raw, model, stopReason, inputTokens, outputTokens",
|
|
59
|
+
"# Enabled by: --debug-protocol-error flag | PROTOCOL_ERROR_LOG env var",
|
|
60
|
+
"",
|
|
61
|
+
].join("\n");
|
|
62
|
+
await fsp.appendFile(logPath, header, "utf-8");
|
|
63
|
+
}
|
|
64
|
+
headerWritten = true;
|
|
65
|
+
}
|
|
66
|
+
const line = JSON.stringify(entry) + "\n";
|
|
67
|
+
await fsp.appendFile(logPath, line, "utf-8");
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// Silently swallow — diagnostic logging must never break the agent loop.
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret redaction for prompt/LLM logging (PRM-10 / CORE-07 / CORE-08).
|
|
3
|
+
*
|
|
4
|
+
* `appendLlm` runs every request/response body through `redactSecrets` before
|
|
5
|
+
* writing, so a key pasted into a prompt, echoed by a model, or captured in a
|
|
6
|
+
* tool observation never lands in the task llm.log under `.xcoder/logs`.
|
|
7
|
+
*
|
|
8
|
+
* Deliberately has NO module-load dependency on config/secret values — that
|
|
9
|
+
* would create a circular import with config loading. Pattern-based only.
|
|
10
|
+
* Never throws.
|
|
11
|
+
*/
|
|
12
|
+
export interface RedactionCount {
|
|
13
|
+
readonly kind: string;
|
|
14
|
+
readonly count: number;
|
|
15
|
+
}
|
|
16
|
+
export interface RedactionResult {
|
|
17
|
+
readonly text: string;
|
|
18
|
+
readonly redactions: readonly RedactionCount[];
|
|
19
|
+
}
|
|
20
|
+
export declare const REDACTED = "[REDACTED]";
|
|
21
|
+
/**
|
|
22
|
+
* Masks API-key shapes, bearer tokens, private-key blocks and secret
|
|
23
|
+
* assignments. Never throws; benign text is returned unchanged.
|
|
24
|
+
*/
|
|
25
|
+
export declare function redactSecrets(text: string): RedactionResult;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// xcoder:version 3 | xcoder:task task-ebf4f7 | xcoder:updated 2026-10-17T12:17:28.413Z | xcoder:subtask test-st-f454da
|
|
2
|
+
/**
|
|
3
|
+
* Secret redaction for prompt/LLM logging (PRM-10 / CORE-07 / CORE-08).
|
|
4
|
+
*
|
|
5
|
+
* `appendLlm` runs every request/response body through `redactSecrets` before
|
|
6
|
+
* writing, so a key pasted into a prompt, echoed by a model, or captured in a
|
|
7
|
+
* tool observation never lands in the task llm.log under `.xcoder/logs`.
|
|
8
|
+
*
|
|
9
|
+
* Deliberately has NO module-load dependency on config/secret values — that
|
|
10
|
+
* would create a circular import with config loading. Pattern-based only.
|
|
11
|
+
* Never throws.
|
|
12
|
+
*/
|
|
13
|
+
export const REDACTED = "[REDACTED]";
|
|
14
|
+
const RULES = [
|
|
15
|
+
// PEM private-key blocks (RSA/EC/OPENSSH/PGP and the generic PRIVATE KEY).
|
|
16
|
+
{
|
|
17
|
+
kind: "private-key",
|
|
18
|
+
pattern: /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z0-9 ]*PRIVATE KEY-----/g,
|
|
19
|
+
replacement: "-----BEGIN PRIVATE KEY-----" + REDACTED + "-----END PRIVATE KEY-----",
|
|
20
|
+
},
|
|
21
|
+
// Authorization headers, any casing, bearer/basic/token schemes.
|
|
22
|
+
{
|
|
23
|
+
kind: "authorization-header",
|
|
24
|
+
pattern: /(Authorization[ \t]*:[ \t]*)(?:Bearer|Basic|Token)?[ \t]*[A-Za-z0-9._\-+/=]{8,}/gi,
|
|
25
|
+
replacement: "Authorization: " + REDACTED,
|
|
26
|
+
},
|
|
27
|
+
// OpenAI / Anthropic / DeepSeek style keys.
|
|
28
|
+
{
|
|
29
|
+
kind: "api-key",
|
|
30
|
+
pattern: /sk-[A-Za-z0-9_\-]{12,}/g,
|
|
31
|
+
replacement: "sk-" + REDACTED,
|
|
32
|
+
},
|
|
33
|
+
// GitHub tokens.
|
|
34
|
+
{
|
|
35
|
+
kind: "github-token",
|
|
36
|
+
pattern: /(?:gh[pousr]_[A-Za-z0-9]{16,}|github_pat_[A-Za-z0-9_]{20,})/g,
|
|
37
|
+
replacement: REDACTED,
|
|
38
|
+
},
|
|
39
|
+
// AWS access key ids.
|
|
40
|
+
{
|
|
41
|
+
kind: "aws-access-key",
|
|
42
|
+
pattern: /(?:AKIA|ASIA)[0-9A-Z]{16}/g,
|
|
43
|
+
replacement: REDACTED,
|
|
44
|
+
},
|
|
45
|
+
// Slack / Google style tokens.
|
|
46
|
+
{
|
|
47
|
+
kind: "platform-token",
|
|
48
|
+
pattern: /(?:xox[baprs]-[A-Za-z0-9\-]{10,}|AIza[0-9A-Za-z_\-]{35})/g,
|
|
49
|
+
replacement: REDACTED,
|
|
50
|
+
},
|
|
51
|
+
// KEY=value / KEY: value assignments for secret-sounding names.
|
|
52
|
+
{
|
|
53
|
+
kind: "secret-assignment",
|
|
54
|
+
pattern: /([A-Za-z0-9_]*(?:API[_-]?KEY|SECRET|TOKEN|PASSWORD|PASSWD|CREDENTIAL)[A-Za-z0-9_]*)[ \t]*[=:][ \t]*["']?([^\s"',;]{6,})/gi,
|
|
55
|
+
replacement: REDACTED,
|
|
56
|
+
},
|
|
57
|
+
// userinfo embedded in a URL: scheme://user:password@host
|
|
58
|
+
{
|
|
59
|
+
kind: "url-credentials",
|
|
60
|
+
pattern: /([a-z][a-z0-9+\-]*:\/\/)[^\s/@:]+:[^\s/@]+@/gi,
|
|
61
|
+
replacement: "$1" + REDACTED + "@",
|
|
62
|
+
},
|
|
63
|
+
];
|
|
64
|
+
function redactOnce(text, hits) {
|
|
65
|
+
let out = text;
|
|
66
|
+
for (const rule of RULES) {
|
|
67
|
+
rule.pattern.lastIndex = 0;
|
|
68
|
+
let count = 0;
|
|
69
|
+
out = out.replace(rule.pattern, (...args) => {
|
|
70
|
+
count++;
|
|
71
|
+
const match = args[0];
|
|
72
|
+
const groups = args.slice(1, -2);
|
|
73
|
+
if (typeof rule.replacement === "function") {
|
|
74
|
+
return rule.replacement(match, ...groups);
|
|
75
|
+
}
|
|
76
|
+
// Expand simple $1 style backreferences in the replacement string.
|
|
77
|
+
return rule.replacement.replace(/\$(\d+)/g, (_m, d) => groups[Number(d) - 1] ?? "");
|
|
78
|
+
});
|
|
79
|
+
if (count > 0)
|
|
80
|
+
hits.set(rule.kind, (hits.get(rule.kind) ?? 0) + count);
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Masks API-key shapes, bearer tokens, private-key blocks and secret
|
|
86
|
+
* assignments. Never throws; benign text is returned unchanged.
|
|
87
|
+
*/
|
|
88
|
+
export function redactSecrets(text) {
|
|
89
|
+
try {
|
|
90
|
+
if (typeof text !== "string" || text.length === 0) {
|
|
91
|
+
return { text: typeof text === "string" ? text : "", redactions: [] };
|
|
92
|
+
}
|
|
93
|
+
const hits = new Map();
|
|
94
|
+
const once = redactOnce(text, hits);
|
|
95
|
+
const twice = redactOnce(once, hits);
|
|
96
|
+
const redactions = [...hits.entries()].map(([kind, count]) => ({ kind, count }));
|
|
97
|
+
return { text: twice, redactions };
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// Fail safe: emit no text rather than risk a leak.
|
|
101
|
+
return { text: REDACTED, redactions: [{ kind: "error", count: 1 }] };
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { FooterState } from "./footer-state.js";
|
|
2
|
+
import type { FooterRenderer } from "./footer-renderer.js";
|
|
3
|
+
/**
|
|
4
|
+
* ScrollRegionGuard — defensive layer that makes ALL stdout writes safe
|
|
5
|
+
* regardless of their source. When the footer has reserved a scroll region
|
|
6
|
+
* (bottom row), any write to stdout that scrolls the terminal will push
|
|
7
|
+
* the reserved footer row out of view. This guard intercepts writes,
|
|
8
|
+
* temporarily resets the scroll region to full-screen so the write lands
|
|
9
|
+
* correctly, then re-establishes the scroll region and re-renders the
|
|
10
|
+
* footer — keeping it pinned to the bottom row.
|
|
11
|
+
*
|
|
12
|
+
* Design: wraps process.stdout.write at a low level, so that ora, clack,
|
|
13
|
+
* thinking-spinner, and agent output all pass through this guard without
|
|
14
|
+
* requiring changes to those libraries.
|
|
15
|
+
*/
|
|
16
|
+
export interface ScrollRegionGuard {
|
|
17
|
+
/** Write safely within the scrollable area without displacing the footer. */
|
|
18
|
+
write(text: string): void;
|
|
19
|
+
/** Convenience: write(text + '\n'). */
|
|
20
|
+
writeln(text: string): void;
|
|
21
|
+
/** Force re-apply the scroll region (used after resize or after hide/show). */
|
|
22
|
+
reestablish(): void;
|
|
23
|
+
/** Reset scroll region to full screen, clear footer row. */
|
|
24
|
+
teardown(): void;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Create a ScrollRegionGuard that wraps writes to protect the footer's
|
|
28
|
+
* reserved bottom row.
|
|
29
|
+
*
|
|
30
|
+
* @param footerRenderer - The FooterRenderer instance (for re-rendering after writes).
|
|
31
|
+
* @param getState - A function returning the current FooterState (for re-render).
|
|
32
|
+
*/
|
|
33
|
+
export declare function createScrollRegionGuard(footerRenderer: FooterRenderer, getState: () => FooterState): ScrollRegionGuard;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// ── ANSI sequences ──
|
|
2
|
+
const SAVE_CURSOR = "\x1b7";
|
|
3
|
+
const RESTORE_CURSOR = "\x1b8";
|
|
4
|
+
const RESET_SCROLL_REGION = "\x1b[r";
|
|
5
|
+
const CURSOR_TO_BOTTOM = "\x1b[999;1H";
|
|
6
|
+
const CLEAR_LINE = "\x1b[2K";
|
|
7
|
+
/**
|
|
8
|
+
* Create a ScrollRegionGuard that wraps writes to protect the footer's
|
|
9
|
+
* reserved bottom row.
|
|
10
|
+
*
|
|
11
|
+
* @param footerRenderer - The FooterRenderer instance (for re-rendering after writes).
|
|
12
|
+
* @param getState - A function returning the current FooterState (for re-render).
|
|
13
|
+
*/
|
|
14
|
+
export function createScrollRegionGuard(footerRenderer, getState) {
|
|
15
|
+
let active = false;
|
|
16
|
+
function getScrollBottom() {
|
|
17
|
+
const height = process.stdout.rows ?? 24;
|
|
18
|
+
return Math.max(1, height - 1);
|
|
19
|
+
}
|
|
20
|
+
function writeToStdout(text) {
|
|
21
|
+
process.stdout.write(text);
|
|
22
|
+
}
|
|
23
|
+
const guard = {
|
|
24
|
+
write(text) {
|
|
25
|
+
if (!active) {
|
|
26
|
+
writeToStdout(text);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const scrollBottom = getScrollBottom();
|
|
30
|
+
const state = getState();
|
|
31
|
+
// Save cursor position
|
|
32
|
+
writeToStdout(SAVE_CURSOR);
|
|
33
|
+
// Reset scroll region to full screen so the write doesn't displace the footer
|
|
34
|
+
writeToStdout(RESET_SCROLL_REGION);
|
|
35
|
+
// Perform the actual write
|
|
36
|
+
writeToStdout(text);
|
|
37
|
+
// Re-establish the scroll region, keeping the bottom row reserved
|
|
38
|
+
writeToStdout(`\x1b[1;${scrollBottom}r`);
|
|
39
|
+
// Re-render the footer on the bottom row
|
|
40
|
+
footerRenderer.forceRender(state);
|
|
41
|
+
// Restore cursor position (so the caller's cursor tracking isn't broken)
|
|
42
|
+
writeToStdout(RESTORE_CURSOR);
|
|
43
|
+
},
|
|
44
|
+
writeln(text) {
|
|
45
|
+
guard.write(text + "\n");
|
|
46
|
+
},
|
|
47
|
+
reestablish() {
|
|
48
|
+
const scrollBottom = getScrollBottom();
|
|
49
|
+
writeToStdout(RESET_SCROLL_REGION);
|
|
50
|
+
writeToStdout(`\x1b[1;${scrollBottom}r`);
|
|
51
|
+
const state = getState();
|
|
52
|
+
footerRenderer.forceRender(state);
|
|
53
|
+
},
|
|
54
|
+
teardown() {
|
|
55
|
+
active = false;
|
|
56
|
+
writeToStdout(RESET_SCROLL_REGION);
|
|
57
|
+
// Clear the footer row
|
|
58
|
+
writeToStdout(CURSOR_TO_BOTTOM);
|
|
59
|
+
writeToStdout(CLEAR_LINE);
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
return guard;
|
|
63
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const AVAILABLE_SPINNER_STYLES: readonly ["clack", ...string[]];
|
|
2
|
+
/**
|
|
3
|
+
* `--spinner <style>`: "clack" (default, Anthropic's own prompt library's
|
|
4
|
+
* spinner) or any named style from `cli-spinners` (the same package `ora`
|
|
5
|
+
* itself uses) — "dots", "line", "arc", "bounceBar", "star", etc. Falls
|
|
6
|
+
* back to "clack" on an unrecognized name rather than throwing, since a
|
|
7
|
+
* bad `--spinner` value shouldn't stop a task from running.
|
|
8
|
+
*/
|
|
9
|
+
export declare function setSpinnerStyle(style: string | undefined): void;
|
|
10
|
+
export declare function getSpinnerStyle(): string;
|
|
11
|
+
export interface SpinnerHandle {
|
|
12
|
+
stop(message: string): void;
|
|
13
|
+
fail(message: string): void;
|
|
14
|
+
}
|
|
15
|
+
export declare function createSpinner(startMessage: string): SpinnerHandle;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as clack from "@clack/prompts";
|
|
2
|
+
import ora from "ora";
|
|
3
|
+
import cliSpinners from "cli-spinners";
|
|
4
|
+
export const AVAILABLE_SPINNER_STYLES = ["clack", ...Object.keys(cliSpinners)];
|
|
5
|
+
let activeStyle = "clack";
|
|
6
|
+
/**
|
|
7
|
+
* `--spinner <style>`: "clack" (default, Anthropic's own prompt library's
|
|
8
|
+
* spinner) or any named style from `cli-spinners` (the same package `ora`
|
|
9
|
+
* itself uses) — "dots", "line", "arc", "bounceBar", "star", etc. Falls
|
|
10
|
+
* back to "clack" on an unrecognized name rather than throwing, since a
|
|
11
|
+
* bad `--spinner` value shouldn't stop a task from running.
|
|
12
|
+
*/
|
|
13
|
+
export function setSpinnerStyle(style) {
|
|
14
|
+
if (!style)
|
|
15
|
+
return;
|
|
16
|
+
if (style === "clack" || style in cliSpinners) {
|
|
17
|
+
activeStyle = style;
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
console.error(`Unknown --spinner "${style}". Using "clack". Available: clack, ${Object.keys(cliSpinners).slice(0, 12).join(", ")}, ... ` +
|
|
21
|
+
`(${Object.keys(cliSpinners).length} total from cli-spinners)`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function getSpinnerStyle() {
|
|
25
|
+
return activeStyle;
|
|
26
|
+
}
|
|
27
|
+
export function createSpinner(startMessage) {
|
|
28
|
+
if (activeStyle === "clack") {
|
|
29
|
+
const s = clack.spinner();
|
|
30
|
+
s.start(startMessage);
|
|
31
|
+
return {
|
|
32
|
+
stop: (msg) => s.stop(msg),
|
|
33
|
+
fail: (msg) => s.stop(msg, 1),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
// Cast is safe: `activeStyle` is validated against `cliSpinners`'s own keys
|
|
37
|
+
// in `setSpinnerStyle` before it can ever reach here (or is the literal
|
|
38
|
+
// "clack" string, handled in the branch above).
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
40
|
+
const instance = ora({ text: startMessage, spinner: activeStyle }).start();
|
|
41
|
+
return {
|
|
42
|
+
stop: (msg) => {
|
|
43
|
+
instance.succeed(msg);
|
|
44
|
+
},
|
|
45
|
+
fail: (msg) => {
|
|
46
|
+
instance.fail(msg);
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface for per-agent terminal output. The real terminal module
|
|
3
|
+
* (terminal.ts) conforms to this implicitly; SilentTerminal is a no-op
|
|
4
|
+
* implementation for UI-submitted tasks.
|
|
5
|
+
*/
|
|
6
|
+
export interface TerminalOutput {
|
|
7
|
+
startThinking(agentId: string): {
|
|
8
|
+
stop(thought: string): void;
|
|
9
|
+
fail(msg: string): void;
|
|
10
|
+
};
|
|
11
|
+
printAction(agentId: string, tool: string, input: unknown): void;
|
|
12
|
+
printObservation(agentId: string, ok: boolean, text: string): void;
|
|
13
|
+
printTokens(agentId: string, turn: {
|
|
14
|
+
inputTokens: number;
|
|
15
|
+
outputTokens: number;
|
|
16
|
+
}, cumulative: {
|
|
17
|
+
inputTokens: number;
|
|
18
|
+
outputTokens: number;
|
|
19
|
+
}): void;
|
|
20
|
+
printProtocolError(agentId: string, message: string): void;
|
|
21
|
+
printDuplicateWarning(agentId: string, message: string): void;
|
|
22
|
+
printCrash(agentId: string, message: string): void;
|
|
23
|
+
printFinalAnswer(agentId: string, summary: string): void;
|
|
24
|
+
taskIntro(taskId: string, goal: string): void;
|
|
25
|
+
taskOutro(status: string): void;
|
|
26
|
+
orchestratorNote(message: string): void;
|
|
27
|
+
printInterruptSummary(summary: {
|
|
28
|
+
taskId: string;
|
|
29
|
+
doneCount: number;
|
|
30
|
+
totalCount: number;
|
|
31
|
+
command: string;
|
|
32
|
+
file: string;
|
|
33
|
+
}): void;
|
|
34
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* No-op terminal adapter for `quiet` runs (swarm / sub-agent).
|
|
3
|
+
* Suppresses all per-agent console output; events still flow on the bus.
|
|
4
|
+
*/
|
|
5
|
+
export const silentTerminal = {
|
|
6
|
+
startThinking(_agentId) {
|
|
7
|
+
return { stop: () => { }, fail: () => { } };
|
|
8
|
+
},
|
|
9
|
+
printAction(..._args) { },
|
|
10
|
+
printObservation(..._args) { },
|
|
11
|
+
printTokens(..._args) { },
|
|
12
|
+
printProtocolError(..._args) { },
|
|
13
|
+
printDuplicateWarning(..._args) { },
|
|
14
|
+
printCrash(..._args) { },
|
|
15
|
+
printFinalAnswer(..._args) { },
|
|
16
|
+
taskIntro(..._args) { },
|
|
17
|
+
taskOutro(..._args) { },
|
|
18
|
+
orchestratorNote(..._args) { },
|
|
19
|
+
printInterruptSummary(..._args) { },
|
|
20
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One spinner per Sub Agent turn — "thinking" while the LLM call is in
|
|
3
|
+
* flight. This is the piece that makes a long silent wait (previously
|
|
4
|
+
* indistinguishable from a hang, which is part of what made a crash look
|
|
5
|
+
* like nothing was happening) visibly alive. Backend/style is selectable
|
|
6
|
+
* via `--spinner` — see `util/spinner.ts`.
|
|
7
|
+
*/
|
|
8
|
+
export declare function startThinking(agentId: string): {
|
|
9
|
+
stop: (thought: string) => void;
|
|
10
|
+
fail: (message: string) => void;
|
|
11
|
+
};
|
|
12
|
+
export declare function printAction(agentId: string, tool: string, input: unknown): void;
|
|
13
|
+
export declare function printObservation(agentId: string, ok: boolean, text: string): void;
|
|
14
|
+
export declare function printTokens(agentId: string, turn: {
|
|
15
|
+
inputTokens: number;
|
|
16
|
+
outputTokens: number;
|
|
17
|
+
}, cumulative: {
|
|
18
|
+
inputTokens: number;
|
|
19
|
+
outputTokens: number;
|
|
20
|
+
}): void;
|
|
21
|
+
export declare function printProtocolError(agentId: string, message: string): void;
|
|
22
|
+
export declare function printDuplicateWarning(agentId: string, message: string): void;
|
|
23
|
+
export declare function printCrash(agentId: string, message: string): void;
|
|
24
|
+
export declare function printFinalAnswer(agentId: string, summary: string): void;
|
|
25
|
+
export declare function taskIntro(taskId: string, goal: string): void;
|
|
26
|
+
export declare function taskOutro(status: string): void;
|
|
27
|
+
export declare function orchestratorNote(message: string): void;
|
|
28
|
+
/**
|
|
29
|
+
* Printed exactly once per interrupt, after state is flushed to disk.
|
|
30
|
+
* Shows task ID, done/total count, exact --resume command, and file path.
|
|
31
|
+
*/
|
|
32
|
+
export declare function printInterruptSummary(summary: {
|
|
33
|
+
taskId: string;
|
|
34
|
+
doneCount: number;
|
|
35
|
+
totalCount: number;
|
|
36
|
+
resumeCommand: string;
|
|
37
|
+
taskFilePath: string;
|
|
38
|
+
}): void;
|
|
39
|
+
/**
|
|
40
|
+
* Print a color-coded summary of an Instance Swarm run.
|
|
41
|
+
* Uses the same palette as the rest of the terminal module:
|
|
42
|
+
* - green for completed workers
|
|
43
|
+
* - coral for crashed/failed workers
|
|
44
|
+
* - amber for the swarm-level status line
|
|
45
|
+
* - dim for metadata (tokens, output dir)
|
|
46
|
+
*/
|
|
47
|
+
export declare function printSwarmSummary(result: {
|
|
48
|
+
instanceId: string;
|
|
49
|
+
status: "completed" | "failed" | "timeout";
|
|
50
|
+
errors: string[];
|
|
51
|
+
workerCount: number;
|
|
52
|
+
crashedCount: number;
|
|
53
|
+
totalInputTokens: number;
|
|
54
|
+
totalOutputTokens: number;
|
|
55
|
+
outputDir: string;
|
|
56
|
+
}): void;
|