xcoder-dna 0.0.0-stage → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +66 -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 +39 -4
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { Role } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Curated map from Xcoder SDLC's internal Role (see src/types.ts) to the external
|
|
4
|
+
* SKILL.md names (under the resolved skills directory, e.g. `skills/<name>/
|
|
5
|
+
* SKILL.md` at the project root) that are safe and relevant to inject for
|
|
6
|
+
* that role.
|
|
7
|
+
*
|
|
8
|
+
* WHY THIS EXISTS: previously, `sub-agent.ts` called `getExternalSkills()`
|
|
9
|
+
* directly and appended *every* external skill's one-line description to
|
|
10
|
+
* *every* non-conversation role's prompt, regardless of relevance. That had
|
|
11
|
+
* two problems:
|
|
12
|
+
* 1. Noise — a `tester` subtask's prompt would also see one-liners for
|
|
13
|
+
* AWS, Kubernetes, DFIR, business-analyst UI design, etc.
|
|
14
|
+
* 2. Real contradictions — some external skills share a name with a Role
|
|
15
|
+
* but describe a different job. The clearest case: the external
|
|
16
|
+
* "business-analyst" skill (traditional BRD/FRD/ERP requirements work)
|
|
17
|
+
* directly contradicted Xcoder SDLC's hardcoded `business-analyst` Role
|
|
18
|
+
* directive, which is deliberately scoped to UI/UX page design only
|
|
19
|
+
* (see ROLE_DIRECTIVES["business-analyst"] in ./directives.ts, and the
|
|
20
|
+
* separate BA_REQUIREMENTS_DIRECTIVE carved out specifically to keep
|
|
21
|
+
* general requirements work OUT of that Role). That skill has since
|
|
22
|
+
* been renamed to "enterprise-systems-analyst" and is intentionally
|
|
23
|
+
* NOT listed under "business-analyst" below.
|
|
24
|
+
*
|
|
25
|
+
* Keep this list conservative: only add a skill here once you've confirmed
|
|
26
|
+
* its guidance doesn't contradict the hardcoded ROLE_DIRECTIVES entry for
|
|
27
|
+
* that role. When in doubt, leave it out — an omitted skill just means one
|
|
28
|
+
* fewer optional hint, but a contradictory one actively confuses the model
|
|
29
|
+
* about what it's supposed to do.
|
|
30
|
+
*/
|
|
31
|
+
export declare const ROLE_SKILL_ALLOWLIST: Partial<Record<Role, string[]>>;
|
|
32
|
+
export interface RoutedSkillsOptions {
|
|
33
|
+
skillDir?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Cap on how many external skill lines get injected per subtask, so a
|
|
36
|
+
* role's allowlist growing over time can't unboundedly bloat the prompt.
|
|
37
|
+
* Default 6.
|
|
38
|
+
*/
|
|
39
|
+
maxSkills?: number;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Role-aware replacement for calling getExternalSkills() directly. Returns
|
|
43
|
+
* only the external skills allowlisted for this specific role, formatted
|
|
44
|
+
* exactly the way getExternalSkills() already formats them ("name:
|
|
45
|
+
* description"), so existing callers that treat the result as a flat
|
|
46
|
+
* string[] keep working unchanged.
|
|
47
|
+
*
|
|
48
|
+
* Returns [] when the XCODER_EXTERNAL_SKILLS flag is off, or when the role
|
|
49
|
+
* has no allowlist entry (e.g. "conversation").
|
|
50
|
+
*/
|
|
51
|
+
export declare function getRoutedExternalSkills(role: Role, opts?: RoutedSkillsOptions): string[];
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { isExternalSkillsEnabled, getExternalSkills } from "./externalSkillLoader.js";
|
|
2
|
+
/**
|
|
3
|
+
* Curated map from Xcoder SDLC's internal Role (see src/types.ts) to the external
|
|
4
|
+
* SKILL.md names (under the resolved skills directory, e.g. `skills/<name>/
|
|
5
|
+
* SKILL.md` at the project root) that are safe and relevant to inject for
|
|
6
|
+
* that role.
|
|
7
|
+
*
|
|
8
|
+
* WHY THIS EXISTS: previously, `sub-agent.ts` called `getExternalSkills()`
|
|
9
|
+
* directly and appended *every* external skill's one-line description to
|
|
10
|
+
* *every* non-conversation role's prompt, regardless of relevance. That had
|
|
11
|
+
* two problems:
|
|
12
|
+
* 1. Noise — a `tester` subtask's prompt would also see one-liners for
|
|
13
|
+
* AWS, Kubernetes, DFIR, business-analyst UI design, etc.
|
|
14
|
+
* 2. Real contradictions — some external skills share a name with a Role
|
|
15
|
+
* but describe a different job. The clearest case: the external
|
|
16
|
+
* "business-analyst" skill (traditional BRD/FRD/ERP requirements work)
|
|
17
|
+
* directly contradicted Xcoder SDLC's hardcoded `business-analyst` Role
|
|
18
|
+
* directive, which is deliberately scoped to UI/UX page design only
|
|
19
|
+
* (see ROLE_DIRECTIVES["business-analyst"] in ./directives.ts, and the
|
|
20
|
+
* separate BA_REQUIREMENTS_DIRECTIVE carved out specifically to keep
|
|
21
|
+
* general requirements work OUT of that Role). That skill has since
|
|
22
|
+
* been renamed to "enterprise-systems-analyst" and is intentionally
|
|
23
|
+
* NOT listed under "business-analyst" below.
|
|
24
|
+
*
|
|
25
|
+
* Keep this list conservative: only add a skill here once you've confirmed
|
|
26
|
+
* its guidance doesn't contradict the hardcoded ROLE_DIRECTIVES entry for
|
|
27
|
+
* that role. When in doubt, leave it out — an omitted skill just means one
|
|
28
|
+
* fewer optional hint, but a contradictory one actively confuses the model
|
|
29
|
+
* about what it's supposed to do.
|
|
30
|
+
*/
|
|
31
|
+
export const ROLE_SKILL_ALLOWLIST = {
|
|
32
|
+
"requirements-analyst": ["analyst", "enterprise-systems-analyst", "task-planning"],
|
|
33
|
+
architect: ["architect", "software-architect", "design-patterns", "solid-principles", "project-scaffolding"],
|
|
34
|
+
// Deliberately does NOT include "refactorer"-flavored language — see the
|
|
35
|
+
// updated skills/programmer/SKILL.md description, which was itself
|
|
36
|
+
// narrowed to new/design-driven implementation for the same reason.
|
|
37
|
+
programmer: ["programmer", "software-engineer", "design-patterns", "solid-principles", "git-vcs"],
|
|
38
|
+
// Deliberately excludes "programmer" — that skill's original scope
|
|
39
|
+
// ("fix bug", "refactor") blurred the boundary Xcoder SDLC's directive draws
|
|
40
|
+
// between programmer (design-driven implementation) and refactorer
|
|
41
|
+
// (minimal-diff, no redesign). Give refactorer its own, narrower set.
|
|
42
|
+
refactorer: ["software-engineer", "design-patterns", "solid-principles", "rca"],
|
|
43
|
+
tester: ["tester", "qa-engineer", "rca", "performance-tester"],
|
|
44
|
+
"ui-api-tester": ["playwright-ui-tester", "qa-engineer", "ui-ux-design"],
|
|
45
|
+
"technical-writer": ["workspace-context"],
|
|
46
|
+
devops: [
|
|
47
|
+
"devops", "docker", "docker-expert", "kubernetes", "kubernetes-expert",
|
|
48
|
+
"aws", "azure", "openshift", "redhat", "rosa", "ubuntu", "git-vcs",
|
|
49
|
+
],
|
|
50
|
+
// "conversation" intentionally omitted: sub-agent.ts already skips
|
|
51
|
+
// external-skill injection entirely for this role, so listing anything
|
|
52
|
+
// here would never be used — kept out to avoid implying otherwise.
|
|
53
|
+
// Intentionally does NOT include "enterprise-systems-analyst" — see the
|
|
54
|
+
// module doc comment above. This Role is UI/UX-scoped in Xcoder SDLC.
|
|
55
|
+
"business-analyst": ["ui-ux-design"],
|
|
56
|
+
"defect-manager": ["rca", "task-planning"],
|
|
57
|
+
// Deliberately excludes "scrum-master-agent" (a behavioral playbook for
|
|
58
|
+
// human-team sprint coaching — stand-ups, burndown, retro insights) —
|
|
59
|
+
// this Role is an internal JSON pass/fail quality gate, a different job,
|
|
60
|
+
// and it needs a strict, uncluttered prompt to reliably emit clean JSON.
|
|
61
|
+
"scrum-master": ["scrum-framework"],
|
|
62
|
+
"system-architect": ["software-architect", "design-patterns", "solid-principles"],
|
|
63
|
+
"security-lead": ["secops", "advanced-dfir", "ethical-hacking-methodology", "advanced-pentest-lab", "pentester"],
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Role-aware replacement for calling getExternalSkills() directly. Returns
|
|
67
|
+
* only the external skills allowlisted for this specific role, formatted
|
|
68
|
+
* exactly the way getExternalSkills() already formats them ("name:
|
|
69
|
+
* description"), so existing callers that treat the result as a flat
|
|
70
|
+
* string[] keep working unchanged.
|
|
71
|
+
*
|
|
72
|
+
* Returns [] when the XCODER_EXTERNAL_SKILLS flag is off, or when the role
|
|
73
|
+
* has no allowlist entry (e.g. "conversation").
|
|
74
|
+
*/
|
|
75
|
+
export function getRoutedExternalSkills(role, opts = {}) {
|
|
76
|
+
if (!isExternalSkillsEnabled())
|
|
77
|
+
return [];
|
|
78
|
+
const allowedNames = ROLE_SKILL_ALLOWLIST[role];
|
|
79
|
+
if (!allowedNames || allowedNames.length === 0)
|
|
80
|
+
return [];
|
|
81
|
+
const allowedSet = new Set(allowedNames);
|
|
82
|
+
const all = getExternalSkills({ skillDir: opts.skillDir }); // ["name: description", ...]
|
|
83
|
+
const filtered = all.filter((line) => {
|
|
84
|
+
const sep = line.indexOf(":");
|
|
85
|
+
const name = sep === -1 ? line : line.slice(0, sep);
|
|
86
|
+
return allowedSet.has(name);
|
|
87
|
+
});
|
|
88
|
+
const max = opts.maxSkills ?? 6;
|
|
89
|
+
return filtered.slice(0, max);
|
|
90
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single source of truth for skill discovery.
|
|
3
|
+
*
|
|
4
|
+
* Before this module there were two independent `path.join(..., "skills")`
|
|
5
|
+
* sites (loadConfig and SkillRegistry) and neither one checked whether the
|
|
6
|
+
* directory it found actually contained a usable pack. An empty
|
|
7
|
+
* `~/.xcoder/skills` therefore *shadowed* the bundled packs and the CLI came
|
|
8
|
+
* up with zero skills — the bug this module exists to fix.
|
|
9
|
+
*
|
|
10
|
+
* Resolution order (first USABLE candidate wins, where usable means at least
|
|
11
|
+
* one pack parses as a valid SkillHeader — never a bare `existsSync`):
|
|
12
|
+
*
|
|
13
|
+
* 1. opts.skillDir (explicit; honoured even if empty)
|
|
14
|
+
* 2. $XCODER_HOME/skills
|
|
15
|
+
* 3. ~/.xcoder/skills (the fixed home location)
|
|
16
|
+
* 4. getAppDir()/skills (installer layout)
|
|
17
|
+
* 5. <exeDir>/../share/xcoder/skills (.deb / macOS / install.sh)
|
|
18
|
+
* 6. getAppDir()/../skills (npm dist/)
|
|
19
|
+
* 7. getAppDir()/../../skills (source checkout)
|
|
20
|
+
* 8. cwd/skills
|
|
21
|
+
* 9. fallback: getAppDir()
|
|
22
|
+
*/
|
|
23
|
+
/** Where a resolved skills root came from, for the debug line and for tests. */
|
|
24
|
+
export type SkillsRootSource = "explicit" | "xcoders-home" | "user-home" | "installer" | "cwd" | "fallback";
|
|
25
|
+
export interface SkillsRoot {
|
|
26
|
+
/** Directory D such that D/skills is the skills directory. */
|
|
27
|
+
readonly root: string;
|
|
28
|
+
/** The skills directory itself (D/skills). */
|
|
29
|
+
readonly skillsDir: string;
|
|
30
|
+
readonly source: SkillsRootSource;
|
|
31
|
+
/** Number of packs that parsed as a valid skill header. */
|
|
32
|
+
readonly usableCount: number;
|
|
33
|
+
}
|
|
34
|
+
export interface ResolveSkillsRootOptions {
|
|
35
|
+
skillDir?: string;
|
|
36
|
+
homeDir?: string;
|
|
37
|
+
appDir?: string;
|
|
38
|
+
exeDir?: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Directory the app runs from. Under `bun build --compile` modules live in a
|
|
42
|
+
* virtual filesystem (`/$bunfs/…`, `B:\~BUN\…`), so use the folder that holds
|
|
43
|
+
* the executable instead — that is where the installer puts `skills/`.
|
|
44
|
+
*/
|
|
45
|
+
export declare function getAppDir(): string;
|
|
46
|
+
/** The fixed, user-owned location new packs are seeded into: ~/.xcoder/skills. */
|
|
47
|
+
export declare function getUserHomeSkillsDir(homeDir?: string): string;
|
|
48
|
+
/**
|
|
49
|
+
* Count the packs in `skillsDir` that actually parse.
|
|
50
|
+
*
|
|
51
|
+
* This is the usability test that replaces `existsSync`: a directory that
|
|
52
|
+
* exists but holds no valid pack must not shadow a directory that does.
|
|
53
|
+
*/
|
|
54
|
+
export declare function probeSkillsDir(skillsDir: string): {
|
|
55
|
+
count: number;
|
|
56
|
+
names: string[];
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Resolve the skills root, probing each candidate in precedence order and
|
|
60
|
+
* returning the first one that holds at least one usable pack.
|
|
61
|
+
*/
|
|
62
|
+
export declare function resolveSkillsRoot(opts?: ResolveSkillsRootOptions): SkillsRoot;
|
|
63
|
+
/** Test hook: drop memoised resolutions and allow the debug line again. */
|
|
64
|
+
export declare function resetSkillsRootCache(): void;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
// xcoder:version 1 | xcoder:task task-f9cf18 | xcoder:updated 2026-11-02T16:14:29.238Z | xcoder:subtask code-st-077ea2
|
|
2
|
+
/**
|
|
3
|
+
* Single source of truth for skill discovery.
|
|
4
|
+
*
|
|
5
|
+
* Before this module there were two independent `path.join(..., "skills")`
|
|
6
|
+
* sites (loadConfig and SkillRegistry) and neither one checked whether the
|
|
7
|
+
* directory it found actually contained a usable pack. An empty
|
|
8
|
+
* `~/.xcoder/skills` therefore *shadowed* the bundled packs and the CLI came
|
|
9
|
+
* up with zero skills — the bug this module exists to fix.
|
|
10
|
+
*
|
|
11
|
+
* Resolution order (first USABLE candidate wins, where usable means at least
|
|
12
|
+
* one pack parses as a valid SkillHeader — never a bare `existsSync`):
|
|
13
|
+
*
|
|
14
|
+
* 1. opts.skillDir (explicit; honoured even if empty)
|
|
15
|
+
* 2. $XCODER_HOME/skills
|
|
16
|
+
* 3. ~/.xcoder/skills (the fixed home location)
|
|
17
|
+
* 4. getAppDir()/skills (installer layout)
|
|
18
|
+
* 5. <exeDir>/../share/xcoder/skills (.deb / macOS / install.sh)
|
|
19
|
+
* 6. getAppDir()/../skills (npm dist/)
|
|
20
|
+
* 7. getAppDir()/../../skills (source checkout)
|
|
21
|
+
* 8. cwd/skills
|
|
22
|
+
* 9. fallback: getAppDir()
|
|
23
|
+
*/
|
|
24
|
+
import fs from "node:fs";
|
|
25
|
+
import os from "node:os";
|
|
26
|
+
import path from "node:path";
|
|
27
|
+
import { log } from "../util/logger.js";
|
|
28
|
+
import { MAX_PACK_DIRS, resolveSkillDir } from "./skill-path-guard.js";
|
|
29
|
+
import { parseSkillHeaderFile } from "./skill-header.js";
|
|
30
|
+
/**
|
|
31
|
+
* Directory the app runs from. Under `bun build --compile` modules live in a
|
|
32
|
+
* virtual filesystem (`/$bunfs/…`, `B:\~BUN\…`), so use the folder that holds
|
|
33
|
+
* the executable instead — that is where the installer puts `skills/`.
|
|
34
|
+
*/
|
|
35
|
+
export function getAppDir() {
|
|
36
|
+
const dir = typeof import.meta !== "undefined" && import.meta.dirname
|
|
37
|
+
? import.meta.dirname
|
|
38
|
+
: __dirname;
|
|
39
|
+
return dir.includes("$bunfs") || dir.includes("~BUN") ? path.dirname(process.execPath) : dir;
|
|
40
|
+
}
|
|
41
|
+
/** The fixed, user-owned location new packs are seeded into: ~/.xcoder/skills. */
|
|
42
|
+
export function getUserHomeSkillsDir(homeDir) {
|
|
43
|
+
const home = homeDir ?? os.homedir();
|
|
44
|
+
return path.join(home, ".xcoder", "skills");
|
|
45
|
+
}
|
|
46
|
+
/** Emit the one-per-process debug line naming the resolved root. */
|
|
47
|
+
let debugLogged = false;
|
|
48
|
+
function logResolvedRoot(result) {
|
|
49
|
+
if (debugLogged || !process.env["XCODER_DEBUG_CONFIG_PATH"])
|
|
50
|
+
return;
|
|
51
|
+
debugLogged = true;
|
|
52
|
+
log.dim(`skillsRoot: ${result.root} (source=${result.source}, packs=${result.usableCount})`);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Count the packs in `skillsDir` that actually parse.
|
|
56
|
+
*
|
|
57
|
+
* This is the usability test that replaces `existsSync`: a directory that
|
|
58
|
+
* exists but holds no valid pack must not shadow a directory that does.
|
|
59
|
+
*/
|
|
60
|
+
export function probeSkillsDir(skillsDir) {
|
|
61
|
+
const names = [];
|
|
62
|
+
let entries;
|
|
63
|
+
try {
|
|
64
|
+
entries = fs.readdirSync(skillsDir, { withFileTypes: true });
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return { count: 0, names };
|
|
68
|
+
}
|
|
69
|
+
let visited = 0;
|
|
70
|
+
for (const entry of entries) {
|
|
71
|
+
if (visited >= MAX_PACK_DIRS)
|
|
72
|
+
break;
|
|
73
|
+
if (!entry.isDirectory())
|
|
74
|
+
continue;
|
|
75
|
+
visited++;
|
|
76
|
+
const packDir = resolveSkillDir(skillsDir, entry.name);
|
|
77
|
+
if (!packDir)
|
|
78
|
+
continue;
|
|
79
|
+
const parsed = parseSkillHeaderFile(path.join(packDir, "SKILL.md"));
|
|
80
|
+
if (!parsed.ok || !parsed.header)
|
|
81
|
+
continue;
|
|
82
|
+
names.push(parsed.header.name);
|
|
83
|
+
}
|
|
84
|
+
return { count: names.length, names };
|
|
85
|
+
}
|
|
86
|
+
function buildCandidates(opts) {
|
|
87
|
+
const appDir = opts.appDir ?? getAppDir();
|
|
88
|
+
const exeDir = opts.exeDir ?? path.dirname(process.execPath);
|
|
89
|
+
const candidates = [];
|
|
90
|
+
if (process.env["XCODER_HOME"]) {
|
|
91
|
+
candidates.push({ root: process.env["XCODER_HOME"], source: "xcoders-home" });
|
|
92
|
+
}
|
|
93
|
+
candidates.push({
|
|
94
|
+
root: path.dirname(getUserHomeSkillsDir(opts.homeDir)),
|
|
95
|
+
source: "user-home",
|
|
96
|
+
});
|
|
97
|
+
candidates.push({ root: appDir, source: "installer" });
|
|
98
|
+
candidates.push({ root: path.join(exeDir, "..", "share", "xcoder"), source: "installer" });
|
|
99
|
+
candidates.push({ root: path.join(appDir, ".."), source: "installer" });
|
|
100
|
+
candidates.push({ root: path.join(appDir, "..", ".."), source: "installer" });
|
|
101
|
+
candidates.push({ root: process.cwd(), source: "cwd" });
|
|
102
|
+
return candidates;
|
|
103
|
+
}
|
|
104
|
+
/** Memoised results, keyed by the option tuple so an injected dir never aliases. */
|
|
105
|
+
const memo = new Map();
|
|
106
|
+
function memoKey(opts) {
|
|
107
|
+
return [
|
|
108
|
+
opts.skillDir ?? "\u0000",
|
|
109
|
+
opts.homeDir ?? "\u0000",
|
|
110
|
+
opts.appDir ?? "\u0000",
|
|
111
|
+
opts.exeDir ?? "\u0000",
|
|
112
|
+
process.env["XCODER_HOME"] ?? "\u0000",
|
|
113
|
+
process.cwd(),
|
|
114
|
+
].join("\u0001");
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Resolve the skills root, probing each candidate in precedence order and
|
|
118
|
+
* returning the first one that holds at least one usable pack.
|
|
119
|
+
*/
|
|
120
|
+
export function resolveSkillsRoot(opts = {}) {
|
|
121
|
+
const key = memoKey(opts);
|
|
122
|
+
const cached = memo.get(key);
|
|
123
|
+
if (cached)
|
|
124
|
+
return cached;
|
|
125
|
+
let result;
|
|
126
|
+
if (opts.skillDir) {
|
|
127
|
+
// Explicit wins even when empty (T2): tests inject a temp dir and assert
|
|
128
|
+
// zero skills; silently falling back would read the developer's real dir.
|
|
129
|
+
const skillsDir = path.resolve(opts.skillDir);
|
|
130
|
+
result = {
|
|
131
|
+
root: path.dirname(skillsDir),
|
|
132
|
+
skillsDir,
|
|
133
|
+
source: "explicit",
|
|
134
|
+
usableCount: probeSkillsDir(skillsDir).count,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
const candidates = buildCandidates(opts);
|
|
139
|
+
const fallbackRoot = opts.appDir ?? getAppDir();
|
|
140
|
+
result = {
|
|
141
|
+
root: fallbackRoot,
|
|
142
|
+
skillsDir: path.join(fallbackRoot, "skills"),
|
|
143
|
+
source: "fallback",
|
|
144
|
+
usableCount: 0,
|
|
145
|
+
};
|
|
146
|
+
for (const candidate of candidates) {
|
|
147
|
+
const skillsDir = path.join(candidate.root, "skills");
|
|
148
|
+
const probe = probeSkillsDir(skillsDir);
|
|
149
|
+
if (probe.count > 0) {
|
|
150
|
+
result = {
|
|
151
|
+
root: candidate.root,
|
|
152
|
+
skillsDir,
|
|
153
|
+
source: candidate.source,
|
|
154
|
+
usableCount: probe.count,
|
|
155
|
+
};
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
memo.set(key, result);
|
|
161
|
+
logResolvedRoot(result);
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
/** Test hook: drop memoised resolutions and allow the debug line again. */
|
|
165
|
+
export function resetSkillsRootCache() {
|
|
166
|
+
memo.clear();
|
|
167
|
+
debugLogged = false;
|
|
168
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: software-architect
|
|
3
|
+
role: architecture
|
|
4
|
+
description: System-level design for new services/features/migrations — explicit tradeoffs, failure-mode analysis, and documented decisions instead of implementing the first design that occurs to you.
|
|
5
|
+
triggers:
|
|
6
|
+
- "architecture"
|
|
7
|
+
- "design a system"
|
|
8
|
+
- "system design"
|
|
9
|
+
- "design doc"
|
|
10
|
+
- "how should we structure"
|
|
11
|
+
- "scalability"
|
|
12
|
+
- "microservice"
|
|
13
|
+
- "migrate"
|
|
14
|
+
- "migration plan"
|
|
15
|
+
- "architecture decision record"
|
|
16
|
+
- "tech stack"
|
|
17
|
+
version: "1.0.0"
|
|
18
|
+
requires_tools:
|
|
19
|
+
- read_tool
|
|
20
|
+
- grep_tool
|
|
21
|
+
- glob_tool
|
|
22
|
+
- write_edit_tool
|
|
23
|
+
composes_with:
|
|
24
|
+
- workspace-context
|
|
25
|
+
- task-planning
|
|
26
|
+
- software-engineer
|
|
27
|
+
- docker
|
|
28
|
+
- kubernetes
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Process
|
|
32
|
+
|
|
33
|
+
1. Establish the actual constraints before designing: expected scale (requests/sec, data volume,
|
|
34
|
+
team size), consistency requirements, latency budget, and what already exists that this must
|
|
35
|
+
integrate with. A design without stated constraints is a guess, not an architecture.
|
|
36
|
+
2. Identify 2–3 genuinely distinct approaches (not one approach and two straw men) and name the
|
|
37
|
+
real tradeoff each makes — write these down even in an informal design doc; "we considered X"
|
|
38
|
+
without the tradeoff is not useful to a future reader.
|
|
39
|
+
3. Design for the failure modes, not just the happy path: what happens when a downstream service
|
|
40
|
+
is slow, unavailable, or returns bad data; what's the blast radius of one component failing;
|
|
41
|
+
what's recoverable automatically vs. needs a human.
|
|
42
|
+
4. Draw the boundary between services/modules along data ownership and change-rate, not
|
|
43
|
+
convenience — two things that change together for unrelated reasons are a sign of a missing
|
|
44
|
+
boundary; two things that always change together are a sign of an unnecessary one.
|
|
45
|
+
5. Record the decision (an ADR-style note: context, options considered, decision, consequences) so
|
|
46
|
+
the reasoning survives past the current conversation — a design that only exists as an
|
|
47
|
+
unexplained set of files is a maintenance liability.
|
|
48
|
+
|
|
49
|
+
## Instructions — non-negotiable
|
|
50
|
+
|
|
51
|
+
- Never propose a distributed/microservices architecture to solve a problem a monolith handles
|
|
52
|
+
fine — the complexity cost (network calls, partial failure, deployment coordination) needs to be
|
|
53
|
+
justified by an actual scaling or team-boundary need, not defaulted to.
|
|
54
|
+
- State the consistency model explicitly for any design involving more than one data store
|
|
55
|
+
(eventual vs. strong, and what happens during the inconsistency window) — "it'll sync eventually"
|
|
56
|
+
without specifying how is not a complete design.
|
|
57
|
+
- Any design that introduces a new external dependency (a new database, queue, cloud service)
|
|
58
|
+
should name what it replaces or what it enables that wasn't possible before — dependencies are
|
|
59
|
+
not free.
|
|
60
|
+
|
|
61
|
+
## Strategies
|
|
62
|
+
|
|
63
|
+
- Prefer boring, well-understood technology for the parts of the system that aren't the actual
|
|
64
|
+
differentiator — save novel/complex choices for where they earn their keep.
|
|
65
|
+
- Design for the current known scale plus a reasonable margin, not for a hypothetical 100x that may
|
|
66
|
+
never materialize — premature scaling design has a real cost in complexity today.
|
|
67
|
+
- When a migration is involved, design the rollback path with the same rigor as the forward path —
|
|
68
|
+
"we'll just roll back if it fails" is not a plan unless you've specified how.
|
|
69
|
+
|
|
70
|
+
## Experience
|
|
71
|
+
|
|
72
|
+
- The most common architecture failure isn't picking the wrong technology, it's an unstated
|
|
73
|
+
assumption about consistency, ownership, or failure handling that only surfaces in production —
|
|
74
|
+
make those assumptions explicit in the design doc even when they seem obvious.
|
|
75
|
+
- Boundaries that map to team/ownership structure tend to survive; boundaries that only reflect a
|
|
76
|
+
snapshot of current code organization tend to get redrawn — factor in who will maintain each
|
|
77
|
+
piece, not just how the code happens to be organized today.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: software-engineer
|
|
3
|
+
role: engineering
|
|
4
|
+
description: General software engineering discipline for implementation tasks — small verifiable changes, tests before/alongside code, and code that's ready for review rather than "it ran once on my machine."
|
|
5
|
+
triggers:
|
|
6
|
+
- "implement"
|
|
7
|
+
- "write code"
|
|
8
|
+
- "fix the bug"
|
|
9
|
+
- "fix a bug"
|
|
10
|
+
- "refactor"
|
|
11
|
+
- "add a feature"
|
|
12
|
+
- "code review"
|
|
13
|
+
- "write a function"
|
|
14
|
+
- "write tests"
|
|
15
|
+
version: "1.0.0"
|
|
16
|
+
requires_tools:
|
|
17
|
+
- read_tool
|
|
18
|
+
- write_edit_tool
|
|
19
|
+
- grep_tool
|
|
20
|
+
- glob_tool
|
|
21
|
+
- run_command_tool
|
|
22
|
+
composes_with:
|
|
23
|
+
- workspace-context
|
|
24
|
+
- task-planning
|
|
25
|
+
- software-architect
|
|
26
|
+
- qa-engineer
|
|
27
|
+
- git-vcs
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Process
|
|
31
|
+
|
|
32
|
+
1. Read the surrounding code before writing any — match existing patterns (naming, error handling,
|
|
33
|
+
module structure) rather than introducing a new style for one change. `grep_tool`/`glob_tool`
|
|
34
|
+
for how similar things are already done in this codebase before assuming a convention.
|
|
35
|
+
2. Make the smallest change that correctly solves the stated problem. A "fix the bug" task is not
|
|
36
|
+
an invitation to also refactor unrelated code nearby — that inflates the diff, makes review
|
|
37
|
+
harder, and increases the chance of an unrelated regression.
|
|
38
|
+
3. Write or update a test alongside the change, not after being asked. If the codebase has a test
|
|
39
|
+
framework, use it; if not, at minimum verify manually via `run_command_tool` and say so.
|
|
40
|
+
4. Run the actual test/build/lint commands this project uses (check `package.json` scripts,
|
|
41
|
+
`Makefile`, or CI config for the real invocation) before declaring the task done — "should work"
|
|
42
|
+
is not verification.
|
|
43
|
+
5. Handle errors explicitly. Don't swallow exceptions silently, don't return null/undefined for a
|
|
44
|
+
failure case without the caller having a way to detect it, and don't add a broad try/catch
|
|
45
|
+
whose only effect is hiding a bug you haven't diagnosed.
|
|
46
|
+
|
|
47
|
+
## Instructions — non-negotiable
|
|
48
|
+
|
|
49
|
+
- Never leave `console.log`/`print` debugging statements, commented-out old code, or TODO markers
|
|
50
|
+
for the exact thing you were asked to do (as opposed to genuinely out-of-scope follow-up work).
|
|
51
|
+
- Match existing naming/formatting conventions exactly — don't introduce camelCase into a
|
|
52
|
+
snake_case codebase or vice versa for "personal preference" reasons.
|
|
53
|
+
- Never silently change a public function's signature or behavior that other code depends on
|
|
54
|
+
without updating every call site — `grep_tool` for all usages first.
|
|
55
|
+
- If a fix reveals the same bug pattern exists elsewhere, say so explicitly rather than silently
|
|
56
|
+
fixing only the one instance mentioned — but don't silently fix the others without flagging it.
|
|
57
|
+
|
|
58
|
+
## Strategies
|
|
59
|
+
|
|
60
|
+
- Prefer pure functions and explicit data flow over shared mutable state when adding new code —
|
|
61
|
+
easier to test, easier for the next person (or the next agent run) to reason about.
|
|
62
|
+
- When two implementation approaches are both reasonable, prefer the one that's more consistent
|
|
63
|
+
with the rest of the codebase over the one that's abstractly "better," unless the task is
|
|
64
|
+
specifically about improving that pattern.
|
|
65
|
+
- If a task is ambiguous about behavior at an edge case, pick the interpretation consistent with
|
|
66
|
+
how the rest of the system handles similar edge cases, and state the assumption.
|
|
67
|
+
|
|
68
|
+
## Experience
|
|
69
|
+
|
|
70
|
+
- The most common real defect in agent-authored code is an untested edge case discovered by the
|
|
71
|
+
next reviewer, not a syntax error — the fix is deliberately testing boundaries (empty input,
|
|
72
|
+
null, zero, max values, concurrent access) rather than only the example given in the task.
|
|
73
|
+
- Large, unfocused diffs get rejected in review more often than small correct ones — resist the
|
|
74
|
+
urge to "clean up while I'm in here" unless asked.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: solid-principles
|
|
3
|
+
role: Software Architect / OOP Design Specialist
|
|
4
|
+
description: >
|
|
5
|
+
Reference guide to the five SOLID object-oriented design principles (Single Responsibility,
|
|
6
|
+
Open/Closed, Liskov Substitution, Interface Segregation, Dependency Inversion), complete with
|
|
7
|
+
directives, violation signs, and fix patterns. Load whenever reviewing class or module design,
|
|
8
|
+
refactoring coupled code, or evaluating adherence to clean OOP design principles.
|
|
9
|
+
triggers: [solid, "solid principles", "single responsibility", "open closed", "liskov substitution", "interface segregation", "dependency inversion", decouple, refactor, "oop design"]
|
|
10
|
+
version: 1.0
|
|
11
|
+
requires_tools: [read_tool, grep_tool]
|
|
12
|
+
composes_with: [programmer, software-engineer, architect, rca]
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# SOLID Principles
|
|
16
|
+
|
|
17
|
+
A quick-reference guide to the five SOLID principles, each with a directive, signs of violation, and how to fix it.
|
|
18
|
+
|
|
19
|
+
## How to use this skill
|
|
20
|
+
|
|
21
|
+
1. If the user names a specific principle, explain the directive and apply it to their code/problem.
|
|
22
|
+
2. If the user pastes code and asks for a review, scan it against the **violation signs** for each principle and flag the ones that apply.
|
|
23
|
+
3. If the user describes a design problem, use the **Quick Decision Guide** to match the symptom to the principle that addresses it.
|
|
24
|
+
4. Don't force all five onto every review — flag what's genuinely relevant, and note tradeoffs (see **General Directives**).
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## S — Single Responsibility Principle
|
|
29
|
+
**Directive:** A class/module should have only one reason to change.
|
|
30
|
+
**Violation signs:**
|
|
31
|
+
- A class does unrelated things (e.g. a `User` class that also handles email sending and database persistence).
|
|
32
|
+
- Changing one feature risks breaking unrelated functionality.
|
|
33
|
+
- The class name is vague or joined with "and" (`ReportGeneratorAndEmailer`).
|
|
34
|
+
**Fix:** Split responsibilities into separate classes, each owning one concern; compose them where needed.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## O — Open/Closed Principle
|
|
39
|
+
**Directive:** Classes should be open for extension, but closed for modification.
|
|
40
|
+
**Violation signs:**
|
|
41
|
+
- Adding a new case means editing an existing class's internals (e.g. a growing `if/elif` or `switch` chain on type).
|
|
42
|
+
- Every new feature touches the same core file, risking regressions in unrelated cases.
|
|
43
|
+
**Fix:** Extract the varying behavior behind an interface/abstract class, and add new behavior via new subclasses or implementations instead of editing existing code (Strategy or Factory patterns often apply here).
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## L — Liskov Substitution Principle
|
|
48
|
+
**Directive:** Subtypes must be substitutable for their base types without breaking correctness.
|
|
49
|
+
**Violation signs:**
|
|
50
|
+
- A subclass overrides a method to throw an exception, do nothing, or narrow what the base type promised.
|
|
51
|
+
- Client code checks the concrete type before calling a method (`if isinstance(x, SubclassY)`).
|
|
52
|
+
- Classic example: `Square extends Rectangle` breaks if `setWidth`/`setHeight` are independent in the base class.
|
|
53
|
+
**Fix:** Make sure a subclass honors the base class's contract (preconditions no stronger, postconditions no weaker). If it can't, it shouldn't be a subclass — reach for composition or a shared interface instead.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## I — Interface Segregation Principle
|
|
58
|
+
**Directive:** Clients shouldn't be forced to depend on methods they don't use.
|
|
59
|
+
**Violation signs:**
|
|
60
|
+
- A large "fat" interface where implementers must stub out irrelevant methods (`throw new NotImplementedException()`).
|
|
61
|
+
- Changing one method's signature forces recompiling/retesting classes that never use it.
|
|
62
|
+
**Fix:** Split large interfaces into smaller, role-specific ones; classes implement only the interfaces relevant to them.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## D — Dependency Inversion Principle
|
|
67
|
+
**Directive:** Depend on abstractions, not concrete implementations. High-level modules shouldn't depend on low-level modules — both should depend on abstractions.
|
|
68
|
+
**Violation signs:**
|
|
69
|
+
- A high-level class directly instantiates a low-level class (`new MySqlDatabase()` inside business logic).
|
|
70
|
+
- Swapping an implementation (e.g. database, payment provider) requires editing high-level code.
|
|
71
|
+
- Hard to unit test because dependencies can't be mocked.
|
|
72
|
+
**Fix:** Introduce an interface/abstract class between layers; inject the concrete implementation from outside (constructor/dependency injection) rather than instantiating it inline.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Quick Decision Guide
|
|
77
|
+
|
|
78
|
+
| Symptom | Principle Violated |
|
|
79
|
+
|---|---|
|
|
80
|
+
| Class does too many unrelated things | Single Responsibility |
|
|
81
|
+
| Adding a feature means editing existing code everywhere | Open/Closed |
|
|
82
|
+
| Subclass breaks behavior the base class promised | Liskov Substitution |
|
|
83
|
+
| Class forced to implement methods it doesn't need | Interface Segregation |
|
|
84
|
+
| Business logic tightly coupled to a concrete implementation | Dependency Inversion |
|
|
85
|
+
| Hard to unit test due to hardcoded dependencies | Dependency Inversion |
|
|
86
|
+
| Growing if/else or switch on type | Open/Closed |
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## General Directives
|
|
91
|
+
- SOLID principles are guidelines, not laws — over-applying them (e.g. an interface for every single class) can add needless indirection. Weigh the cost of abstraction against the actual likelihood of change.
|
|
92
|
+
- SRP and ISP both fight bloat — SRP at the class level, ISP at the interface level.
|
|
93
|
+
- OCP and DIP work together: depending on abstractions (DIP) is usually what *lets* you extend without modifying (OCP).
|
|
94
|
+
- When reviewing code, prioritize violations that cause real pain (hard to test, hard to extend, fragile on change) over theoretical purity.
|