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,40 @@
|
|
|
1
|
+
// xcoder:version 1 | xcoder:task task-7a4850 | xcoder:updated 2026-10-25T16:26:45.781Z | xcoder:subtask code-st-892a22
|
|
2
|
+
// C1 — pure argv pre-extractor for the root-level `--wbc <file>` flag.
|
|
3
|
+
//
|
|
4
|
+
// `xcoder --wbc foo.md` has NO subcommand, so commander would reject it with
|
|
5
|
+
// `commander.unknownCommand` (exit 127). The workspace already solves this class
|
|
6
|
+
// of problem for `--config` by rewriting `process.argv` before
|
|
7
|
+
// `program.parseAsync()` (see `extractConfigArg` in config/user-config.ts); this
|
|
8
|
+
// follows that precedent exactly rather than adding a root positional argument,
|
|
9
|
+
// which would change how every argument-less invocation is parsed.
|
|
10
|
+
//
|
|
11
|
+
// Never touches the filesystem, never throws. Path validation and workspace
|
|
12
|
+
// confinement are C3's job (via C9), so there is exactly one confinement
|
|
13
|
+
// implementation.
|
|
14
|
+
const FLAGS = ["--wbc", "--wbs"];
|
|
15
|
+
export function extractWbcArg(argv) {
|
|
16
|
+
const rest = argv.slice(0, 2);
|
|
17
|
+
let value;
|
|
18
|
+
let error;
|
|
19
|
+
for (let i = 2; i < argv.length; i++) {
|
|
20
|
+
const arg = argv[i];
|
|
21
|
+
const inline = FLAGS.find((f) => arg.startsWith(`${f}=`));
|
|
22
|
+
if (inline) {
|
|
23
|
+
value = arg.slice(inline.length + 1);
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (FLAGS.includes(arg)) {
|
|
27
|
+
const next = argv[i + 1];
|
|
28
|
+
if (next === undefined || next.startsWith("--")) {
|
|
29
|
+
return { argv, error: "--wbc requires a path to a WBS file" };
|
|
30
|
+
}
|
|
31
|
+
value = next;
|
|
32
|
+
i++;
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
rest.push(arg);
|
|
36
|
+
}
|
|
37
|
+
if (error)
|
|
38
|
+
return { argv, error };
|
|
39
|
+
return { argv: rest, value };
|
|
40
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
export interface WbcCliOptions {
|
|
3
|
+
wbc: string;
|
|
4
|
+
/** --dry-run: print the plan, write nothing. */
|
|
5
|
+
dryRun?: boolean;
|
|
6
|
+
/** --force: replace a record that already has progress. */
|
|
7
|
+
force?: boolean;
|
|
8
|
+
/** --no-architect: deterministic, zero-token content. */
|
|
9
|
+
noArchitect?: boolean;
|
|
10
|
+
/** --max-items <n>, clamped to MAX_ITEMS (200). */
|
|
11
|
+
maxItems?: number;
|
|
12
|
+
/** Default 3, clamped 1..8. */
|
|
13
|
+
concurrency?: number;
|
|
14
|
+
/** Passed through to createLlmClient. */
|
|
15
|
+
model?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function setWbcSourcePath(value: string | undefined): void;
|
|
18
|
+
/** The path captured from argv, or undefined when `--wbc` was not given. */
|
|
19
|
+
export declare function capturedWbc(): string | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Root-level flags for the feature. Declared here so the help text and the
|
|
22
|
+
* option list live in one file; the composition root applies them.
|
|
23
|
+
*/
|
|
24
|
+
export declare const WBC_OPTIONS: ReadonlyArray<readonly [string, string]>;
|
|
25
|
+
/** Applies the feature's root flags to `program`. */
|
|
26
|
+
export declare function registerWbcFlag(program: Command): void;
|
|
27
|
+
/**
|
|
28
|
+
* Runs the extraction and translates the result into an exit code and
|
|
29
|
+
* sanitised terminal output. Every attacker-influenced string goes through
|
|
30
|
+
* `sanitizeForTerminal` (C14) on the way to the terminal only.
|
|
31
|
+
*/
|
|
32
|
+
export declare function runWbcCli(opts: WbcCliOptions, workspaceRoot: string): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Root-action branch: runs the extraction when `--wbc` was captured and
|
|
35
|
+
* reports whether it handled the invocation (so the caller can return early).
|
|
36
|
+
*/
|
|
37
|
+
export declare function runCapturedWbc(opts: {
|
|
38
|
+
workspace: string;
|
|
39
|
+
dryRun?: boolean;
|
|
40
|
+
force?: boolean;
|
|
41
|
+
architect?: boolean;
|
|
42
|
+
maxItems?: unknown;
|
|
43
|
+
concurrency?: unknown;
|
|
44
|
+
model?: string;
|
|
45
|
+
}): Promise<boolean>;
|
package/dist/cli/wbc.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// xcoder:version 3 | xcoder:task task-7a4850 | xcoder:updated 2026-10-25T16:40:07.741Z | xcoder:subtask code-st-892a22
|
|
2
|
+
// C2 — the root-command surface for `xcoder --wbc <file>`.
|
|
3
|
+
//
|
|
4
|
+
// `--wbc` is declared on the ROOT command (the same block that owns
|
|
5
|
+
// `--workspace`, `--concurrency` and `--model`), so it shows up in
|
|
6
|
+
// `xcoder --help` and reuses those globals rather than declaring a second set
|
|
7
|
+
// of conflicting flags. `--wbc` itself is lifted out of argv by
|
|
8
|
+
// `extractWbcArg()` before `program.parseAsync()` (C1); the captured path is
|
|
9
|
+
// handed in through `setWbcSourcePath()` and consumed inside the root action.
|
|
10
|
+
import { extractWbsTasks } from "../task-ingest/wbs-extract.js";
|
|
11
|
+
import { sanitizeForTerminal } from "../util/text-sanitize.js";
|
|
12
|
+
import { log } from "../util/logger.js";
|
|
13
|
+
/** Set by the composition root after `extractWbcArg()` captures the value. */
|
|
14
|
+
let capturedWbcPath;
|
|
15
|
+
export function setWbcSourcePath(value) {
|
|
16
|
+
capturedWbcPath = value;
|
|
17
|
+
}
|
|
18
|
+
/** The path captured from argv, or undefined when `--wbc` was not given. */
|
|
19
|
+
export function capturedWbc() {
|
|
20
|
+
return capturedWbcPath;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Root-level flags for the feature. Declared here so the help text and the
|
|
24
|
+
* option list live in one file; the composition root applies them.
|
|
25
|
+
*/
|
|
26
|
+
export const WBC_OPTIONS = [
|
|
27
|
+
["--wbc <path>", "with a WBS file: extract every pending item into its own scannable task run"],
|
|
28
|
+
["--dry-run", "with --wbc: print the extraction plan and write nothing"],
|
|
29
|
+
["--force", "with --wbc: replace task records that already have progress"],
|
|
30
|
+
["--max-items <n>", "with --wbc: extract at most <n> pending items (default 50, max 200)"],
|
|
31
|
+
["--no-architect", "with --wbc: use deterministic task content, spending zero tokens"],
|
|
32
|
+
];
|
|
33
|
+
/** Applies the feature's root flags to `program`. */
|
|
34
|
+
export function registerWbcFlag(program) {
|
|
35
|
+
for (const [flags, description] of WBC_OPTIONS)
|
|
36
|
+
program.option(flags, description);
|
|
37
|
+
}
|
|
38
|
+
/** Commander leaves option values as strings; NaN is passed through so the
|
|
39
|
+
* orchestrator reports `bad-options` rather than silently defaulting. */
|
|
40
|
+
function numeric(value) {
|
|
41
|
+
if (value === undefined)
|
|
42
|
+
return undefined;
|
|
43
|
+
return Number(value);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Runs the extraction and translates the result into an exit code and
|
|
47
|
+
* sanitised terminal output. Every attacker-influenced string goes through
|
|
48
|
+
* `sanitizeForTerminal` (C14) on the way to the terminal only.
|
|
49
|
+
*/
|
|
50
|
+
export async function runWbcCli(opts, workspaceRoot) {
|
|
51
|
+
const result = await extractWbsTasks({
|
|
52
|
+
workspaceRoot,
|
|
53
|
+
from: opts.wbc,
|
|
54
|
+
dryRun: opts.dryRun === true,
|
|
55
|
+
force: opts.force === true,
|
|
56
|
+
detailer: opts.noArchitect === true ? null : undefined,
|
|
57
|
+
maxItems: opts.maxItems,
|
|
58
|
+
concurrency: opts.concurrency,
|
|
59
|
+
});
|
|
60
|
+
if (!result.ok) {
|
|
61
|
+
const where = result.line === undefined ? "" : ` (line ${result.line})`;
|
|
62
|
+
log.fail(`${result.code}${where}: ${sanitizeForTerminal(result.message, 300)}`);
|
|
63
|
+
process.exitCode = 1;
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (result.tasks.length === 0) {
|
|
67
|
+
log.ok(`no pending items — nothing to extract from ${sanitizeForTerminal(result.sourcePath, 100)}`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
for (const task of result.tasks) {
|
|
71
|
+
const verb = task.created ? (result.dryRun ? "would create" : "created") : "unchanged";
|
|
72
|
+
log.raw(`${verb} ${task.taskId} ${sanitizeForTerminal(result.sourcePath, 60)}:${task.line} ` +
|
|
73
|
+
`${sanitizeForTerminal(task.stages.join(">"), 60)} resume: ${task.nextCommand}`);
|
|
74
|
+
}
|
|
75
|
+
const c = result.counts;
|
|
76
|
+
const prefix = result.dryRun ? "dry run — would extract" : "extracted";
|
|
77
|
+
log.dim(`${prefix} ${result.tasks.length} task(s) from ${sanitizeForTerminal(result.sourcePath, 100)} — ` +
|
|
78
|
+
`${c.created} created, ${c.unchanged} unchanged, ${c.checked} checked skipped, ${c.superseded} superseded`);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Root-action branch: runs the extraction when `--wbc` was captured and
|
|
82
|
+
* reports whether it handled the invocation (so the caller can return early).
|
|
83
|
+
*/
|
|
84
|
+
export async function runCapturedWbc(opts) {
|
|
85
|
+
const from = capturedWbc();
|
|
86
|
+
if (from === undefined)
|
|
87
|
+
return false;
|
|
88
|
+
await runWbcCli({
|
|
89
|
+
wbc: from,
|
|
90
|
+
dryRun: opts.dryRun === true,
|
|
91
|
+
force: opts.force === true,
|
|
92
|
+
noArchitect: opts.architect === false,
|
|
93
|
+
maxItems: numeric(opts.maxItems),
|
|
94
|
+
concurrency: numeric(opts.concurrency),
|
|
95
|
+
model: opts.model,
|
|
96
|
+
}, opts.workspace);
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
import { type LicenseApi } from "../license/http-client.js";
|
|
3
|
+
import { type LicenseManager } from "../license/manager.js";
|
|
4
|
+
/** Test seam: the registrar accepts injected dependencies. */
|
|
5
|
+
export interface LicenseCommandDeps {
|
|
6
|
+
manager?: LicenseManager;
|
|
7
|
+
api?: LicenseApi;
|
|
8
|
+
}
|
|
9
|
+
export declare function registerLicenseCommand(program: Command, deps?: LicenseCommandDeps): void;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// xcoder:version 2 | xcoder:task task-1d9460 | xcoder:updated 2026-10-25T17:02:40.271Z | xcoder:subtask code-st-4b0403
|
|
2
|
+
/**
|
|
3
|
+
* `xcoder license …` — activation, status, refresh and seat release.
|
|
4
|
+
*
|
|
5
|
+
* Registration only: every rule lives in src/license/manager.ts so it can be
|
|
6
|
+
* unit-tested without spawning a process. This layer prints and sets an exit
|
|
7
|
+
* code.
|
|
8
|
+
*
|
|
9
|
+
* Output never contains the serial key or the raw receipt — the key comes
|
|
10
|
+
* from argv only (never an env var) and is not even held after the request.
|
|
11
|
+
*/
|
|
12
|
+
import * as readline from "node:readline";
|
|
13
|
+
import { log } from "../util/logger.js";
|
|
14
|
+
import { sanitizeForTerminal } from "../util/text-sanitize.js";
|
|
15
|
+
import { createLicenseStore } from "../license/store.js";
|
|
16
|
+
import { createLicenseApi, LicenseApiError } from "../license/http-client.js";
|
|
17
|
+
import { createLicenseManager } from "../license/manager.js";
|
|
18
|
+
import { LICENSE_API_BASE_URL, TRUST_ANCHOR } from "../license/trust-anchor.js";
|
|
19
|
+
import { DENIAL_DETAIL } from "../license/types.js";
|
|
20
|
+
function buildManager() {
|
|
21
|
+
return createLicenseManager({
|
|
22
|
+
store: createLicenseStore(),
|
|
23
|
+
api: createLicenseApi({ baseUrl: LICENSE_API_BASE_URL, retries: 0 }),
|
|
24
|
+
anchor: TRUST_ANCHOR,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
/** Strip terminal control sequences before printing server-derived text. */
|
|
28
|
+
function safe(value) {
|
|
29
|
+
return sanitizeForTerminal(value, 200);
|
|
30
|
+
}
|
|
31
|
+
function printActivation(rec) {
|
|
32
|
+
log.ok("license activated");
|
|
33
|
+
log.raw(` plan: ${safe(rec.plan)}`);
|
|
34
|
+
log.raw(` expires at: ${safe(rec.expiresAt)}`);
|
|
35
|
+
log.raw(` refresh by: ${safe(rec.refreshBy)}`);
|
|
36
|
+
log.raw(` activation id: ${safe(rec.activationId)}`);
|
|
37
|
+
log.dim(" the serial key was not stored on this machine.");
|
|
38
|
+
}
|
|
39
|
+
function reportError(err) {
|
|
40
|
+
if (err instanceof LicenseApiError) {
|
|
41
|
+
log.fail(`license: ${err.message}`);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
log.fail(`license: ${err?.message ?? String(err)}`);
|
|
45
|
+
}
|
|
46
|
+
async function confirmRelease() {
|
|
47
|
+
// In a non-TTY there is nobody to answer the prompt — refuse instead of
|
|
48
|
+
// blocking forever on a stdin that will never arrive.
|
|
49
|
+
if (!process.stdin.isTTY)
|
|
50
|
+
return false;
|
|
51
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
52
|
+
try {
|
|
53
|
+
const answer = await new Promise((resolve) => {
|
|
54
|
+
rl.question("Release this seat? The machine will need to activate again [y/N] ", resolve);
|
|
55
|
+
});
|
|
56
|
+
return /^y(es)?$/i.test(answer.trim());
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
rl.close();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export function registerLicenseCommand(program, deps = {}) {
|
|
63
|
+
const manager = () => deps.manager ?? buildManager();
|
|
64
|
+
const license = program
|
|
65
|
+
.command("license")
|
|
66
|
+
.description("Manage this machine's xcoder license — activate, status, refresh, release.");
|
|
67
|
+
license
|
|
68
|
+
.command("activate <serialKey>")
|
|
69
|
+
.description("Activate this machine with a serial key.")
|
|
70
|
+
.option("--label <text>", "a human label for this seat, e.g. \"work laptop\"")
|
|
71
|
+
.action(async (serialKey, opts) => {
|
|
72
|
+
try {
|
|
73
|
+
const record = await manager().activate({ serialKey, label: opts.label });
|
|
74
|
+
printActivation(record);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
reportError(err);
|
|
78
|
+
process.exitCode = 1;
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
license
|
|
82
|
+
.command("status")
|
|
83
|
+
.description("Show this machine's activation state.")
|
|
84
|
+
.action(() => {
|
|
85
|
+
const mgr = manager();
|
|
86
|
+
const status = mgr.status();
|
|
87
|
+
if (!status.activation) {
|
|
88
|
+
log.fail("license: not activated — run `xcoder license activate <serial-key>`");
|
|
89
|
+
process.exitCode = 1;
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
printActivation(status.activation);
|
|
93
|
+
if (status.verification.ok) {
|
|
94
|
+
log.ok("status: valid");
|
|
95
|
+
if (status.needsRefresh)
|
|
96
|
+
log.dim("a refresh is due — run `xcoder license refresh`.");
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
const reason = status.verification.reason;
|
|
100
|
+
log.fail(`status: ${reason} — ${DENIAL_DETAIL[reason]}`);
|
|
101
|
+
process.exitCode = 1;
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
license
|
|
105
|
+
.command("refresh")
|
|
106
|
+
.description("Renew the offline window from the license server (needs network).")
|
|
107
|
+
.action(async () => {
|
|
108
|
+
try {
|
|
109
|
+
const record = await manager().refresh();
|
|
110
|
+
printActivation(record);
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
reportError(err);
|
|
114
|
+
process.exitCode = 1;
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
license
|
|
118
|
+
.command("release")
|
|
119
|
+
.description("Free this seat on the license server and remove local state.")
|
|
120
|
+
.option("--yes", "skip the confirmation prompt", false)
|
|
121
|
+
.action(async (opts) => {
|
|
122
|
+
if (!opts.yes) {
|
|
123
|
+
const confirmed = await confirmRelease();
|
|
124
|
+
if (!confirmed) {
|
|
125
|
+
log.fail("license: release cancelled — pass --yes to confirm non-interactively.");
|
|
126
|
+
process.exitCode = 1;
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
await manager().release();
|
|
132
|
+
log.ok("license released — this machine is no longer activated.");
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
reportError(err);
|
|
136
|
+
log.dim("local state was kept so you can retry.");
|
|
137
|
+
process.exitCode = 1;
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Xcoder SDLC Release Command — `xcoder release` subcommand.
|
|
3
|
+
*
|
|
4
|
+
* Exposes the existing build-dist pipeline as a CLI subcommand.
|
|
5
|
+
* Handles version incrementing, platform selection, and output
|
|
6
|
+
* directory management using .xcoder/release/ as the default output path.
|
|
7
|
+
*/
|
|
8
|
+
export interface ReleaseOptions {
|
|
9
|
+
/** Target platform: win, macos, linux, or "current" for auto-detect. */
|
|
10
|
+
platform: "win" | "macos" | "linux" | "current";
|
|
11
|
+
/** Target architecture: x64, arm64. Defaults to current arch. */
|
|
12
|
+
arch: "x64" | "arm64";
|
|
13
|
+
/** Output directory for the installer. Defaults to <workspace>/.xcoder/release/. */
|
|
14
|
+
output: string;
|
|
15
|
+
/** Increment the version in package.json before building. */
|
|
16
|
+
increment?: "major" | "minor" | "patch";
|
|
17
|
+
/** Dry-run: validate inputs and print plan, don't build. */
|
|
18
|
+
dryRun: boolean;
|
|
19
|
+
/** Workspace root. */
|
|
20
|
+
workspaceRoot: string;
|
|
21
|
+
}
|
|
22
|
+
export interface ReleaseResult {
|
|
23
|
+
ok: boolean;
|
|
24
|
+
/** Path to the produced installer file. */
|
|
25
|
+
installerPath?: string;
|
|
26
|
+
/** Path to the SEA binary. */
|
|
27
|
+
binaryPath?: string;
|
|
28
|
+
/** Version string used for the build. */
|
|
29
|
+
version: string;
|
|
30
|
+
/** Platform built for. */
|
|
31
|
+
platform: string;
|
|
32
|
+
/** Duration of the build in ms. */
|
|
33
|
+
durationMs: number;
|
|
34
|
+
/** Error message if ok === false. */
|
|
35
|
+
error?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Run the full release pipeline:
|
|
39
|
+
* 1. If --increment is set, bump package.json version atomically.
|
|
40
|
+
* 2. Run the build-dist pipeline (tsc → bundle → SEA → installer).
|
|
41
|
+
* 3. Write the installer to the output directory (default: .xcoder/release/).
|
|
42
|
+
* 4. Return structured result; exit non-zero on failure.
|
|
43
|
+
*/
|
|
44
|
+
export declare function runRelease(opts: ReleaseOptions): Promise<ReleaseResult>;
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
// xcoder:version 6 | xcoder:task swarm-swarm-is-b22287 | xcoder:updated 2026-08-04T12:17:59.289Z | xcoder:subtask swarm-swarm-is-b22287/2
|
|
2
|
+
/**
|
|
3
|
+
* Xcoder SDLC Release Command — `xcoder release` subcommand.
|
|
4
|
+
*
|
|
5
|
+
* Exposes the existing build-dist pipeline as a CLI subcommand.
|
|
6
|
+
* Handles version incrementing, platform selection, and output
|
|
7
|
+
* directory management using .xcoder/release/ as the default output path.
|
|
8
|
+
*/
|
|
9
|
+
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
10
|
+
import { execSync } from "node:child_process";
|
|
11
|
+
import path from "node:path";
|
|
12
|
+
import { log } from "../util/logger.js";
|
|
13
|
+
import { createXcoderPaths } from "../util/xcoder-paths.js";
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Helpers
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
function detectPlatform() {
|
|
18
|
+
switch (process.platform) {
|
|
19
|
+
case "win32": return "win";
|
|
20
|
+
case "darwin": return "macos";
|
|
21
|
+
case "linux": return "linux";
|
|
22
|
+
default: throw new Error(`Unsupported platform: ${process.platform}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function detectArch() {
|
|
26
|
+
return process.arch === "arm64" ? "arm64" : "x64";
|
|
27
|
+
}
|
|
28
|
+
function resolvePlatform(platform) {
|
|
29
|
+
return platform === "current" ? detectPlatform() : platform;
|
|
30
|
+
}
|
|
31
|
+
async function readPackageJson(workspaceRoot) {
|
|
32
|
+
const pkgPath = path.resolve(workspaceRoot, "package.json");
|
|
33
|
+
const data = await readFile(pkgPath, "utf-8");
|
|
34
|
+
return JSON.parse(data);
|
|
35
|
+
}
|
|
36
|
+
async function writePackageJson(workspaceRoot, data) {
|
|
37
|
+
const pkgPath = path.resolve(workspaceRoot, "package.json");
|
|
38
|
+
await writeFile(pkgPath, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
39
|
+
}
|
|
40
|
+
function incrementVersion(version, level) {
|
|
41
|
+
const parts = version.split(".").map(Number);
|
|
42
|
+
if (parts.length !== 3)
|
|
43
|
+
throw new Error(`Invalid semver version: ${version}`);
|
|
44
|
+
switch (level) {
|
|
45
|
+
case "major":
|
|
46
|
+
parts[0]++;
|
|
47
|
+
parts[1] = 0;
|
|
48
|
+
parts[2] = 0;
|
|
49
|
+
break;
|
|
50
|
+
case "minor":
|
|
51
|
+
parts[1]++;
|
|
52
|
+
parts[2] = 0;
|
|
53
|
+
break;
|
|
54
|
+
case "patch":
|
|
55
|
+
parts[2]++;
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
return parts.join(".");
|
|
59
|
+
}
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
// Main
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
/**
|
|
64
|
+
* Run the full release pipeline:
|
|
65
|
+
* 1. If --increment is set, bump package.json version atomically.
|
|
66
|
+
* 2. Run the build-dist pipeline (tsc → bundle → SEA → installer).
|
|
67
|
+
* 3. Write the installer to the output directory (default: .xcoder/release/).
|
|
68
|
+
* 4. Return structured result; exit non-zero on failure.
|
|
69
|
+
*/
|
|
70
|
+
export async function runRelease(opts) {
|
|
71
|
+
const start = Date.now();
|
|
72
|
+
const platform = resolvePlatform(opts.platform);
|
|
73
|
+
const arch = opts.arch || detectArch();
|
|
74
|
+
let pkg = await readPackageJson(opts.workspaceRoot);
|
|
75
|
+
const originalVersion = String(pkg.version ?? "0.0.0");
|
|
76
|
+
let version = originalVersion;
|
|
77
|
+
if (opts.increment) {
|
|
78
|
+
version = incrementVersion(originalVersion, opts.increment);
|
|
79
|
+
if (opts.dryRun) {
|
|
80
|
+
log.ok(`Would bump version: ${originalVersion} → ${version}`);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
pkg.version = version;
|
|
84
|
+
await writePackageJson(opts.workspaceRoot, pkg);
|
|
85
|
+
log.ok(`Bumped version: ${originalVersion} → ${version}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const xcoderPaths = createXcoderPaths(opts.workspaceRoot);
|
|
89
|
+
const outputDir = opts.output || xcoderPaths.releaseDir();
|
|
90
|
+
if (opts.dryRun) {
|
|
91
|
+
log.ok(`Dry-run plan:`);
|
|
92
|
+
log.ok(` Platform: ${platform}`);
|
|
93
|
+
log.ok(` Arch: ${arch}`);
|
|
94
|
+
log.ok(` Version: ${version}${opts.increment ? ` (was ${originalVersion})` : ""}`);
|
|
95
|
+
log.ok(` Output: ${outputDir}`);
|
|
96
|
+
log.ok(` Workspace: ${opts.workspaceRoot}`);
|
|
97
|
+
log.ok(`Dry-run complete — no build performed.`);
|
|
98
|
+
return {
|
|
99
|
+
ok: true,
|
|
100
|
+
version,
|
|
101
|
+
platform,
|
|
102
|
+
durationMs: Date.now() - start,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
await mkdir(outputDir, { recursive: true });
|
|
106
|
+
try {
|
|
107
|
+
const rootDir = opts.workspaceRoot;
|
|
108
|
+
log.ok("[1/4] Building TypeScript...");
|
|
109
|
+
execSync("npm run build", { cwd: rootDir, stdio: "inherit" });
|
|
110
|
+
log.ok("[2/4] Bundling with esbuild...");
|
|
111
|
+
// @ts-expect-error - scripts/*.mjs have no declaration files
|
|
112
|
+
const { bundleEntry } = await import("../../scripts/bundler.mjs");
|
|
113
|
+
const bundleOut = path.join(rootDir, "dist", "xcoder-bundled.mjs");
|
|
114
|
+
await bundleEntry(path.join(rootDir, "dist", "sdlc-cli.js"), bundleOut, { minify: false });
|
|
115
|
+
log.ok("[3/4] Compiling SEA binary...");
|
|
116
|
+
// @ts-expect-error - scripts/*.mjs have no declaration files
|
|
117
|
+
const { compileSEA } = await import("../../scripts/sea-compiler.mjs");
|
|
118
|
+
const seaBinaryPath = await compileSEA(bundleOut, "xcoder", path.join(rootDir, "dist"));
|
|
119
|
+
log.ok("[4/4] Building platform installer...");
|
|
120
|
+
let installerPath;
|
|
121
|
+
switch (platform) {
|
|
122
|
+
case "win": {
|
|
123
|
+
// @ts-expect-error - scripts/*.mjs have no declaration files
|
|
124
|
+
const { buildWindowsInstaller } = await import("../../scripts/installer-windows.mjs");
|
|
125
|
+
const result = await buildWindowsInstaller(seaBinaryPath, outputDir, version, arch);
|
|
126
|
+
installerPath = result.installerPath;
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
case "macos": {
|
|
130
|
+
// @ts-expect-error - scripts/*.mjs have no declaration files
|
|
131
|
+
const { buildMacOSInstaller } = await import("../../scripts/installer-macos.mjs");
|
|
132
|
+
const result = await buildMacOSInstaller(seaBinaryPath, outputDir, version, arch);
|
|
133
|
+
installerPath = result.installerPath;
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
case "linux": {
|
|
137
|
+
// @ts-expect-error - scripts/*.mjs have no declaration files
|
|
138
|
+
const { buildLinuxInstaller } = await import("../../scripts/installer-linux.mjs");
|
|
139
|
+
const result = await buildLinuxInstaller(seaBinaryPath, outputDir, version, arch);
|
|
140
|
+
installerPath = result.installerPath;
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const durationMs = Date.now() - start;
|
|
145
|
+
log.ok(`\nRelease complete! v${version} for ${platform}-${arch}`);
|
|
146
|
+
if (installerPath)
|
|
147
|
+
log.ok(`Installer: ${installerPath}`);
|
|
148
|
+
log.ok(`Duration: ${durationMs}ms`);
|
|
149
|
+
return {
|
|
150
|
+
ok: true,
|
|
151
|
+
installerPath,
|
|
152
|
+
binaryPath: seaBinaryPath,
|
|
153
|
+
version,
|
|
154
|
+
platform,
|
|
155
|
+
durationMs,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
const durationMs = Date.now() - start;
|
|
160
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
161
|
+
log.fail(`Release failed: ${message}`);
|
|
162
|
+
if (opts.increment && version !== originalVersion) {
|
|
163
|
+
try {
|
|
164
|
+
pkg.version = originalVersion;
|
|
165
|
+
await writePackageJson(opts.workspaceRoot, pkg);
|
|
166
|
+
log.ok(`Restored version to ${originalVersion}`);
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
// Best effort
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
ok: false,
|
|
174
|
+
version,
|
|
175
|
+
platform,
|
|
176
|
+
durationMs,
|
|
177
|
+
error: message,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
export interface TestSuiteDescriptor {
|
|
3
|
+
name: string;
|
|
4
|
+
configPath: string;
|
|
5
|
+
npmScript: string;
|
|
6
|
+
label: string;
|
|
7
|
+
/**
|
|
8
|
+
* If set, vitest positional arguments to scope tests to specific files.
|
|
9
|
+
* Passed as direct file paths (not globs) to avoid shell expansion issues on Windows.
|
|
10
|
+
*/
|
|
11
|
+
testFiles?: string[];
|
|
12
|
+
}
|
|
13
|
+
export interface SuiteResult {
|
|
14
|
+
suiteName: string;
|
|
15
|
+
passed: boolean;
|
|
16
|
+
durationMs: number;
|
|
17
|
+
testCount: number | null;
|
|
18
|
+
passedCount: number | null;
|
|
19
|
+
failedCount: number | null;
|
|
20
|
+
exitCode: number | null;
|
|
21
|
+
error: string | null;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Scan src/ directories for *.test.ts files, group by immediate parent
|
|
25
|
+
* directory, and produce one suite descriptor per folder that has tests.
|
|
26
|
+
* Skips folders with no tests. Uses the share vitest config, scoped
|
|
27
|
+
* via --include.
|
|
28
|
+
*/
|
|
29
|
+
export declare function generateFolderSuites(rootDir: string): TestSuiteDescriptor[];
|
|
30
|
+
/**
|
|
31
|
+
* Spawn vitest as a child process for a single suite, capture
|
|
32
|
+
* stdout/stderr, enforce a per-suite timeout, and return a
|
|
33
|
+
* structured SuiteResult.
|
|
34
|
+
*
|
|
35
|
+
* Uses vitest's built-in JSON reporter so we can parse test counts
|
|
36
|
+
* for the summary. Falls back to exit-code-only pass/fail if JSON
|
|
37
|
+
* parsing fails (vitest crash, old version, etc.).
|
|
38
|
+
*
|
|
39
|
+
* If suite has testFiles, they are passed as positional arguments.
|
|
40
|
+
*/
|
|
41
|
+
export declare function runSuite(suite: TestSuiteDescriptor, timeoutMs: number, capture: boolean): Promise<SuiteResult>;
|
|
42
|
+
/**
|
|
43
|
+
* Accept an array of SuiteResults and print a color-coded,
|
|
44
|
+
* human-readable summary to stdout.
|
|
45
|
+
*/
|
|
46
|
+
export declare function printSummary(results: SuiteResult[], totalDurationMs: number): void;
|
|
47
|
+
/**
|
|
48
|
+
* Register the `xcoder test` subcommand.
|
|
49
|
+
*/
|
|
50
|
+
export declare function registerTestCommand(parent: Command): void;
|