@codyswann/lisa 4.22.12 → 4.22.13
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/all/copy-overwrite/scripts/lib/gate-failure-diagnosis.mjs +4 -2
- package/all/copy-overwrite/scripts/lib/process-tree-runner.mjs +62 -11
- package/all/copy-overwrite/scripts/lisa-environment-prepare.mjs +10 -1
- package/all/copy-overwrite/scripts/lisa-floor-collisions.mjs +1 -0
- package/all/copy-overwrite/scripts/lisa-hooks/block-no-verify.sh +43 -2
- package/all/copy-overwrite/scripts/lisa-hooks/parity-safety-net.sh +19 -5
- package/all/copy-overwrite/scripts/lisa-reconcile-policy.mjs +13 -1
- package/all/copy-overwrite/scripts/lisa-schema-validate.mjs +2 -2
- package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.js +24 -0
- package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
- package/dist/core/nightly-e2e-guard-behavior-certificate.d.ts +5 -0
- package/dist/core/nightly-e2e-guard-behavior-certificate.d.ts.map +1 -1
- package/dist/core/nightly-e2e-guard-behavior-certificate.js +8 -2
- package/dist/core/nightly-e2e-guard-behavior-certificate.js.map +1 -1
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +33 -32
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/dist/opencode/plugin-templates/block-no-verify.sh +43 -2
- package/dist/opencode/plugin-templates/lisa-block-direct-issue-create.ts +4 -3
- package/dist/opencode/plugin-templates/lisa-block-no-verify.ts +11 -2
- package/dist/opencode/plugin-templates/parity-safety-net.sh +19 -5
- package/expo/create-only/.github/workflows/nightly-e2e-report.yml +1 -0
- package/package.json +3 -3
- 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-github-build-intake/SKILL.md +7 -8
- package/plugins/lisa/.codex-plugin/skills/lisa-github-prd-intake/SKILL.md +10 -11
- package/plugins/lisa/.codex-plugin/skills/lisa-github-sync/SKILL.md +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-github-write-prd/SKILL.md +14 -12
- package/plugins/lisa/.codex-plugin/skills/lisa-jira-build-intake/SKILL.md +7 -8
- package/plugins/lisa/.codex-plugin/skills/lisa-jira-journey/scripts/parse-plan.py +54 -12
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-build-intake/SKILL.md +9 -10
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-evidence/SKILL.md +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-sync/SKILL.md +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-repair-intake/SKILL.md +2 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +4 -3
- package/plugins/lisa/.codex-plugin/skills/lisa-tracker-sync/SKILL.md +2 -2
- package/plugins/lisa/hooks/block-no-verify.sh +43 -2
- package/plugins/lisa/hooks/parity-safety-net.sh +19 -5
- package/plugins/lisa/hooks/threshold-ratchet-families.mjs +10 -1
- package/plugins/lisa/rules/reference/config-resolution.md +0 -4
- package/plugins/lisa/rules/reference/leaf-only-lifecycle.md +1 -1
- package/plugins/lisa/scripts/resolve-lifecycle-role.mjs +15 -3
- package/plugins/lisa/skills/lisa-github-build-intake/SKILL.md +7 -8
- package/plugins/lisa/skills/lisa-github-prd-intake/SKILL.md +10 -11
- package/plugins/lisa/skills/lisa-github-sync/SKILL.md +1 -1
- package/plugins/lisa/skills/lisa-github-write-prd/SKILL.md +14 -12
- package/plugins/lisa/skills/lisa-jira-build-intake/SKILL.md +7 -8
- package/plugins/lisa/skills/lisa-jira-journey/scripts/parse-plan.py +54 -12
- package/plugins/lisa/skills/lisa-linear-build-intake/SKILL.md +9 -10
- package/plugins/lisa/skills/lisa-linear-evidence/SKILL.md +1 -1
- package/plugins/lisa/skills/lisa-linear-sync/SKILL.md +1 -1
- package/plugins/lisa/skills/lisa-repair-intake/SKILL.md +2 -1
- package/plugins/lisa/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +4 -3
- package/plugins/lisa/skills/lisa-tracker-sync/SKILL.md +2 -2
- package/plugins/lisa-agy/hooks/parity-safety-net.sh +19 -5
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/scripts/resolve-lifecycle-role.mjs +15 -3
- package/plugins/lisa-agy/skills/lisa-github-build-intake/SKILL.md +7 -8
- package/plugins/lisa-agy/skills/lisa-github-prd-intake/SKILL.md +10 -11
- package/plugins/lisa-agy/skills/lisa-github-sync/SKILL.md +1 -1
- package/plugins/lisa-agy/skills/lisa-github-write-prd/SKILL.md +14 -12
- package/plugins/lisa-agy/skills/lisa-jira-build-intake/SKILL.md +7 -8
- package/plugins/lisa-agy/skills/lisa-jira-journey/scripts/parse-plan.py +54 -12
- package/plugins/lisa-agy/skills/lisa-linear-build-intake/SKILL.md +9 -10
- package/plugins/lisa-agy/skills/lisa-linear-evidence/SKILL.md +1 -1
- package/plugins/lisa-agy/skills/lisa-linear-sync/SKILL.md +1 -1
- package/plugins/lisa-agy/skills/lisa-repair-intake/SKILL.md +2 -1
- package/plugins/lisa-agy/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +4 -3
- package/plugins/lisa-agy/skills/lisa-tracker-sync/SKILL.md +2 -2
- 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/hooks/block-no-verify.sh +43 -2
- package/plugins/lisa-copilot/hooks/parity-safety-net.sh +19 -5
- package/plugins/lisa-copilot/hooks/threshold-ratchet-families.mjs +10 -1
- package/plugins/lisa-copilot/rules/reference/config-resolution.md +0 -4
- package/plugins/lisa-copilot/rules/reference/leaf-only-lifecycle.md +1 -1
- package/plugins/lisa-copilot/scripts/resolve-lifecycle-role.mjs +15 -3
- package/plugins/lisa-copilot/skills/lisa-github-build-intake/SKILL.md +7 -8
- package/plugins/lisa-copilot/skills/lisa-github-prd-intake/SKILL.md +10 -11
- package/plugins/lisa-copilot/skills/lisa-github-sync/SKILL.md +1 -1
- package/plugins/lisa-copilot/skills/lisa-github-write-prd/SKILL.md +14 -12
- package/plugins/lisa-copilot/skills/lisa-jira-build-intake/SKILL.md +7 -8
- package/plugins/lisa-copilot/skills/lisa-jira-journey/scripts/parse-plan.py +54 -12
- package/plugins/lisa-copilot/skills/lisa-linear-build-intake/SKILL.md +9 -10
- package/plugins/lisa-copilot/skills/lisa-linear-evidence/SKILL.md +1 -1
- package/plugins/lisa-copilot/skills/lisa-linear-sync/SKILL.md +1 -1
- package/plugins/lisa-copilot/skills/lisa-repair-intake/SKILL.md +2 -1
- package/plugins/lisa-copilot/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +4 -3
- package/plugins/lisa-copilot/skills/lisa-tracker-sync/SKILL.md +2 -2
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/hooks/block-no-verify.sh +43 -2
- package/plugins/lisa-cursor/hooks/parity-safety-net.sh +19 -5
- package/plugins/lisa-cursor/hooks/threshold-ratchet-families.mjs +10 -1
- package/plugins/lisa-cursor/rules/config-resolution-reference.mdc +0 -4
- package/plugins/lisa-cursor/rules/leaf-only-lifecycle-reference.mdc +1 -1
- package/plugins/lisa-cursor/scripts/resolve-lifecycle-role.mjs +15 -3
- package/plugins/lisa-cursor/skills/lisa-github-build-intake/SKILL.md +7 -8
- package/plugins/lisa-cursor/skills/lisa-github-prd-intake/SKILL.md +10 -11
- package/plugins/lisa-cursor/skills/lisa-github-sync/SKILL.md +1 -1
- package/plugins/lisa-cursor/skills/lisa-github-write-prd/SKILL.md +14 -12
- package/plugins/lisa-cursor/skills/lisa-jira-build-intake/SKILL.md +7 -8
- package/plugins/lisa-cursor/skills/lisa-jira-journey/scripts/parse-plan.py +54 -12
- package/plugins/lisa-cursor/skills/lisa-linear-build-intake/SKILL.md +9 -10
- package/plugins/lisa-cursor/skills/lisa-linear-evidence/SKILL.md +1 -1
- package/plugins/lisa-cursor/skills/lisa-linear-sync/SKILL.md +1 -1
- package/plugins/lisa-cursor/skills/lisa-repair-intake/SKILL.md +2 -1
- package/plugins/lisa-cursor/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +4 -3
- package/plugins/lisa-cursor/skills/lisa-tracker-sync/SKILL.md +2 -2
- 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/hooks/block-no-verify.sh +43 -2
- package/plugins/src/base/hooks/parity-safety-net.sh +19 -5
- package/plugins/src/base/hooks/threshold-ratchet-families.mjs +10 -1
- package/plugins/src/base/rules/reference/config-resolution.md +0 -4
- package/plugins/src/base/rules/reference/leaf-only-lifecycle.md +1 -1
- package/plugins/src/base/scripts/resolve-lifecycle-role.mjs +15 -3
- package/plugins/src/base/skills/lisa-github-build-intake/SKILL.md +7 -8
- package/plugins/src/base/skills/lisa-github-prd-intake/SKILL.md +10 -11
- package/plugins/src/base/skills/lisa-github-sync/SKILL.md +1 -1
- package/plugins/src/base/skills/lisa-github-write-prd/SKILL.md +14 -12
- package/plugins/src/base/skills/lisa-jira-build-intake/SKILL.md +7 -8
- package/plugins/src/base/skills/lisa-jira-journey/scripts/parse-plan.py +54 -12
- package/plugins/src/base/skills/lisa-linear-build-intake/SKILL.md +9 -10
- package/plugins/src/base/skills/lisa-linear-evidence/SKILL.md +1 -1
- package/plugins/src/base/skills/lisa-linear-sync/SKILL.md +1 -1
- package/plugins/src/base/skills/lisa-repair-intake/SKILL.md +2 -1
- package/plugins/src/base/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +4 -3
- package/plugins/src/base/skills/lisa-tracker-sync/SKILL.md +2 -2
- package/rails/copy-overwrite/scripts/threshold-ratchet-families.mjs +10 -1
- package/typescript/copy-overwrite/scripts/check-nightly-e2e-health.mjs +10 -13
- package/typescript/copy-overwrite/scripts/check-skipped-required-checks.mjs +34 -3
- package/typescript/copy-overwrite/scripts/lisa-mutation.mjs +17 -1
- package/typescript/copy-overwrite/scripts/threshold-ratchet-families.mjs +10 -1
|
@@ -94,6 +94,9 @@ export const VENDOR_ROOTS = Object.freeze({
|
|
|
94
94
|
github: "github.labels.build",
|
|
95
95
|
});
|
|
96
96
|
|
|
97
|
+
/** GitHub's PRD lifecycle is a separate required role map from build work. */
|
|
98
|
+
const GITHUB_PRD_PREFIX = "prd.";
|
|
99
|
+
|
|
97
100
|
/** Resolution outcomes, reported so a caller never has to guess what happened. */
|
|
98
101
|
export const OUTCOMES = Object.freeze({
|
|
99
102
|
CONFIGURED: "configured",
|
|
@@ -170,7 +173,12 @@ export const resolveRole = ({
|
|
|
170
173
|
global: globalConfig,
|
|
171
174
|
fallback,
|
|
172
175
|
}) => {
|
|
173
|
-
|
|
176
|
+
let root = VENDOR_ROOTS[vendor];
|
|
177
|
+
let configuredRole = role;
|
|
178
|
+
if (vendor === "github" && role.startsWith(GITHUB_PRD_PREFIX)) {
|
|
179
|
+
root = "github.labels.prd";
|
|
180
|
+
configuredRole = role.slice(GITHUB_PRD_PREFIX.length);
|
|
181
|
+
}
|
|
174
182
|
if (!root) {
|
|
175
183
|
return {
|
|
176
184
|
value: "",
|
|
@@ -182,7 +190,9 @@ export const resolveRole = ({
|
|
|
182
190
|
|
|
183
191
|
// `done` is env-keyed on every vendor; an env selects one rung of the map.
|
|
184
192
|
const path =
|
|
185
|
-
env &&
|
|
193
|
+
env && configuredRole === "done"
|
|
194
|
+
? `${root}.done.${env}`
|
|
195
|
+
: `${root}.${configuredRole}`;
|
|
186
196
|
|
|
187
197
|
for (const [label, source] of [
|
|
188
198
|
["local", local],
|
|
@@ -199,7 +209,9 @@ export const resolveRole = ({
|
|
|
199
209
|
}
|
|
200
210
|
}
|
|
201
211
|
|
|
202
|
-
const optional =
|
|
212
|
+
const optional =
|
|
213
|
+
!role.startsWith(GITHUB_PRD_PREFIX) &&
|
|
214
|
+
OPTIONAL_ROLES.includes(configuredRole);
|
|
203
215
|
|
|
204
216
|
// R2 — a fallback may inform a read, never supply a write target.
|
|
205
217
|
if (fallback && intent === "write") {
|
|
@@ -36,18 +36,17 @@ selection-only: never assign or reassign issues as part of build intake.
|
|
|
36
36
|
Build-queue label names are read from `.lisa.config.json` `github.labels.build.*`, falling back to defaults documented in the `config-resolution` rule. Bash pattern:
|
|
37
37
|
|
|
38
38
|
```bash
|
|
39
|
-
# Read role with default fallback. Local overrides global per-key.
|
|
40
39
|
read_role() {
|
|
41
40
|
# Single resolver — see config-resolution "The single resolver".
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
local value
|
|
42
|
+
value=$(node "${CLAUDE_PLUGIN_ROOT:-${PLUGIN_ROOT:-plugins/lisa}}/scripts/resolve-lifecycle-role.mjs" \
|
|
43
|
+
--role "$1" --vendor github --intent "${2:-read}") || return $?
|
|
44
|
+
[ -n "$value" ] || { echo "Error: required GitHub role '$1' resolved empty." >&2; return 2; }
|
|
45
|
+
printf '%s\n' "$value"
|
|
47
46
|
}
|
|
48
47
|
|
|
49
|
-
READY=$(read_role ready
|
|
50
|
-
CLAIMED=$(read_role claimed
|
|
48
|
+
READY=$(read_role ready read) || exit $?
|
|
49
|
+
CLAIMED=$(read_role claimed write) || exit $?
|
|
51
50
|
|
|
52
51
|
read_intake_assignee() {
|
|
53
52
|
local cli_value local_v
|
|
@@ -19,21 +19,20 @@ Run one intake cycle against that repo. The first eligible issue with the `ready
|
|
|
19
19
|
PRD label names are read from `.lisa.config.json` `github.labels.prd.*`, falling back to defaults documented in the `config-resolution` rule. Bash pattern:
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
# Read role with default fallback. Local overrides global per-key.
|
|
23
22
|
read_role() {
|
|
24
23
|
# Single resolver — see config-resolution "The single resolver".
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
local value
|
|
25
|
+
value=$(node "${CLAUDE_PLUGIN_ROOT:-${PLUGIN_ROOT:-plugins/lisa}}/scripts/resolve-lifecycle-role.mjs" \
|
|
26
|
+
--role "$1" --vendor github --intent "${2:-write}") || return $?
|
|
27
|
+
[ -n "$value" ] || { echo "Error: required GitHub PRD role '$1' resolved empty." >&2; return 2; }
|
|
28
|
+
printf '%s\n' "$value"
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
READY=$(read_role ready
|
|
33
|
-
IN_REVIEW=$(read_role in_review
|
|
34
|
-
BLOCKED=$(read_role blocked
|
|
35
|
-
TICKETED=$(read_role ticketed
|
|
36
|
-
SHIPPED=$(read_role shipped
|
|
31
|
+
READY=$(read_role prd.ready write) || exit $?
|
|
32
|
+
IN_REVIEW=$(read_role prd.in_review write) || exit $?
|
|
33
|
+
BLOCKED=$(read_role prd.blocked write) || exit $?
|
|
34
|
+
TICKETED=$(read_role prd.ticketed write) || exit $?
|
|
35
|
+
SHIPPED=$(read_role prd.shipped write) || exit $?
|
|
37
36
|
```
|
|
38
37
|
|
|
39
38
|
In prose below, the role names refer to the resolved labels: e.g. "the `ready` label" means whatever `github.labels.prd.ready` resolves to (default: `prd-ready`).
|
|
@@ -129,7 +129,7 @@ classifier absent.
|
|
|
129
129
|
|
|
130
130
|
**Single-environment collapse (this repo).** `.lisa.config.json` `deploy.branches` declares only `production: main`, so the env-keyed `done` resolves to the single label `status:done` — there is no `status:on-dev` / `status:on-stg` and **no dev → staging → prod promotion chain**. Resolve the env rungs via the env-keyed `done` logic in `config-resolution`, but in the single-environment case the only rung is production and it collapses to the one `status:done` value; the rollup never attempts to resolve a dev or staging `done`. Projects that DO have multiple environments keep the env-keyed map and roll the parent up to whichever `done` (including intermediate `status:on-dev`/`status:on-stg`) its leaves have collectively reached.
|
|
131
131
|
|
|
132
|
-
**Apply the derived label** (only when it differs from the parent's current `status:*`): remove the parent's existing `status:*` label and add the derived one, keeping exactly one `status:*` label so the build-queue invariant holds. Post an idempotent `[claude-sync] rollup` comment naming the derived state and the child tally (e.g. `3/4 leaves terminal, 1 blocked → status:blocked`); when the derived state is `status:blocked` the comment also carries the classifier's per-class section, so the blocking child and its actor are one read rather than a descent.
|
|
132
|
+
**Apply the derived label** (only when it differs from the parent's current `status:*`): remove the parent's existing `status:*` label and add the derived one, keeping exactly one `status:*` label so the build-queue invariant holds. Re-read the labels immediately after the edit and require exactly one `status:*`; if the count differs, surface an error and stop without trying to normalize the ambiguous set automatically. Post an idempotent `[claude-sync] rollup` comment naming the derived state and the child tally (e.g. `3/4 leaves terminal, 1 blocked → status:blocked`); when the derived state is `status:blocked` the comment also carries the classifier's per-class section, so the blocking child and its actor are one read rather than a descent. Use the classifier's `change.summary` as the dedupe key and skip the comment when that summary is unchanged.
|
|
133
133
|
|
|
134
134
|
```bash
|
|
135
135
|
gh issue edit <parent-number> --repo <org>/<repo> \
|
|
@@ -22,21 +22,23 @@ REPO=$(jq -r '.github.repo // empty' .lisa.config.local.json 2>/dev/null); REPO=
|
|
|
22
22
|
|
|
23
23
|
read_role() {
|
|
24
24
|
# Single resolver — see config-resolution "The single resolver".
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
|
|
28
|
-
node "${CLAUDE_PLUGIN_ROOT}/scripts/resolve-lifecycle-role.mjs" \
|
|
29
|
-
--role "$1" --vendor github --intent "${
|
|
25
|
+
# Every PRD role used here is required. Resolver errors remain visible, and
|
|
26
|
+
# an empty result is refused rather than passed to `gh --label`.
|
|
27
|
+
local value
|
|
28
|
+
value=$(node "${CLAUDE_PLUGIN_ROOT:-${PLUGIN_ROOT:-plugins/lisa}}/scripts/resolve-lifecycle-role.mjs" \
|
|
29
|
+
--role "$1" --vendor github --intent "${2:-write}") || return $?
|
|
30
|
+
[ -n "$value" ] || { echo "Error: required GitHub role '$1' resolved empty." >&2; return 2; }
|
|
31
|
+
printf '%s\n' "$value"
|
|
30
32
|
}
|
|
31
33
|
# Resolve the FULL PRD lifecycle vocabulary from config (never hard-code names) — needed so the
|
|
32
34
|
# "exactly one role" reconcile and the past-ready check work for projects that renamed any label.
|
|
33
|
-
PRD_DRAFT=$(read_role
|
|
34
|
-
PRD_READY=$(read_role
|
|
35
|
-
PRD_IN_REVIEW=$(read_role
|
|
36
|
-
PRD_BLOCKED=$(read_role
|
|
37
|
-
PRD_TICKETED=$(read_role
|
|
38
|
-
PRD_SHIPPED=$(read_role
|
|
39
|
-
PRD_VERIFIED=$(read_role
|
|
35
|
+
PRD_DRAFT=$(read_role prd.draft write) || exit $?
|
|
36
|
+
PRD_READY=$(read_role prd.ready write) || exit $?
|
|
37
|
+
PRD_IN_REVIEW=$(read_role prd.in_review write) || exit $?
|
|
38
|
+
PRD_BLOCKED=$(read_role prd.blocked write) || exit $?
|
|
39
|
+
PRD_TICKETED=$(read_role prd.ticketed write) || exit $?
|
|
40
|
+
PRD_SHIPPED=$(read_role prd.shipped write) || exit $?
|
|
41
|
+
PRD_VERIFIED=$(read_role prd.verified write) || exit $?
|
|
40
42
|
# All lifecycle labels (for one-of reconcile) and the "progressed past ready" set (never down-rank):
|
|
41
43
|
ALL_PRD_LABELS=("$PRD_DRAFT" "$PRD_READY" "$PRD_IN_REVIEW" "$PRD_BLOCKED" "$PRD_TICKETED" "$PRD_SHIPPED" "$PRD_VERIFIED")
|
|
42
44
|
PROGRESSED=("$PRD_IN_REVIEW" "$PRD_BLOCKED" "$PRD_TICKETED" "$PRD_SHIPPED" "$PRD_VERIFIED")
|
|
@@ -20,18 +20,17 @@ Run one build-intake cycle. The first eligible ready ticket is claimed, built vi
|
|
|
20
20
|
Status names are read from `.lisa.config.json` `jira.workflow.*`, falling back to defaults documented in the `config-resolution` rule. Bash pattern:
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
|
-
# Read role with default fallback. Local overrides global per-key.
|
|
24
23
|
read_role() {
|
|
25
24
|
# Single resolver — see config-resolution "The single resolver".
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
local value
|
|
26
|
+
value=$(node "${CLAUDE_PLUGIN_ROOT:-${PLUGIN_ROOT:-plugins/lisa}}/scripts/resolve-lifecycle-role.mjs" \
|
|
27
|
+
--role "$1" --vendor jira --intent "${2:-read}") || return $?
|
|
28
|
+
[ -n "$value" ] || { echo "Error: required JIRA role '$1' resolved empty." >&2; return 2; }
|
|
29
|
+
printf '%s\n' "$value"
|
|
31
30
|
}
|
|
32
31
|
|
|
33
|
-
READY=$(read_role ready
|
|
34
|
-
CLAIMED=$(read_role claimed
|
|
32
|
+
READY=$(read_role ready read) || exit $?
|
|
33
|
+
CLAIMED=$(read_role claimed write) || exit $?
|
|
35
34
|
```
|
|
36
35
|
|
|
37
36
|
For env-keyed `done`, resolve the env first, then look up `done[<env>]`:
|
|
@@ -33,6 +33,7 @@ import sys
|
|
|
33
33
|
import urllib.request
|
|
34
34
|
from base64 import b64encode
|
|
35
35
|
from pathlib import Path
|
|
36
|
+
from urllib.parse import urlsplit
|
|
36
37
|
|
|
37
38
|
|
|
38
39
|
# Intentionally matches the exact local-claim prefixes only. EVIDENCE-REF is a
|
|
@@ -66,13 +67,50 @@ def jira_config_candidates():
|
|
|
66
67
|
return candidates
|
|
67
68
|
|
|
68
69
|
|
|
70
|
+
def read_jira_config(config_path):
|
|
71
|
+
"""Read the server and login fields from one jira-cli config."""
|
|
72
|
+
server = ""
|
|
73
|
+
login = ""
|
|
74
|
+
with open(config_path) as config:
|
|
75
|
+
for line in config:
|
|
76
|
+
if line.startswith("server:"):
|
|
77
|
+
server = line.split(":", 1)[1].strip()
|
|
78
|
+
elif line.startswith("login:"):
|
|
79
|
+
login = line.split(":", 1)[1].strip()
|
|
80
|
+
return server, login
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def server_origin(server):
|
|
84
|
+
"""Return the normalized HTTPS origin used as the credential trust key."""
|
|
85
|
+
try:
|
|
86
|
+
parsed = urlsplit(server)
|
|
87
|
+
port = parsed.port
|
|
88
|
+
except ValueError:
|
|
89
|
+
return ""
|
|
90
|
+
if parsed.scheme.lower() != "https" or not parsed.hostname:
|
|
91
|
+
return ""
|
|
92
|
+
authority = parsed.hostname.lower()
|
|
93
|
+
if port and port != 443:
|
|
94
|
+
authority = f"{authority}:{port}"
|
|
95
|
+
return f"https://{authority}"
|
|
96
|
+
|
|
97
|
+
|
|
69
98
|
def resolve_jira_config_path():
|
|
70
|
-
"""Resolve
|
|
99
|
+
"""Resolve a project config only when its host matches a user trust root."""
|
|
71
100
|
candidates = jira_config_candidates()
|
|
72
|
-
|
|
73
|
-
|
|
101
|
+
home_config = candidates[-1]
|
|
102
|
+
trusted_server = os.environ.get("JIRA_SERVER", "").strip()
|
|
103
|
+
if not trusted_server and home_config.exists():
|
|
104
|
+
trusted_server, _ = read_jira_config(home_config)
|
|
105
|
+
trusted_origin = server_origin(trusted_server)
|
|
106
|
+
|
|
107
|
+
for candidate in candidates[:-1]:
|
|
108
|
+
if not candidate.exists():
|
|
109
|
+
continue
|
|
110
|
+
candidate_server, _ = read_jira_config(candidate)
|
|
111
|
+
if trusted_origin and server_origin(candidate_server) == trusted_origin:
|
|
74
112
|
return candidate
|
|
75
|
-
return
|
|
113
|
+
return home_config
|
|
76
114
|
|
|
77
115
|
|
|
78
116
|
def get_jira_config():
|
|
@@ -82,14 +120,18 @@ def get_jira_config():
|
|
|
82
120
|
print(f"ERROR: jira-cli config not found at {config_path}", file=sys.stderr)
|
|
83
121
|
sys.exit(1)
|
|
84
122
|
|
|
85
|
-
server =
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
123
|
+
server, login = read_jira_config(config_path)
|
|
124
|
+
|
|
125
|
+
trusted_server = os.environ.get("JIRA_SERVER", "").strip()
|
|
126
|
+
trusted_origin = server_origin(trusted_server)
|
|
127
|
+
if trusted_origin:
|
|
128
|
+
if server_origin(server) != trusted_origin:
|
|
129
|
+
print("ERROR: jira-cli config server does not match trusted JIRA_SERVER", file=sys.stderr)
|
|
130
|
+
sys.exit(1)
|
|
131
|
+
server = trusted_server.rstrip("/")
|
|
132
|
+
if not server_origin(server):
|
|
133
|
+
print("ERROR: JIRA server must be an HTTPS URL from a trusted config", file=sys.stderr)
|
|
134
|
+
sys.exit(1)
|
|
93
135
|
|
|
94
136
|
token = os.environ.get("JIRA_API_TOKEN", "")
|
|
95
137
|
if not token:
|
|
@@ -21,20 +21,19 @@ This skill is the destination of the `lisa-tracker-build-intake` shim when `trac
|
|
|
21
21
|
Build-queue **workflow state** names are read from `.lisa.config.json` `linear.workflow.*`, falling back to defaults documented in the `config-resolution` rule. Bash pattern:
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
|
-
# Read role with default fallback. Local overrides global per-key.
|
|
25
24
|
read_role() {
|
|
26
25
|
# Single resolver — see config-resolution "The single resolver".
|
|
27
26
|
# Exit 0 + empty output means an OPTIONAL role is unset: skip that transition,
|
|
28
|
-
# never substitute
|
|
29
|
-
#
|
|
30
|
-
node "${CLAUDE_PLUGIN_ROOT}/scripts/resolve-lifecycle-role.mjs" \
|
|
31
|
-
--role "$1" --vendor linear --intent "${
|
|
27
|
+
# never substitute a default. Any non-zero status is a resolver failure and
|
|
28
|
+
# remains visible to the caller.
|
|
29
|
+
node "${CLAUDE_PLUGIN_ROOT:-${PLUGIN_ROOT:-plugins/lisa}}/scripts/resolve-lifecycle-role.mjs" \
|
|
30
|
+
--role "$1" --vendor linear --intent "${2:-read}"
|
|
32
31
|
}
|
|
33
32
|
|
|
34
|
-
READY=$(read_role ready
|
|
35
|
-
CLAIMED=$(read_role claimed
|
|
36
|
-
REVIEW=$(read_role review
|
|
37
|
-
BLOCKED=$(read_role blocked
|
|
33
|
+
READY=$(read_role ready read) || exit $?
|
|
34
|
+
CLAIMED=$(read_role claimed write) || exit $?
|
|
35
|
+
REVIEW=$(read_role review write) || exit $?
|
|
36
|
+
BLOCKED=$(read_role blocked read) || exit $?
|
|
38
37
|
```
|
|
39
38
|
|
|
40
39
|
For env-keyed `done`, resolve the env first, then look up `done[<env>]`:
|
|
@@ -69,7 +68,7 @@ else
|
|
|
69
68
|
fi
|
|
70
69
|
```
|
|
71
70
|
|
|
72
|
-
In prose below, the role names refer to the
|
|
71
|
+
In prose below, the role names refer to the configured **states**: e.g. "the `ready` state" means whatever `linear.workflow.ready` resolves to. Required roles must be configured; optional roles carry no default.
|
|
73
72
|
|
|
74
73
|
## Why native states, not labels
|
|
75
74
|
|
|
@@ -109,6 +109,6 @@ Return:
|
|
|
109
109
|
## Rules
|
|
110
110
|
|
|
111
111
|
- Never modify the Issue description as part of evidence posting — comments only. Description edits go through `lisa-linear-write-issue`.
|
|
112
|
-
- Never skip the
|
|
112
|
+
- Never skip the transition when `review` is configured. An empty `$REVIEW` is the one sanctioned skip (Phase 5): post the evidence comment, leave the Issue in `$CLAIMED`, and report the skip. Whenever `$REVIEW` is non-empty, the configured native state transition is mandatory.
|
|
113
113
|
- If `lisa-linear-access operation: save-comment` fails, retry once. If it fails again, surface the error — don't pretend the comment was posted.
|
|
114
114
|
- Do not delete prior comments. The history is the audit trail.
|
|
@@ -152,7 +152,7 @@ When the caller passes `--rollup`, this skill **derives a parent/container's wor
|
|
|
152
152
|
|
|
153
153
|
## Rules
|
|
154
154
|
|
|
155
|
-
- Never transition a leaf Issue's workflow `state` from this skill at
|
|
155
|
+
- Never transition a leaf Issue's workflow `state` from this skill except for the narrowly defined Phase 4b backstop that reopens a leaf auto-closed at an intermediate environment. `--rollup` remains the only other write path (parent derivation, per the `leaf-only-lifecycle` rule); every normal milestone SUGGESTS a transition in its comment and nothing more. The state is the lifecycle lane, so an unscoped write here would move the item in the build queue.
|
|
156
156
|
- Never resolve a role by searching the team's states. Only a name the project configured may be written; a `type`- or position-derived match may inform a read and must never supply a write target (`config-resolution`, R2).
|
|
157
157
|
- Rollup derives a *parent's* workflow state from its children and never rolls a parent into the human-owned ready lane (never `$READY`). It cites the `leaf-only-lifecycle` rule by slug rather than restating the state machine.
|
|
158
158
|
- Never post empty or minimal comments — if a milestone has no meaningful content, skip the post.
|
|
@@ -728,7 +728,8 @@ node "${CLAUDE_PLUGIN_ROOT}/scripts/rollup-blocker-classification.mjs" \
|
|
|
728
728
|
report already asks a person to decide.
|
|
729
729
|
|
|
730
730
|
3. **If the derived state differs from the parent's current state, apply it** via the vendor's
|
|
731
|
-
lifecycle write
|
|
731
|
+
lifecycle write: a JIRA transition; a GitHub label swap keeping exactly one `status:*`; or a
|
|
732
|
+
Linear `save-issue` update that writes the resolved workflow `stateId`, never a lifecycle label.
|
|
732
733
|
removing any conflicting stale build lifecycle role — **including a stale `ready`** the parent
|
|
733
734
|
should never carry. Post an idempotent `[lisa-repair-intake]` rollup note naming the derived
|
|
734
735
|
state and the child tally (honor the backoff window + fingerprint). Include that exact rendered
|
|
@@ -131,6 +131,7 @@ export function probe(name, exec = boundedChildOutput) {
|
|
|
131
131
|
return { present: true, version: extractVersion(out) };
|
|
132
132
|
} catch (err) {
|
|
133
133
|
if (err.code === "ENOENT") return { present: false, version: null };
|
|
134
|
+
if (err.code === "ETIMEDOUT") throw err;
|
|
134
135
|
const output = `${err.stdout ?? ""}${err.stderr ?? ""}`;
|
|
135
136
|
return { present: true, version: extractVersion(output) };
|
|
136
137
|
}
|
|
@@ -808,9 +809,9 @@ export function installUserSessionHook(repoRoot, options = {}) {
|
|
|
808
809
|
const dir = join(home, ".claude");
|
|
809
810
|
const settingsPath = join(dir, "settings.json");
|
|
810
811
|
// Settings stores shell source, so the absolute path still needs quoting.
|
|
811
|
-
//
|
|
812
|
-
//
|
|
813
|
-
const command = `bash ${
|
|
812
|
+
// Single quotes suppress parameter expansion and command substitution. An
|
|
813
|
+
// embedded quote closes, escapes, and reopens the quoted shell word.
|
|
814
|
+
const command = `bash '${script.replaceAll("'", `'\\''`)}'`;
|
|
814
815
|
|
|
815
816
|
let settings = {};
|
|
816
817
|
if (exists(settingsPath)) {
|
|
@@ -37,11 +37,11 @@ Two consequences the vendor arms must not restate differently:
|
|
|
37
37
|
Resolve roles through the shared resolver rather than an inlined helper:
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
|
-
node "${CLAUDE_PLUGIN_ROOT}/scripts/resolve-lifecycle-role.mjs" \
|
|
40
|
+
node "${CLAUDE_PLUGIN_ROOT:-${PLUGIN_ROOT:-plugins/lisa}}/scripts/resolve-lifecycle-role.mjs" \
|
|
41
41
|
--role <role> --vendor <jira|linear|github> --intent <read|write> [--env <env>]
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
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.
|
|
44
|
+
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.
|
|
45
45
|
|
|
46
46
|
If `$ARGUMENTS` is empty, all vendor skills auto-detect a ticket reference from the active plan file (most recently modified `.md` in `plans/`).
|
|
47
47
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "4.22.
|
|
3
|
+
"version": "4.22.13",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "4.22.
|
|
3
|
+
"version": "4.22.13",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, across Claude and Codex.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "4.22.
|
|
3
|
+
"version": "4.22.13",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "4.22.
|
|
3
|
+
"version": "4.22.13",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "4.22.
|
|
3
|
+
"version": "4.22.13",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|