@codyswann/lisa 2.223.3 → 2.225.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/README.md +2 -2
- package/package.json +1 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-agent-ready/SKILL.md +97 -7
- package/plugins/lisa/.codex-plugin/skills/lisa-github-build-intake/SKILL.md +13 -3
- package/plugins/lisa/.codex-plugin/skills/lisa-intake/SKILL.md +17 -5
- package/plugins/lisa/.codex-plugin/skills/lisa-queue-status/SKILL.md +13 -5
- package/plugins/lisa/.codex-plugin/skills/lisa-repair-intake/SKILL.md +24 -10
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-automations/SKILL.md +12 -7
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-github/SKILL.md +54 -3
- package/plugins/lisa/commands/agent-ready.md +2 -2
- package/plugins/lisa/rules/eager/factory-model.md +3 -2
- package/plugins/lisa/rules/reference/config-resolution.md +8 -0
- package/plugins/lisa/rules/reference/factory-model.md +9 -5
- package/plugins/lisa/scripts/automation-status-expected-fleet.mjs +40 -10
- package/plugins/lisa/scripts/queue-contract-resolution.mjs +73 -4
- package/plugins/lisa/scripts/queue-status-build-readers.mjs +62 -10
- package/plugins/lisa/skills/lisa-agent-ready/SKILL.md +98 -8
- package/plugins/lisa/skills/lisa-agent-ready/agents/openai.yaml +2 -2
- package/plugins/lisa/skills/lisa-github-build-intake/SKILL.md +13 -3
- package/plugins/lisa/skills/lisa-intake/SKILL.md +17 -5
- package/plugins/lisa/skills/lisa-queue-status/SKILL.md +13 -5
- package/plugins/lisa/skills/lisa-repair-intake/SKILL.md +24 -10
- package/plugins/lisa/skills/lisa-setup-automations/SKILL.md +12 -7
- package/plugins/lisa/skills/lisa-setup-github/SKILL.md +54 -3
- package/plugins/lisa-agy/commands/lisa/agent-ready.md +2 -2
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/scripts/automation-status-expected-fleet.mjs +40 -10
- package/plugins/lisa-agy/scripts/queue-contract-resolution.mjs +73 -4
- package/plugins/lisa-agy/scripts/queue-status-build-readers.mjs +62 -10
- package/plugins/lisa-agy/skills/lisa-agent-ready/SKILL.md +98 -8
- package/plugins/lisa-agy/skills/lisa-github-build-intake/SKILL.md +13 -3
- package/plugins/lisa-agy/skills/lisa-intake/SKILL.md +17 -5
- package/plugins/lisa-agy/skills/lisa-queue-status/SKILL.md +13 -5
- package/plugins/lisa-agy/skills/lisa-repair-intake/SKILL.md +24 -10
- package/plugins/lisa-agy/skills/lisa-setup-automations/SKILL.md +12 -7
- package/plugins/lisa-agy/skills/lisa-setup-github/SKILL.md +54 -3
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/commands/lisa/agent-ready.md +2 -2
- package/plugins/lisa-copilot/rules/eager/factory-model.md +3 -2
- package/plugins/lisa-copilot/rules/reference/config-resolution.md +8 -0
- package/plugins/lisa-copilot/rules/reference/factory-model.md +9 -5
- package/plugins/lisa-copilot/scripts/automation-status-expected-fleet.mjs +40 -10
- package/plugins/lisa-copilot/scripts/queue-contract-resolution.mjs +73 -4
- package/plugins/lisa-copilot/scripts/queue-status-build-readers.mjs +62 -10
- package/plugins/lisa-copilot/skills/lisa-agent-ready/SKILL.md +98 -8
- package/plugins/lisa-copilot/skills/lisa-github-build-intake/SKILL.md +13 -3
- package/plugins/lisa-copilot/skills/lisa-intake/SKILL.md +17 -5
- package/plugins/lisa-copilot/skills/lisa-queue-status/SKILL.md +13 -5
- package/plugins/lisa-copilot/skills/lisa-repair-intake/SKILL.md +24 -10
- package/plugins/lisa-copilot/skills/lisa-setup-automations/SKILL.md +12 -7
- package/plugins/lisa-copilot/skills/lisa-setup-github/SKILL.md +54 -3
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/commands/lisa/agent-ready.md +2 -2
- package/plugins/lisa-cursor/rules/config-resolution-reference.mdc +8 -0
- package/plugins/lisa-cursor/rules/factory-model-reference.mdc +9 -5
- package/plugins/lisa-cursor/rules/factory-model.mdc +3 -2
- package/plugins/lisa-cursor/scripts/automation-status-expected-fleet.mjs +40 -10
- package/plugins/lisa-cursor/scripts/queue-contract-resolution.mjs +73 -4
- package/plugins/lisa-cursor/scripts/queue-status-build-readers.mjs +62 -10
- package/plugins/lisa-cursor/skills/lisa-agent-ready/SKILL.md +98 -8
- package/plugins/lisa-cursor/skills/lisa-github-build-intake/SKILL.md +13 -3
- package/plugins/lisa-cursor/skills/lisa-intake/SKILL.md +17 -5
- package/plugins/lisa-cursor/skills/lisa-queue-status/SKILL.md +13 -5
- package/plugins/lisa-cursor/skills/lisa-repair-intake/SKILL.md +24 -10
- package/plugins/lisa-cursor/skills/lisa-setup-automations/SKILL.md +12 -7
- package/plugins/lisa-cursor/skills/lisa-setup-github/SKILL.md +54 -3
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/src/base/commands/agent-ready.md +2 -2
- package/plugins/src/base/rules/eager/factory-model.md +3 -2
- package/plugins/src/base/rules/reference/config-resolution.md +8 -0
- package/plugins/src/base/rules/reference/factory-model.md +9 -5
- package/plugins/src/base/scripts/automation-status-expected-fleet.mjs +40 -10
- package/plugins/src/base/scripts/queue-contract-resolution.mjs +73 -4
- package/plugins/src/base/scripts/queue-status-build-readers.mjs +62 -10
- package/plugins/src/base/skills/lisa-agent-ready/SKILL.md +98 -8
- package/plugins/src/base/skills/lisa-github-build-intake/SKILL.md +13 -3
- package/plugins/src/base/skills/lisa-intake/SKILL.md +17 -5
- package/plugins/src/base/skills/lisa-queue-status/SKILL.md +13 -5
- package/plugins/src/base/skills/lisa-repair-intake/SKILL.md +24 -10
- package/plugins/src/base/skills/lisa-setup-automations/SKILL.md +12 -7
- package/plugins/src/base/skills/lisa-setup-github/SKILL.md +54 -3
- package/ui/index.html +2 -2
|
@@ -6,7 +6,8 @@ allowed-tools: ["Skill", "Bash", "Read", "Write", "Edit"]
|
|
|
6
6
|
|
|
7
7
|
# Repair Intake: $ARGUMENTS
|
|
8
8
|
|
|
9
|
-
Run one batch-**repair** cycle against the queue identified by `$ARGUMENTS
|
|
9
|
+
Run one batch-**repair** cycle against the queue identified by `$ARGUMENTS`, or by merged GitHub
|
|
10
|
+
config when the queue is omitted and a GitHub source/tracker default is resolvable. Where `lisa-intake`
|
|
10
11
|
scans the `ready` role and moves work *forward*, repair-intake scans the **stuck and
|
|
11
12
|
close-out** roles and moves work *unstuck* or *fully closed*:
|
|
12
13
|
|
|
@@ -73,22 +74,24 @@ lifecycle state with provider-native closure and rollup state.
|
|
|
73
74
|
## Public contract
|
|
74
75
|
|
|
75
76
|
```text
|
|
76
|
-
/lisa:repair-intake <queue> [intake_mode=prd|build|both] [stale_after=2h] [max_candidates=100] [force=true]
|
|
77
|
+
/lisa:repair-intake [<queue>] [intake_mode=prd|build|both] [build_queue=owner/repo] [stale_after=2h] [max_candidates=100] [force=true]
|
|
77
78
|
```
|
|
78
79
|
|
|
79
80
|
| Token | Meaning | Default |
|
|
80
81
|
|-------|---------|---------|
|
|
81
|
-
| `<queue>` | Same queue identifier `lisa-intake` accepts (see Source dispatch).
|
|
82
|
+
| `<queue>` | Same queue identifier `lisa-intake` accepts (see Source dispatch). Optional only when merged config resolves a GitHub source/tracker and identity; otherwise required. | merged GitHub default when resolvable |
|
|
82
83
|
| `intake_mode` | `prd` \| `build` \| `both`. Only meaningful for a GitHub `org/repo` (or bare `github`) that hosts both PRD and build label namespaces. `both` is unique to repair — a repair sweep usefully covers both lifecycles in one schedule. Absent → `both` when both namespaces exist, else whichever lifecycle exists. | `both` for dual GitHub queues; otherwise infer |
|
|
84
|
+
| `build_queue` | GitHub build scan target used with literal `github`, especially `intake_mode=both`. Explicit `owner/repo` or URL for a build-only invocation wins over this token; otherwise this wins over `github.queueRepo`. It never redirects the PRD scan. | `github.queueRepo`, then `github.org/github.repo` |
|
|
83
85
|
| `stale_after` | How long since the last state-changing transition into the in-progress role, or since the last human / PR-side forward-progress activity, before an in-progress item counts as stalled. Automation self-comments do not reset this clock. Accepts `24h`, `90m`, `2d`, or `0` (treat any in-progress item as stalled — manual recovery, also the only way to resume work on a provider that exposes no reliable timestamp). Overrides config. | `2h` |
|
|
84
86
|
| `max_candidates` | Cap on how many stuck/close-out candidates to enumerate and evaluate. Repair every materially actionable candidate within this bounded set, then stop. Overrides config. | `100` |
|
|
85
87
|
| `force` | `true` bypasses the loop-prevention backoff window (so a manual re-run re-attempts items even if their fingerprint is unchanged). It does **not** change the staleness rule — use `stale_after=0` for that. | `false` |
|
|
86
88
|
|
|
87
89
|
## Confirmation policy
|
|
88
90
|
|
|
89
|
-
Do NOT ask the caller whether to proceed. Once invoked
|
|
90
|
-
completion. The caller (a human at the CLI or a scheduled cron) has
|
|
91
|
-
by invoking the skill; re-prompting defeats the purpose of a
|
|
91
|
+
Do NOT ask the caller whether to proceed. Once invoked, resolve the explicit or config-backed
|
|
92
|
+
queue and run the cycle to completion. The caller (a human at the CLI or a scheduled cron) has
|
|
93
|
+
already authorized the run by invoking the skill; re-prompting defeats the purpose of a
|
|
94
|
+
background repair sweep.
|
|
92
95
|
|
|
93
96
|
Specifically forbidden:
|
|
94
97
|
|
|
@@ -105,8 +108,8 @@ Specifically forbidden:
|
|
|
105
108
|
|
|
106
109
|
The only legitimate reasons to stop early:
|
|
107
110
|
|
|
108
|
-
- Missing required input (no queue argument
|
|
109
|
-
missing value and exit.
|
|
111
|
+
- Missing required input (no queue argument **and** no resolvable GitHub default, or missing
|
|
112
|
+
project configuration). Surface the missing value and exit.
|
|
110
113
|
- The queue itself is misconfigured (Status property missing expected values, JIRA workflow
|
|
111
114
|
can't reach required transitions). Surface and exit.
|
|
112
115
|
- No stuck/close-out candidates, or none actionable this cycle. Exit cleanly with the idle-case
|
|
@@ -142,7 +145,7 @@ claim-and-advance). The essentials, inlined here so this skill is self-complete:
|
|
|
142
145
|
| GitHub **repo** URL / `org/repo` (PRD namespace) | PRD (GitHub) | source=github | `in_review`, `blocked`, terminal/open PRDs, missing PRD child links, all-terminal generated-work rollups |
|
|
143
146
|
| GitHub **repo** URL / `org/repo` with `tracker = github` (build namespace) | Build (GitHub) | tracker=github | `claimed`, `blocked`, terminal/open issues, parent rollups (intermediate-env + all-terminal), stale-`ready` containers |
|
|
144
147
|
| GitHub **repo** URL / `org/repo` with an open issue missing configured lifecycle labels | GitHub label normalization | per classified lifecycle | add configured `prd.ready` or build `ready` |
|
|
145
|
-
| Literal `github` | GitHub;
|
|
148
|
+
| Literal `github` or omitted GitHub repo when merged config resolves a GitHub source/tracker and identity | GitHub; PRD scans identity, build scans `build_queue` → merged `github.queueRepo` → identity; `both` runs those two lane-specific targets | per lifecycle | per lifecycle above, plus GitHub ready-label normalization |
|
|
146
149
|
| JIRA project key or full JQL | Build (JIRA) | tracker=jira | `claimed`, `blocked`, terminal/closure verification, parent rollups (intermediate-env + all-terminal), stale-`ready` containers |
|
|
147
150
|
|
|
148
151
|
Disambiguation (same as `lisa-intake`): a `notion.so`/`notion.site` URL → Notion; an Atlassian
|
|
@@ -153,6 +156,17 @@ token / literal `github` → GitHub; a bare token matching the JIRA project-key
|
|
|
153
156
|
URL is out of scope** — this skill is batch-only; repair one item by hand via `lisa-implement`
|
|
154
157
|
(build) or by re-running `lisa:<source>-to-tracker` (PRD).
|
|
155
158
|
|
|
159
|
+
For GitHub `intake_mode=build` (a build-only invocation), an explicit URL or `owner/repo` wins;
|
|
160
|
+
otherwise resolve `build_queue`, then local/global `github.queueRepo`, falling back to
|
|
161
|
+
`github.org/github.repo`. For `intake_mode=both`, the primary `<queue>` is the PRD identity/source
|
|
162
|
+
repo and `build_queue` controls the build lane, falling back through `github.queueRepo` to identity.
|
|
163
|
+
A short queueRepo is normalized to `github.org`. Thus `both` is a bounded split scan: PRD candidates
|
|
164
|
+
at the primary identity queue, build candidates at the resolved build queue, combined into one
|
|
165
|
+
summary. Never apply both lifecycle namespaces to the umbrella repo merely because
|
|
166
|
+
`github.queueRepo` is set. Repository identity remains distinct and continues to drive
|
|
167
|
+
`repo:<current>` filtering, writes, and automation names. If neither an explicit queue nor a
|
|
168
|
+
resolvable merged GitHub default exists, stop with the missing-input error.
|
|
169
|
+
|
|
156
170
|
Role names for every vendor are resolved from `.lisa.config.json` per the `config-resolution`
|
|
157
171
|
rule — never hardcode status/label strings. The relevant repair roles:
|
|
158
172
|
|
|
@@ -968,7 +982,7 @@ bucket and show compact refs plus counts.
|
|
|
968
982
|
/schedule "every 2 hours" /lisa:repair-intake https://linear.app/acme
|
|
969
983
|
/schedule "every 2 hours" /lisa:repair-intake acme/product-prds
|
|
970
984
|
/schedule "every 2 hours" /lisa:repair-intake acme/frontend-v2 intake_mode=build
|
|
971
|
-
/schedule "every 2 hours" /lisa:repair-intake
|
|
985
|
+
/schedule "every 2 hours" /lisa:repair-intake acme/frontend intake_mode=both build_queue=acme/planning
|
|
972
986
|
/schedule "every 4 hours" /lisa:repair-intake SE stale_after=12h
|
|
973
987
|
/lisa:repair-intake SE stale_after=0 force=true # manual: treat all in-progress as stalled, ignore backoff
|
|
974
988
|
```
|
|
@@ -59,9 +59,9 @@ report the exact conflicting path(s).
|
|
|
59
59
|
|
|
60
60
|
| Automation | Command it runs | Cadence |
|
|
61
61
|
|---|---|---|
|
|
62
|
-
| **intake-repair** | `/lisa:repair-intake <queue>` | every **60 minutes** |
|
|
63
|
-
| **intake-prd** | `/lisa:intake <PRD queue>` (e.g. `
|
|
64
|
-
| **intake-tickets** | `/lisa:intake <build queue>` (e.g. `
|
|
62
|
+
| **intake-repair** | `/lisa:repair-intake <resolved repair queue>` (GitHub self-host example: `acme/frontend intake_mode=both build_queue=acme/planning`) | every **60 minutes** |
|
|
63
|
+
| **intake-prd** | `/lisa:intake <PRD queue>` (e.g. `acme/frontend intake_mode=prd`) | every **60 minutes** |
|
|
64
|
+
| **intake-tickets** | `/lisa:intake <build queue>` (e.g. `acme/planning intake_mode=build`) | every **10 minutes** |
|
|
65
65
|
| **exploratory-bugs** | `/lisa-<stack>:exploratory-qa ready=<auto-start-tickets>` | **once a day** |
|
|
66
66
|
| **exploratory-prds** | `/lisa:project-ideation prd_ready=<auto-start-prds>` | **once a day** |
|
|
67
67
|
| **monitor** | `/lisa:monitor` | **once a day** |
|
|
@@ -75,10 +75,15 @@ lifecycle when the PRD queue has capacity," not "always create a new ready PRD."
|
|
|
75
75
|
`/lisa:queue-status`; if pressure exists, the cycle should report the blocking role/ref and the
|
|
76
76
|
smallest next action, usually `/lisa:intake <PRD queue>`, without invoking research or writing a PRD.
|
|
77
77
|
|
|
78
|
-
**Queue resolution.** Resolve the intake/repair queue from
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
**Queue resolution.** Resolve the intake/repair queue from merged config — `source` for the PRD
|
|
79
|
+
queue, `tracker` for the build queue. For GitHub, the PRD command uses canonical identity
|
|
80
|
+
`github.org/github.repo`; the build command resolves `github.queueRepo` and falls back to that
|
|
81
|
+
identity. Keep automation naming tied to the identity repo. Bake every resolved `owner/repo` into
|
|
82
|
+
the scheduled commands (for example `/lisa:intake acme/frontend intake_mode=prd`,
|
|
83
|
+
`/lisa:intake acme/planning intake_mode=build`, and
|
|
84
|
+
`/lisa:repair-intake acme/frontend intake_mode=both build_queue=acme/planning`) so a later
|
|
85
|
+
config/read-context failure cannot silently redirect the cron. A short queueRepo is normalized to
|
|
86
|
+
`github.org` before writing the automation.
|
|
82
87
|
|
|
83
88
|
**Naming + scope (so teardown is precise).** Name each automation with the stable prefix
|
|
84
89
|
`lisa-auto-<project>-` (e.g. `lisa-auto-<project>-intake-tickets`), where `<project>` identifies this
|
|
@@ -79,6 +79,23 @@ gh repo view "$ORG/$REPO" --json name,viewerPermission \
|
|
|
79
79
|
|
|
80
80
|
If permission is `READ` / `TRIAGE`, stop — lisa cannot create labels or issues. Surface and exit.
|
|
81
81
|
|
|
82
|
+
### Step 2b — Choose the queue repository
|
|
83
|
+
|
|
84
|
+
When GitHub is selected as the destination tracker, initialize the choice from an existing
|
|
85
|
+
`github.queueRepo`, or `$ORG/$REPO` when absent, then ask whether the build backlog lives there, in
|
|
86
|
+
the identity repo, or in another umbrella/planning repo. If the user gives an umbrella repo, accept a short name by normalizing it to `$ORG/<name>` or accept a full
|
|
87
|
+
`owner/repo`, then verify it is reachable and the authenticated identity can manage the lifecycle
|
|
88
|
+
labels Lisa needs:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
gh repo view "$QUEUE_ORG/$QUEUE_REPO" --json name,viewerPermission \
|
|
92
|
+
--jq 'if (.viewerPermission | IN("ADMIN","MAINTAIN","WRITE")) then "ok" else error("insufficient permission: \(.viewerPermission)") end'
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Store `github.queueRepo` only when the canonical queue `owner/repo` differs from `$ORG/$REPO`.
|
|
96
|
+
This choice changes queue scans, not repository identity: `github.repo`, `repo:<current>` claim
|
|
97
|
+
scoping, issue destinations, and automation naming remain tied to the identity/tracker repo.
|
|
98
|
+
|
|
82
99
|
### Step 3 — Scaffold the lifecycle label namespaces
|
|
83
100
|
|
|
84
101
|
Read role → label mappings with the same default-fallback ladder the intake skills use, so the labels created here exactly match what they look for. Only the namespaces selected in Step 0 are scaffolded.
|
|
@@ -92,12 +109,13 @@ read_role() { # $1=namespace (build|prd) $2=role $3=default
|
|
|
92
109
|
}
|
|
93
110
|
|
|
94
111
|
# Idempotent label creator: create if missing, leave untouched if present.
|
|
112
|
+
# LABEL_ORG/LABEL_REPO select the repo for the namespace being scaffolded.
|
|
95
113
|
ensure_label() { # $1=name $2=hex-color $3=description
|
|
96
114
|
local name="$1" color="$2" desc="$3"
|
|
97
|
-
if gh label list --repo "$
|
|
115
|
+
if gh label list --repo "$LABEL_ORG/$LABEL_REPO" --limit 200 --json name --jq '.[].name' | grep -qxF "$name"; then
|
|
98
116
|
echo " = $name (exists)"
|
|
99
117
|
else
|
|
100
|
-
gh label create "$name" --repo "$
|
|
118
|
+
gh label create "$name" --repo "$LABEL_ORG/$LABEL_REPO" --color "$color" --description "$desc" \
|
|
101
119
|
&& echo " + $name (created)"
|
|
102
120
|
fi
|
|
103
121
|
}
|
|
@@ -108,6 +126,8 @@ ensure_label() { # $1=name $2=hex-color $3=description
|
|
|
108
126
|
Defaults from `config-resolution`. The `done` role is **env-keyed** — create all three by default; a project whose terminal state is env-independent can later collapse `github.labels.build.done` to a single string.
|
|
109
127
|
|
|
110
128
|
```bash
|
|
129
|
+
LABEL_ORG="$QUEUE_ORG"
|
|
130
|
+
LABEL_REPO="$QUEUE_REPO"
|
|
111
131
|
ensure_label "$(read_role build ready status:ready)" FBCA04 "Ready for build (human signal)"
|
|
112
132
|
ensure_label "$(read_role build claimed status:in-progress)" 0E8A16 "Build in progress (agent owns)"
|
|
113
133
|
ensure_label "$(read_role build blocked status:blocked)" D93F0B "Blocked — human attention required"
|
|
@@ -119,6 +139,8 @@ ensure_label "$(read_role build done.production status:done)" 0E8A16 "Shipped
|
|
|
119
139
|
#### 3b. PRD-lifecycle labels (only if GitHub is the PRD source)
|
|
120
140
|
|
|
121
141
|
```bash
|
|
142
|
+
LABEL_ORG="$ORG"
|
|
143
|
+
LABEL_REPO="$REPO"
|
|
122
144
|
ensure_label "$(read_role prd draft prd-draft)" C5DEF5 "PRD in progress (product owns)"
|
|
123
145
|
ensure_label "$(read_role prd ready prd-ready)" FBCA04 "PRD ready for ticketing"
|
|
124
146
|
ensure_label "$(read_role prd in_review prd-in-review)" 5319E7 "Claude is reviewing this PRD"
|
|
@@ -145,6 +167,19 @@ jq --arg org "$ORG" --arg repo "$REPO" \
|
|
|
145
167
|
'.github = ((.github // {}) | .org = $org | .repo = $repo)' \
|
|
146
168
|
.lisa.config.json > .lisa.config.json.tmp && mv .lisa.config.json.tmp .lisa.config.json
|
|
147
169
|
|
|
170
|
+
# Queue repo is canonical owner/repo and omitted for the identity/default case.
|
|
171
|
+
# A source-only setup rerun preserves any existing build-queue choice.
|
|
172
|
+
if [ "$GITHUB_TRACKER_SELECTED" = "true" ]; then
|
|
173
|
+
if [ "$QUEUE_ORG/$QUEUE_REPO" = "$ORG/$REPO" ]; then
|
|
174
|
+
jq 'del(.github.queueRepo)' .lisa.config.json > .lisa.config.json.tmp \
|
|
175
|
+
&& mv .lisa.config.json.tmp .lisa.config.json
|
|
176
|
+
else
|
|
177
|
+
jq --arg queue "$QUEUE_ORG/$QUEUE_REPO" '.github.queueRepo = $queue' \
|
|
178
|
+
.lisa.config.json > .lisa.config.json.tmp \
|
|
179
|
+
&& mv .lisa.config.json.tmp .lisa.config.json
|
|
180
|
+
fi
|
|
181
|
+
fi
|
|
182
|
+
|
|
148
183
|
# Conditionally write label overrides (only roles the user mapped to non-default names).
|
|
149
184
|
# $LABEL_OVERRIDES_JSON is e.g. {"build":{"ready":"ready-for-dev"}} — {} if all defaults.
|
|
150
185
|
if [ -n "$LABEL_OVERRIDES_JSON" ] && [ "$LABEL_OVERRIDES_JSON" != "{}" ]; then
|
|
@@ -198,8 +233,24 @@ Both are project-wide switches that change every downstream skill's default —
|
|
|
198
233
|
|
|
199
234
|
```bash
|
|
200
235
|
jq -e '.github.org and .github.repo' .lisa.config.json >/dev/null
|
|
236
|
+
EFFECTIVE_ORG=$(jq -r '.github.org // empty' .lisa.config.local.json 2>/dev/null)
|
|
237
|
+
EFFECTIVE_ORG=${EFFECTIVE_ORG:-$(jq -r '.github.org' .lisa.config.json)}
|
|
238
|
+
EFFECTIVE_REPO=$(jq -r '.github.repo // empty' .lisa.config.local.json 2>/dev/null)
|
|
239
|
+
EFFECTIVE_REPO=${EFFECTIVE_REPO:-$(jq -r '.github.repo' .lisa.config.json)}
|
|
240
|
+
QUEUE_VALUE=$(jq -r '.github.queueRepo // empty' .lisa.config.local.json 2>/dev/null)
|
|
241
|
+
QUEUE_VALUE=${QUEUE_VALUE:-$(jq -r '.github.queueRepo // empty' .lisa.config.json)}
|
|
242
|
+
if [ -z "$QUEUE_VALUE" ]; then
|
|
243
|
+
QUEUE_REF="$EFFECTIVE_ORG/$EFFECTIVE_REPO"
|
|
244
|
+
elif [[ "$QUEUE_VALUE" == */* ]]; then
|
|
245
|
+
QUEUE_REF="$QUEUE_VALUE"
|
|
246
|
+
else
|
|
247
|
+
QUEUE_REF="$EFFECTIVE_ORG/$QUEUE_VALUE"
|
|
248
|
+
fi
|
|
249
|
+
gh repo view "$QUEUE_REF" --json nameWithOwner --jq .nameWithOwner
|
|
201
250
|
gh label list --repo "$ORG/$REPO" --limit 200 --json name --jq '.[].name' \
|
|
202
|
-
| grep -E '
|
|
251
|
+
| grep -E 'prd-' || true
|
|
252
|
+
gh label list --repo "$QUEUE_REF" --limit 200 --json name --jq '.[].name' \
|
|
253
|
+
| grep -E 'status:' || true
|
|
203
254
|
```
|
|
204
255
|
|
|
205
256
|
If `github.projects.v2` is configured, setup verification MUST also run the shared Project utility in
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: "Make a brownfield project agent-ready: build the initial knowledge wiki
|
|
2
|
+
description: "Make a brownfield project agent-ready: build the initial knowledge wiki through read-only, redacted ingestion, persist complete/partial/unavailable coverage for every source, write wiki/gaps.md with the questions only a human can answer, and converge over re-runs until every source is complete and zero gaps remain. Run before letting the automation fleet operate a brownfield project unattended."
|
|
3
3
|
argument-hint: "[path]"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Use the /lisa-agent-ready skill to build the initial knowledge wiki
|
|
6
|
+
Use the /lisa-agent-ready skill to build the initial knowledge wiki through read-only, redacted ingestion of every inventoried source, persist each source's complete/partial/unavailable status, write the human-answerable gaps to wiki/gaps.md, absorb any answered gaps from a prior run, and report whether every source is complete with zero gaps or what still blocks readiness. $ARGUMENTS
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import {
|
|
12
12
|
resolveBuildQueueArgument,
|
|
13
|
+
resolveGithubQueueRepoRef,
|
|
13
14
|
resolveGithubRepoRef,
|
|
14
15
|
resolvePrdQueueArgument,
|
|
15
16
|
resolvePrdSource,
|
|
@@ -119,9 +120,32 @@ export function resolveExpectedAutomationFleet(input = {}) {
|
|
|
119
120
|
|
|
120
121
|
const tracker = config.tracker;
|
|
121
122
|
const source = resolvePrdSource(config);
|
|
122
|
-
const
|
|
123
|
-
const
|
|
124
|
-
|
|
123
|
+
const explicitGithubIdentity = `${identity.owner}/${identity.repo}`;
|
|
124
|
+
const githubQueue =
|
|
125
|
+
tracker === "github"
|
|
126
|
+
? resolveGithubQueueRepoRef(config, {
|
|
127
|
+
gitRemoteUrl: input.gitRemoteUrl,
|
|
128
|
+
})
|
|
129
|
+
: null;
|
|
130
|
+
const explicitGithubQueue = githubQueue
|
|
131
|
+
? `${githubQueue.owner}/${githubQueue.repo}`
|
|
132
|
+
: undefined;
|
|
133
|
+
const prdQueue =
|
|
134
|
+
source === "github"
|
|
135
|
+
? `${explicitGithubIdentity} intake_mode=prd`
|
|
136
|
+
: resolvePrdQueueArgument(config, source);
|
|
137
|
+
const buildQueue = resolveBuildQueueArgument(config, tracker, {
|
|
138
|
+
explicitQueue: tracker === "github" ? explicitGithubQueue : undefined,
|
|
139
|
+
gitRemoteUrl: input.gitRemoteUrl,
|
|
140
|
+
});
|
|
141
|
+
const repairQueue = resolveRepairQueueArgument(
|
|
142
|
+
config,
|
|
143
|
+
source,
|
|
144
|
+
tracker,
|
|
145
|
+
explicitGithubIdentity,
|
|
146
|
+
explicitGithubQueue,
|
|
147
|
+
buildQueue
|
|
148
|
+
);
|
|
125
149
|
|
|
126
150
|
const expected = [
|
|
127
151
|
createExpectedEntry(
|
|
@@ -237,10 +261,17 @@ function createUnsupportedEntry(identity, id, reason) {
|
|
|
237
261
|
* @param {string | undefined} tracker
|
|
238
262
|
* @returns {string}
|
|
239
263
|
*/
|
|
240
|
-
function resolveRepairQueueArgument(
|
|
264
|
+
function resolveRepairQueueArgument(
|
|
265
|
+
config,
|
|
266
|
+
source,
|
|
267
|
+
tracker,
|
|
268
|
+
explicitGithubIdentity,
|
|
269
|
+
explicitGithubQueue,
|
|
270
|
+
resolvedBuildQueue
|
|
271
|
+
) {
|
|
241
272
|
if (tracker === "github" && source === "github") {
|
|
242
273
|
requireGithubRepo(config);
|
|
243
|
-
return
|
|
274
|
+
return `${explicitGithubIdentity} intake_mode=both build_queue=${explicitGithubQueue}`;
|
|
244
275
|
}
|
|
245
276
|
|
|
246
277
|
if (tracker === "linear" && source === "linear") {
|
|
@@ -260,13 +291,12 @@ function resolveRepairQueueArgument(config, source, tracker) {
|
|
|
260
291
|
|
|
261
292
|
if (tracker === "github" && source === undefined) {
|
|
262
293
|
requireGithubRepo(config);
|
|
263
|
-
return
|
|
294
|
+
return `${explicitGithubIdentity} intake_mode=both build_queue=${explicitGithubQueue}`;
|
|
264
295
|
}
|
|
265
296
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
: `${buildQueue} intake_mode=build`;
|
|
297
|
+
return resolvedBuildQueue.includes("intake_mode=")
|
|
298
|
+
? resolvedBuildQueue
|
|
299
|
+
: `${resolvedBuildQueue} intake_mode=build`;
|
|
270
300
|
}
|
|
271
301
|
|
|
272
302
|
/**
|
|
@@ -173,12 +173,17 @@ export function resolvePrdQueueArgument(
|
|
|
173
173
|
*/
|
|
174
174
|
export function resolveBuildQueueArgument(
|
|
175
175
|
config = {},
|
|
176
|
-
tracker = resolveBuildTracker(config)
|
|
176
|
+
tracker = resolveBuildTracker(config),
|
|
177
|
+
options = {}
|
|
177
178
|
) {
|
|
178
179
|
switch (tracker) {
|
|
179
|
-
case "github":
|
|
180
|
-
|
|
180
|
+
case "github": {
|
|
181
|
+
const queue = resolveGithubQueueRepoRef(config, options);
|
|
182
|
+
if (options.explicitQueue || config.github?.queueRepo) {
|
|
183
|
+
return `${queue.owner}/${queue.repo} intake_mode=build`;
|
|
184
|
+
}
|
|
181
185
|
return "github intake_mode=build";
|
|
186
|
+
}
|
|
182
187
|
case "linear":
|
|
183
188
|
requireLinearWorkspace(config);
|
|
184
189
|
return "linear";
|
|
@@ -340,6 +345,14 @@ export function resolveQueueContract(input = {}) {
|
|
|
340
345
|
const source = resolvePrdSource(config);
|
|
341
346
|
const tracker = resolveBuildTracker(config);
|
|
342
347
|
|
|
348
|
+
const githubIdentity = resolveGithubRepoRef(config, input.gitRemoteUrl);
|
|
349
|
+
const githubQueue =
|
|
350
|
+
tracker === "github"
|
|
351
|
+
? resolveGithubQueueRepoRef(config, {
|
|
352
|
+
gitRemoteUrl: input.gitRemoteUrl,
|
|
353
|
+
})
|
|
354
|
+
: null;
|
|
355
|
+
|
|
343
356
|
return {
|
|
344
357
|
currentRepo: resolveCurrentRepo(input),
|
|
345
358
|
source,
|
|
@@ -349,7 +362,15 @@ export function resolveQueueContract(input = {}) {
|
|
|
349
362
|
...resolvePrdLifecycleRoles(config, source),
|
|
350
363
|
},
|
|
351
364
|
buildQueue: {
|
|
352
|
-
argument: resolveBuildQueueArgument(config, tracker
|
|
365
|
+
argument: resolveBuildQueueArgument(config, tracker, {
|
|
366
|
+
gitRemoteUrl: input.gitRemoteUrl,
|
|
367
|
+
}),
|
|
368
|
+
...(tracker === "github"
|
|
369
|
+
? {
|
|
370
|
+
identityRepo: `${githubIdentity.owner}/${githubIdentity.repo}`,
|
|
371
|
+
queueRepo: `${githubQueue.owner}/${githubQueue.repo}`,
|
|
372
|
+
}
|
|
373
|
+
: {}),
|
|
353
374
|
...resolveBuildLifecycleRoles(config, tracker),
|
|
354
375
|
},
|
|
355
376
|
};
|
|
@@ -408,6 +429,54 @@ export function resolveGithubRepoRef(config = {}, gitRemoteUrl) {
|
|
|
408
429
|
return null;
|
|
409
430
|
}
|
|
410
431
|
|
|
432
|
+
/**
|
|
433
|
+
* Resolve the GitHub queue without changing the repository identity used
|
|
434
|
+
* for automation names and `repo:<name>` claim scoping. An explicit invocation
|
|
435
|
+
* target wins, followed by `github.queueRepo`, then the identity repo.
|
|
436
|
+
*
|
|
437
|
+
* `github.queueRepo` may be a short repo name (normalized to the identity
|
|
438
|
+
* owner) or an `owner/repo` reference. Cross-owner queues therefore remain
|
|
439
|
+
* explicit while the common same-organization umbrella layout stays concise.
|
|
440
|
+
*
|
|
441
|
+
* @param {Record<string, any>} config
|
|
442
|
+
* @param {{ readonly explicitQueue?: string, readonly gitRemoteUrl?: string }} [options]
|
|
443
|
+
* @returns {{ readonly owner: string, readonly repo: string }}
|
|
444
|
+
*/
|
|
445
|
+
export function resolveGithubQueueRepoRef(config = {}, options = {}) {
|
|
446
|
+
const identity = resolveGithubRepoRef(config, options.gitRemoteUrl);
|
|
447
|
+
if (!identity) {
|
|
448
|
+
throw new Error(
|
|
449
|
+
"Unable to resolve the GitHub repository identity: github.org/github.repo or a GitHub origin remote is required."
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
const configured = options.explicitQueue ?? config.github?.queueRepo;
|
|
454
|
+
if (configured === undefined || configured === null || configured === "") {
|
|
455
|
+
return identity;
|
|
456
|
+
}
|
|
457
|
+
if (typeof configured !== "string") {
|
|
458
|
+
throw new Error(
|
|
459
|
+
"Unable to resolve the GitHub queue: github.queueRepo must be a repo name or owner/repo."
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
const value = configured
|
|
464
|
+
.trim()
|
|
465
|
+
.replace(/^https:\/\/github\.com\//i, "")
|
|
466
|
+
.replace(/\.git$/i, "");
|
|
467
|
+
const parts = value.split("/").filter(Boolean);
|
|
468
|
+
if (parts.length === 1) {
|
|
469
|
+
return { owner: identity.owner, repo: parts[0] };
|
|
470
|
+
}
|
|
471
|
+
if (parts.length === 2) {
|
|
472
|
+
return { owner: parts[0], repo: parts[1] };
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
throw new Error(
|
|
476
|
+
"Unable to resolve the GitHub queue: github.queueRepo must be a repo name or owner/repo."
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
|
|
411
480
|
/**
|
|
412
481
|
* @param {string | undefined} gitRemoteUrl
|
|
413
482
|
* @returns {string | null}
|
|
@@ -58,23 +58,75 @@ const HIGHLIGHT_COPY = {
|
|
|
58
58
|
* readonly queueResolved?: boolean
|
|
59
59
|
* readonly queueArgument?: string
|
|
60
60
|
* readonly resolutionError?: string | null
|
|
61
|
+
* readonly currentRepo?: string | null
|
|
61
62
|
* }} input
|
|
62
63
|
*/
|
|
63
64
|
export function readGithubBuildQueueSnapshot(input = {}) {
|
|
64
65
|
const roles = input.roles ?? resolveBuildLifecycleRoles({}, "github").roles;
|
|
65
|
-
const
|
|
66
|
+
const issues = input.issues ?? [];
|
|
67
|
+
const normalizedItems = issues
|
|
68
|
+
.filter(
|
|
69
|
+
issue =>
|
|
70
|
+
classifyGithubIssueRepoScope(issue, input.currentRepo) === "current"
|
|
71
|
+
)
|
|
72
|
+
.map(issue => normalizeGithubBuildIssue(issue, roles))
|
|
73
|
+
.filter(Boolean);
|
|
74
|
+
const unscopedCandidates = issues
|
|
75
|
+
.filter(
|
|
76
|
+
issue =>
|
|
77
|
+
classifyGithubIssueRepoScope(issue, input.currentRepo) === "unscoped"
|
|
78
|
+
)
|
|
66
79
|
.map(issue => normalizeGithubBuildIssue(issue, roles))
|
|
67
80
|
.filter(Boolean);
|
|
68
81
|
|
|
69
|
-
return
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
82
|
+
return {
|
|
83
|
+
...createBuildQueueSnapshot({
|
|
84
|
+
tracker: "github",
|
|
85
|
+
items: normalizedItems,
|
|
86
|
+
roles,
|
|
87
|
+
namespaceAdopted: input.namespaceAdopted,
|
|
88
|
+
queueResolved: input.queueResolved,
|
|
89
|
+
queueArgument: input.queueArgument,
|
|
90
|
+
resolutionError: input.resolutionError,
|
|
91
|
+
}),
|
|
92
|
+
unscopedCount: unscopedCandidates.length,
|
|
93
|
+
unscopedCandidates,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Classify current-repo, unlabeled, and sibling-only candidates. Unlabeled work
|
|
99
|
+
* remains separately visible because build intake must determine and stamp its
|
|
100
|
+
* repo, but it must not inflate current-repo lifecycle counts. Containers
|
|
101
|
+
* carrying multiple repo labels are current when one label matches.
|
|
102
|
+
*
|
|
103
|
+
* @param {Record<string, any>} issue
|
|
104
|
+
* @param {string | null | undefined} currentRepo
|
|
105
|
+
* @returns {"current" | "unscoped" | "sibling"}
|
|
106
|
+
*/
|
|
107
|
+
function classifyGithubIssueRepoScope(issue, currentRepo) {
|
|
108
|
+
if (typeof currentRepo !== "string" || currentRepo.trim().length === 0) {
|
|
109
|
+
return "current";
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const repoLabels = (Array.isArray(issue?.labels) ? issue.labels : [])
|
|
113
|
+
.map(label =>
|
|
114
|
+
typeof label === "string"
|
|
115
|
+
? label
|
|
116
|
+
: typeof label?.name === "string"
|
|
117
|
+
? label.name
|
|
118
|
+
: ""
|
|
119
|
+
)
|
|
120
|
+
.map(label => label.trim().toLowerCase())
|
|
121
|
+
.filter(label => label.startsWith("repo:") && label.length > 5);
|
|
122
|
+
|
|
123
|
+
if (repoLabels.length === 0) {
|
|
124
|
+
return "unscoped";
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return repoLabels.includes(`repo:${currentRepo.trim().toLowerCase()}`)
|
|
128
|
+
? "current"
|
|
129
|
+
: "sibling";
|
|
78
130
|
}
|
|
79
131
|
|
|
80
132
|
/**
|