用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/CodySwannGT/lisa --skill lisa-tracker-sync命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
| name | lisa-tracker-sync |
| description | Vendor-neutral wrapper for… |
| allowed-tools | ["Skill","Bash","Read"] |
Thin dispatcher. Resolves the configured destination tracker and delegates to the matching vendor sync skill.
See the config-resolution rule for configuration and dispatch table.
lisa-tracker-write)."No tracker configured in .lisa.config.json. Run /lisa:setup:jira, /lisa:setup:github, or /lisa:setup:linear first."jira → invoke lisa-jira-sync with $ARGUMENTS verbatim.github → invoke lisa-github-sync with $ARGUMENTS verbatim.linear → invoke lisa-linear-sync with $ARGUMENTS verbatim."Unknown tracker '<value>' in .lisa.config.json. Expected 'jira', 'github', or 'linear'."$ARGUMENTS is forwarded verbatim, including the optional --rollup flag (see "Parent status rollup" below), pr_url=<url>, and merge_sha=<sha>. The shim never interprets these — the vendor skill does.
There is no per-milestone lane-write flag on any vendor. This paragraph previously documented
--update-labelon GitHub and--update-stateon Linear.--update-labelwas never implemented —lisa-github-syncsays flatly "This skill never relabels" — so a caller passing it got a silent no-op on GitHub and a real write on Linear for the equivalent flag. Both are gone.--rollupis the only write path a sync skill has.
Every suggested or performed transition names only a role the project configured, never a status, state or label discovered from the tracker's live workflow (transition lists, board columns, type-derived matches, other tickets). This binds a lead performing tracker writes exactly as it binds a subagent.
Two consequences the vendor arms must not restate differently:
review and the qa.* roles are optional and carry no default — omitting one means the project does not run that step, and the lifecycle skips it. "Unset" must never resolve to a built-in name; that is the difference between "not customized" and "we deliberately don't do this".type), it selects by board position rather than intent — so on a board carrying more than one plausible state it returns whichever sits earliest, which is exactly the human-only lane a project left out of its config on purpose.Resolve roles through the shared resolver rather than an inlined helper:
node "${CLAUDE_PLUGIN_ROOT:-${PLUGIN_ROOT:-plugins/lisa}}/scripts/resolve-lifecycle-role.mjs" \
--role <role> --vendor <jira|linear|github> --intent <read|write> [--env <env>]
Exit 0 with a value means configured; exit 0 with empty output means an optional role is unset — skip the transition; exit 2 means a required role is unset or a write was refused a fallback value. Any other exit is a resolver failure, never an unset role.
If $ARGUMENTS is empty, all vendor skills auto-detect a ticket reference from the active plan file (most recently modified .md in plans/).
--rollup)When the caller passes --rollup after the milestone, the dispatch target additionally derives the parent/container's lifecycle state from its children instead of acting on the work item directly. This is the vendor-neutral implementation of the Parent status rollup (the state machine) section of the leaf-only-lifecycle rule — cite that rule, do not restate the policy here. The shim is dispatch only; the rollup mechanics live in the vendor sync skill (lisa-github-sync, lisa-jira-sync, lisa-linear-sync), which resolves child membership via its *-read-* skill and evaluates the state machine below.
The state machine (first match wins, evaluated over the required leaves only, on the env ladder in-progress < dev < staging < production — the ordered keys of the project's env-keyed done map):
| If among the required leaves… | …the parent rolls up to | Role |
|---|---|---|
| any leaf is blocked | blocked / attention-needed | blocked |
else every required leaf has shipped to some env (each at a done-map value) | the least-advanced env among them | done[min-env] (terminal done at production) |
| else any leaf has started (claimed or in review, or shipped while a sibling has not) | active / in-progress | claimed (or review where supported) |
| else (leaves exist, none started) | unchanged | — |
leaf-only-lifecycle → Classifying a hold.run_rollup_classifier() {
local input_path="$1"
local attempted_paths=""
local seen_root=""
local candidate_suffix="scripts/rollup-blocker-classification.mjs"
local root root_real candidate candidate_real expected_candidate
local classifier_output
for root in "${CLAUDE_PLUGIN_ROOT:-}" "${PLUGIN_ROOT:-}"; do
[ -n "$root" ] || continue
[ "$root" != "$seen_root" ] || continue
seen_root="$root"
case "$root" in
/*) ;;
*) continue ;;
esac
case "$root" in
*/../*|*/..|*/./*|*/.) continue ;;
esac
candidate="${root%/}/$candidate_suffix"
if [ -z "$attempted_paths" ]; then
attempted_paths="$candidate"
else
attempted_paths=
root_real= ||
[ -f ] && [ -r ] ||
candidate_real= ||
expected_candidate=
[ = ] ||
classifier_output=;
0
\
>&2
1
\
>&2
1
}
On Stg → On Stg; mixed dev/staging → the dev value). Native terminal closure fires only at the production done, never at an intermediate env.ready — ready is a human "claim this leaf" signal; rollup only moves a parent between non-ready container states.done — multi-env projects roll up to whichever done value (including intermediate On Dev/On Stg) their leaves have collectively reached (see config-resolution "Env-keyed done"). Single-environment collapse (this repo): deploy.branches declares only production: main, so done is a single value, the only env rung is production, and the GitHub build lifecycle collapses to ready → claimed (in-progress) → done; the rollup terminal is simply done (or the PRD-side ticketed for PRD containers), with no dev/staging promotion hops and no env-keyed multi-entry chain to resolve.Safe-by-default when not yet supported. A vendor sync path that has not implemented native rollup MUST be a documented no-op that surfaces the derived state as a suggestion/comment rather than guessing a transition — never an unsafe default. Without --rollup, the sync skills behave exactly as before (milestone comment on the work item; no parent derivation).
When $ARGUMENTS includes pr_url=<url> with milestone pr-ready or pr-merged, the dispatch target must ensure ticket -> PR linkage, not just post a generic progress note:
Prefer the provider's native development-link primitive when Lisa can write and verify it for that provider.
Verify the native link using the provider read surface when available.
Whether or not the native link exists or cannot be verified, establish the managed backlink comment with the one command that owns it:
node scripts/lisa-work-item.mjs backlink --ref <work-item> --pr-url <url>
That command is idempotent by construction — it updates the existing [lisa-pr-link] comment rather than appending duplicates — and it refuses loudly for a tracker it cannot write. Do not restate its procedure in a vendor skill; the file that writes the comment is the file that checks it, and that is what stops the two from drifting.
This is the reverse half of lisa-git-submit-pr's PR body linkage. A PR that mentions a ticket is not considered fully synced until the ticket also has either a verified native PR link or the managed fallback comment.
status:* label on GitHub, the workflow status on JIRA, the native workflow state on Linear — but the owner is the same everywhere: build-intake / the vendor agent. Every arm only suggests. --rollup (parent derivation) is the sole exception, and it derives the parent from its children rather than advancing a leaf.leaf-only-lifecycle rule; it never sets a parent to ready and never resolves a dev/staging done in this single-environment repo.pr_url=<url> is present: native first, managed-comment fallback, never silently dropped.