dx-discover-repos
Resolve which repos a work item touches (explicit directive → simple block → cross-repo table → LLM). Used by the KAI-HUB router to fan an agent out across repos; 'which repos'.
- License 许可
- MIT
- 最近更新
- 2026-11-11
- Stars
- ★ 7
- Forks
- 3
01 前言 Front Matter
- name
- dx-discover-repos
- model
- sonnet
- description
- Resolve which repos a work item touches (explicit directive → simple block → cross-repo table → LLM). Used by the KAI-HUB router to fan an agent out across repos; 'which repos'.
- argument-hint
- <work-item-id>
02 资源文件 10
- 脚本scripts/parse-crossrepo-table.sh3.4 KB
- 脚本scripts/parse-explicit-repos.sh3.3 KB
- 脚本scripts/route-targets.sh6.1 KB
- 参考文档tests/fixtures/comment-explicit.txt84 B
- 参考文档tests/fixtures/comment-no-repos.txt48 B
- 参考文档tests/fixtures/config-multi-platform.yaml486 B
- 参考文档tests/fixtures/config-single-platform.yaml98 B
- 参考文档tests/fixtures/repos-registry.json405 B
- 参考文档tests/fixtures/research-crossrepo.md300 B
- 脚本tests/run-tests.sh7.1 KB
03 SKILL.md 正文
dx-discover-repos
Resolve the set of repos a work item touches and emit a structured JSON array the KAI-HUB router uses to fan a worker pipeline out — one run per repo.
This skill is the multi-repo brain of the hub model. Single-repo projects never call it: their worker fires directly via its own webhook (dual-mode workers).
Inputs
| Input | Source | Notes |
|---|---|---|
workItemId |
skill argument | the ticket being routed |
| trigger-comment text | .ai/run-context/trigger-comment.txt if present, else fetch from the work item |
the human comment that fired the hook (after @kai-<agent>) |
| repo registry | $DX_REPOS_REGISTRY (default .ai/automation/registries/repos.json) |
alias → metadata; see dx-hub/shared/registry-format.md |
Output (StructuredOutput)
A JSON array, constrained to known registry aliases — never invent repos:
[
{ "alias": "brand-one", "repoId": "…", "adoProject": "Example Project",
"cloneUrl": "https://…/_git/brand-one", "branch": "development",
"reason": "explicit 'repos:' directive in trigger comment" }
]
On ambiguity or no match the skill emits a structured error object instead of an array, which the hub turns into a clarification comment on the work item:
{ "error": "ambiguous", "code": 3, "message": "project spans 2 platforms — add 'platform:' …" }
{ "error": "no-match", "code": 8, "message": "no candidate repo matched platform=… scope=… brand=…" }
The cascade
First non-empty tier wins. Tiers 0–2 are deterministic (fully testable offline); tier 3 is the LLM fallback, constrained to registry aliases.
digraph discover {
"Start" [shape=box];
"Tier 0: explicit repos: directive?" [shape=diamond];
"Tier 1: simple block present?" [shape=diamond];
"Tier 1 route ok?" [shape=diamond];
"Tier 2: cross-repo table?" [shape=diamond];
"Tier 3: LLM choose from registry" [shape=box];
"Emit JSON array" [shape=doublecircle];
"Emit structured error" [shape=doublecircle];
"Start" -> "Tier 0: explicit repos: directive?";
"Tier 0: explicit repos: directive?" -> "Emit JSON array" [label="non-empty"];
"Tier 0: explicit repos: directive?" -> "Tier 1: simple block present?" [label="empty"];
"Tier 1: simple block present?" -> "Tier 1 route ok?" [label="yes"];
"Tier 1: simple block present?" -> "Tier 2: cross-repo table?" [label="no"];
"Tier 1 route ok?" -> "Emit JSON array" [label="repos resolved"];
"Tier 1 route ok?" -> "Emit structured error" [label="exit 3 / exit 8"];
"Tier 2: cross-repo table?" -> "Emit JSON array" [label="non-empty"];
"Tier 2: cross-repo table?" -> "Tier 3: LLM choose from registry" [label="empty"];
"Tier 3: LLM choose from registry" -> "Emit JSON array";
}
Node Details
Tier 0: explicit repos: directive?
Run scripts/parse-explicit-repos.sh <comment-file> $DX_REPOS_REGISTRY. It reads
a repos: a, b directive a human typed after the @kai-<agent> tag and maps
each alias to its registry entry. Deterministic, no LLM. Unknown aliases are
skipped with a warning. A non-empty array wins the cascade immediately.
Tier 1: simple block present?
If the story has a ```simple block, this is a /dx-simple ticket — route by
its declared platform/brand/scope:
-
dx-simple/scripts/parse-simple-block.sh <raw-story.md> /tmp/block.yaml(resolve via$PLUGIN_BASE_DIR/dx-core/skills/dx-simple/scripts/…in the pipeline; the worker keeps this script — only the routing brain moved here). -
Bridge: synthesize a
config.yaml-shapedrepos:block from the registry soroute-targets.sh(which reads YAML viarepos_table, not JSON) can consume it.repos.jsonstays the single source of truth:jq -r '"repos:", (to_entries[] | " - name: \(.key)\n role: \(.value.role)" + (if .value.platform then "\n platform: \(.value.platform)" else "" end) + (if .value.brand then "\n brand: \(.value.brand)" else "" end) + (if .value.adoProject then "\n ado-project: \(.value.adoProject)" else "" end))' \ "$DX_REPOS_REGISTRY" > /tmp/discover-repos.yaml -
Build a reachability map (every alias → placeholder id; the real worker id comes from
agents.jsonat queue time, so the value is a filter-only stub):MAP=$(jq -c 'to_entries | map({(.key): "x"}) | add' "$DX_REPOS_REGISTRY") -
scripts/route-targets.sh /tmp/block.yaml /tmp/discover-repos.yaml "$MAP".- exit 0 → map the emitted
.repoaliases back to full registry entries and emit the JSON array. - exit 3 (ambiguous — missing platform/brand) → emit the
ambiguousstructured error with the script's stderr message. - exit 8 (no candidate matched) → emit the
no-matchstructured error.
- exit 0 → map the emitted
Tier 1 route ok?
Branch on route-targets' exit code (handled above). Errors stop the cascade — do not fall through to tier 2/3; the hub needs the human to clarify.
Tier 2: cross-repo table?
Run scripts/parse-crossrepo-table.sh <triage.md|research.md> $DX_REPOS_REGISTRY.
It extracts repo aliases from the ## Cross-Repo Scope markdown table that
triage/research emit (see dx-core/shared/repo-discovery.md). Non-matching rows
are skipped. A non-empty array wins.
Tier 3: LLM choose from registry
Only if every deterministic tier was empty. Read the work item title +
description and choose the touched repos from the registry aliases only.
List the available aliases (jq -r 'keys[]' $DX_REPOS_REGISTRY) and pick the
subset the change clearly touches. Never emit an alias not in the registry. If
nothing clearly matches, emit the no-match structured error rather than
guessing.
Emit JSON array
Each entry must carry alias, repoId, adoProject, cloneUrl, branch, reason.
Write to the run-context output file the hub reads, and return it as the
StructuredOutput result.
Emit structured error
{ error, code, message }. The hub posts the message to the work item as a
clarification comment and queues nothing.
04 同仓库更多 Skills
dx-hub-status
Show hub dispatch status — which repos are running, done, blocked or failed. Use for 'hub status', 'what's running'.
dx-hub-init
Initialize a hub directory for multi-repo orchestration. Discovers sibling repos, merges configs, validates CLI compatibility. Use when setting up hub mode for the first time. Trigger on "init hub", "set up hub", "multi-repo setup".
dx-hub-dispatch
Dispatch a ticket to several repos — open an independent Claude session per repo in VS Code terminals. Use for 'hub dispatch', 'work on ticket across repos'.
dx-hub-config
View and edit hub configuration — add repos, adjust terminal delay. Use to manage hub settings. Trigger on "hub config", "add repo to hub", "terminal delay".
dx-upgrade
Upgrade a consumer project to the installed plugin versions — run dx-doctor, fix stale and missing files, list manual actions. Use after upgrading plugins.
dx-ticket-analyze
Research an ADO/Jira ticket and list the source files and assets it involves. Use for 'analyze ticket', 'what files does this touch?', 'find files for this story'.