@codyswann/lisa 4.55.2 → 4.55.4
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/check-orphaned-branches.mjs +49 -13
- package/all/copy-overwrite/scripts/lisa-enforcement-fallback.sh +9 -1
- package/all/copy-overwrite/scripts/lisa-hooks/block-blind-automerge.sh +10 -5
- package/all/copy-overwrite/scripts/lisa-hooks/block-direct-issue-create.sh +4 -0
- package/all/copy-overwrite/scripts/lisa-hooks/block-managed-file-edits.sh +73 -2
- package/all/copy-overwrite/scripts/lisa-hooks/guard-dedupe.bash +63 -29
- package/all/copy-overwrite/scripts/lisa-hooks/parity-safety-net.sh +2 -1
- package/all/copy-overwrite/scripts/lisa-hooks/worktree-binding-guard.sh +2 -1
- package/all/copy-overwrite/scripts/lisa-run-gates.mjs +7 -2
- package/all/copy-overwrite/scripts/lisa-work-item.mjs +50 -14
- package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.js +36 -0
- package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
- package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +92 -80
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/dist/opencode/plugin-templates/block-managed-file-edits.sh +76 -2
- package/dist/opencode/plugin-templates/block-no-verify.sh +3 -0
- package/dist/opencode/plugin-templates/guard-dedupe.bash +66 -29
- package/dist/opencode/plugin-templates/parity-safety-net-heredoc.py +3 -0
- package/dist/opencode/plugin-templates/parity-safety-net.sh +5 -1
- package/dist/opencode/support-file-resolver.d.ts.map +1 -1
- package/dist/opencode/support-file-resolver.js +3 -1
- package/dist/opencode/support-file-resolver.js.map +1 -1
- package/expo/copy-overwrite/plugins/withAndroidSplashNoClientExit.js +23 -21
- package/expo/create-only/.github/required-checks.json +1 -1
- package/nestjs/create-only/.github/required-checks.json +1 -1
- package/package.json +4 -4
- 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 +38 -15
- package/plugins/lisa/.codex-plugin/skills/lisa-github-write-issue/SKILL.md +15 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-jira-build-intake/SKILL.md +37 -13
- package/plugins/lisa/.codex-plugin/skills/lisa-jira-write-ticket/SKILL.md +15 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-access/SKILL.md +56 -7
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-build-intake/SKILL.md +36 -11
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-prd-intake/SKILL.md +12 -2
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-validate-issue/SKILL.md +1 -18
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-verify/SKILL.md +0 -17
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-write-issue/SKILL.md +18 -35
- package/plugins/lisa/.codex-plugin/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
- package/plugins/lisa/.codex-plugin/skills/lisa-repair-intake/SKILL.md +66 -12
- package/plugins/lisa/.codex-plugin/skills/lisa-rework-triage/SKILL.md +2 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/providers.mjs +2 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-linear/SKILL.md +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-env/scripts/preflight-tools.mjs +7 -2
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +11 -4
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-env/scripts/toolchain.mjs +17 -5
- package/plugins/lisa/.codex-plugin/skills/lisa-track/SKILL.md +32 -4
- package/plugins/lisa/.codex-plugin/skills/lisa-tracker-build-intake/SKILL.md +15 -1
- package/plugins/lisa/hooks/block-blind-automerge.sh +13 -5
- package/plugins/lisa/hooks/block-direct-issue-create.sh +7 -0
- package/plugins/lisa/hooks/block-instruction-file-edits.sh +3 -0
- package/plugins/lisa/hooks/block-managed-file-edits.sh +76 -2
- package/plugins/lisa/hooks/block-no-verify.sh +3 -0
- package/plugins/lisa/hooks/block-shell-json-parsing.sh +3 -0
- package/plugins/lisa/hooks/guard-dedupe.bash +66 -29
- package/plugins/lisa/hooks/parity-safety-net-heredoc.py +3 -0
- package/plugins/lisa/hooks/parity-safety-net.sh +5 -1
- package/plugins/lisa/hooks/worktree-binding-guard.mjs +3 -0
- package/plugins/lisa/hooks/worktree-binding-guard.sh +5 -1
- package/plugins/lisa/rules/eager/00-rule-index.md +1 -0
- package/plugins/lisa/rules/eager/base-rules.md +3 -1
- package/plugins/lisa/rules/eager/withdrawn-rulings.md +14 -3
- package/plugins/lisa/rules/reference/automation-runbook-contract.md +1 -1
- package/plugins/lisa/rules/reference/bdd-e2e-coverage.md +1 -1
- package/plugins/lisa/rules/reference/blocker-containment.md +3 -3
- package/plugins/lisa/rules/reference/claim-archaeology.md +1 -1
- package/plugins/lisa/rules/reference/claim-evidence-mapping.md +1 -1
- package/plugins/lisa/rules/reference/claim-time-guards.md +1 -1
- package/plugins/lisa/rules/reference/control-reachability.md +1 -1
- package/plugins/lisa/rules/reference/convergent-review.md +1 -1
- package/plugins/lisa/rules/reference/credential-substrate-precedence.md +1 -1
- package/plugins/lisa/rules/reference/dependency-decision-records.md +1 -1
- package/plugins/lisa/rules/reference/dependency-internalization-kit.md +1 -1
- package/plugins/lisa/rules/reference/dependency-trust-classes.md +1 -1
- package/plugins/lisa/rules/reference/deployed-state-readback.md +1 -1
- package/plugins/lisa/rules/reference/derived-branch-plan.md +1 -1
- package/plugins/lisa/rules/reference/design-source-of-truth.md +1 -1
- package/plugins/lisa/rules/reference/design-value-binding.md +1 -1
- package/plugins/lisa/rules/reference/documentation-source-paths.md +1 -1
- package/plugins/lisa/rules/reference/leaf-only-lifecycle.md +1 -1
- package/plugins/lisa/rules/reference/observability-audit.md +1 -1
- package/plugins/lisa/rules/reference/prd-definition-of-ready.md +1 -1
- package/plugins/lisa/rules/reference/prd-lifecycle-rollup.md +1 -1
- package/plugins/lisa/rules/reference/pre-flight-autofill.md +1 -1
- package/plugins/lisa/rules/reference/promotion-contract.md +1 -1
- package/plugins/lisa/rules/reference/readiness-rubric.md +1 -1
- package/plugins/lisa/rules/reference/ready-role-filing.md +37 -1
- package/plugins/lisa/rules/reference/rejection-detection.md +1 -1
- package/plugins/lisa/rules/reference/repo-scope-split.md +9 -10
- package/plugins/lisa/rules/reference/reset-seed-coverage.md +1 -1
- package/plugins/lisa/rules/reference/usage-accounting.md +1 -1
- package/plugins/lisa/rules/reference/work-item-definition-of-ready.md +1 -1
- package/plugins/lisa/scripts/intake-blocker-reprobe.mjs +85 -17
- package/plugins/lisa/scripts/qa-signal-lifecycle.mjs +5 -2
- package/plugins/lisa/skills/lisa-github-build-intake/SKILL.md +38 -15
- package/plugins/lisa/skills/lisa-github-write-issue/SKILL.md +15 -1
- package/plugins/lisa/skills/lisa-jira-build-intake/SKILL.md +37 -13
- package/plugins/lisa/skills/lisa-jira-write-ticket/SKILL.md +15 -1
- package/plugins/lisa/skills/lisa-linear-access/SKILL.md +56 -7
- package/plugins/lisa/skills/lisa-linear-build-intake/SKILL.md +36 -11
- package/plugins/lisa/skills/lisa-linear-prd-intake/SKILL.md +12 -2
- package/plugins/lisa/skills/lisa-linear-validate-issue/SKILL.md +1 -18
- package/plugins/lisa/skills/lisa-linear-verify/SKILL.md +0 -17
- package/plugins/lisa/skills/lisa-linear-write-issue/SKILL.md +18 -35
- package/plugins/lisa/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
- package/plugins/lisa/skills/lisa-repair-intake/SKILL.md +66 -12
- package/plugins/lisa/skills/lisa-rework-triage/SKILL.md +2 -1
- package/plugins/lisa/skills/lisa-secrets-access/scripts/providers.mjs +2 -1
- package/plugins/lisa/skills/lisa-setup-linear/SKILL.md +1 -1
- package/plugins/lisa/skills/lisa-setup-remote-env/scripts/preflight-tools.mjs +7 -2
- package/plugins/lisa/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +11 -4
- package/plugins/lisa/skills/lisa-setup-remote-env/scripts/toolchain.mjs +17 -5
- package/plugins/lisa/skills/lisa-track/SKILL.md +32 -4
- package/plugins/lisa/skills/lisa-tracker-build-intake/SKILL.md +15 -1
- package/plugins/lisa-agy/hooks/block-blind-automerge.sh +13 -5
- package/plugins/lisa-agy/hooks/block-direct-issue-create.sh +7 -0
- package/plugins/lisa-agy/hooks/block-instruction-file-edits.sh +3 -0
- package/plugins/lisa-agy/hooks/block-managed-file-edits.sh +76 -2
- package/plugins/lisa-agy/hooks/block-shell-json-parsing.sh +3 -0
- package/plugins/lisa-agy/hooks/guard-dedupe.bash +66 -29
- package/plugins/lisa-agy/hooks/parity-safety-net-heredoc.py +3 -0
- package/plugins/lisa-agy/hooks/parity-safety-net.sh +5 -1
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/scripts/intake-blocker-reprobe.mjs +85 -17
- package/plugins/lisa-agy/scripts/qa-signal-lifecycle.mjs +5 -2
- package/plugins/lisa-agy/skills/lisa-github-build-intake/SKILL.md +38 -15
- package/plugins/lisa-agy/skills/lisa-github-write-issue/SKILL.md +15 -1
- package/plugins/lisa-agy/skills/lisa-jira-build-intake/SKILL.md +37 -13
- package/plugins/lisa-agy/skills/lisa-jira-write-ticket/SKILL.md +15 -1
- package/plugins/lisa-agy/skills/lisa-linear-access/SKILL.md +56 -7
- package/plugins/lisa-agy/skills/lisa-linear-build-intake/SKILL.md +36 -11
- package/plugins/lisa-agy/skills/lisa-linear-prd-intake/SKILL.md +12 -2
- package/plugins/lisa-agy/skills/lisa-linear-validate-issue/SKILL.md +1 -18
- package/plugins/lisa-agy/skills/lisa-linear-verify/SKILL.md +0 -17
- package/plugins/lisa-agy/skills/lisa-linear-write-issue/SKILL.md +18 -35
- package/plugins/lisa-agy/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
- package/plugins/lisa-agy/skills/lisa-repair-intake/SKILL.md +66 -12
- package/plugins/lisa-agy/skills/lisa-rework-triage/SKILL.md +2 -1
- package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/providers.mjs +2 -1
- package/plugins/lisa-agy/skills/lisa-setup-linear/SKILL.md +1 -1
- package/plugins/lisa-agy/skills/lisa-setup-remote-env/scripts/preflight-tools.mjs +7 -2
- package/plugins/lisa-agy/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +11 -4
- package/plugins/lisa-agy/skills/lisa-setup-remote-env/scripts/toolchain.mjs +17 -5
- package/plugins/lisa-agy/skills/lisa-track/SKILL.md +32 -4
- package/plugins/lisa-agy/skills/lisa-tracker-build-intake/SKILL.md +15 -1
- 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-blind-automerge.sh +13 -5
- package/plugins/lisa-copilot/hooks/block-direct-issue-create.sh +7 -0
- package/plugins/lisa-copilot/hooks/block-instruction-file-edits.sh +3 -0
- package/plugins/lisa-copilot/hooks/block-managed-file-edits.sh +76 -2
- package/plugins/lisa-copilot/hooks/block-no-verify.sh +3 -0
- package/plugins/lisa-copilot/hooks/block-shell-json-parsing.sh +3 -0
- package/plugins/lisa-copilot/hooks/guard-dedupe.bash +66 -29
- package/plugins/lisa-copilot/hooks/parity-safety-net-heredoc.py +3 -0
- package/plugins/lisa-copilot/hooks/parity-safety-net.sh +5 -1
- package/plugins/lisa-copilot/hooks/worktree-binding-guard.mjs +3 -0
- package/plugins/lisa-copilot/hooks/worktree-binding-guard.sh +5 -1
- package/plugins/lisa-copilot/rules/eager/00-rule-index.md +1 -0
- package/plugins/lisa-copilot/rules/eager/base-rules.md +3 -1
- package/plugins/lisa-copilot/rules/eager/withdrawn-rulings.md +14 -3
- package/plugins/lisa-copilot/rules/reference/automation-runbook-contract.md +1 -1
- package/plugins/lisa-copilot/rules/reference/bdd-e2e-coverage.md +1 -1
- package/plugins/lisa-copilot/rules/reference/blocker-containment.md +3 -3
- package/plugins/lisa-copilot/rules/reference/claim-archaeology.md +1 -1
- package/plugins/lisa-copilot/rules/reference/claim-evidence-mapping.md +1 -1
- package/plugins/lisa-copilot/rules/reference/claim-time-guards.md +1 -1
- package/plugins/lisa-copilot/rules/reference/control-reachability.md +1 -1
- package/plugins/lisa-copilot/rules/reference/convergent-review.md +1 -1
- package/plugins/lisa-copilot/rules/reference/credential-substrate-precedence.md +1 -1
- package/plugins/lisa-copilot/rules/reference/dependency-decision-records.md +1 -1
- package/plugins/lisa-copilot/rules/reference/dependency-internalization-kit.md +1 -1
- package/plugins/lisa-copilot/rules/reference/dependency-trust-classes.md +1 -1
- package/plugins/lisa-copilot/rules/reference/deployed-state-readback.md +1 -1
- package/plugins/lisa-copilot/rules/reference/derived-branch-plan.md +1 -1
- package/plugins/lisa-copilot/rules/reference/design-source-of-truth.md +1 -1
- package/plugins/lisa-copilot/rules/reference/design-value-binding.md +1 -1
- package/plugins/lisa-copilot/rules/reference/documentation-source-paths.md +1 -1
- package/plugins/lisa-copilot/rules/reference/leaf-only-lifecycle.md +1 -1
- package/plugins/lisa-copilot/rules/reference/observability-audit.md +1 -1
- package/plugins/lisa-copilot/rules/reference/prd-definition-of-ready.md +1 -1
- package/plugins/lisa-copilot/rules/reference/prd-lifecycle-rollup.md +1 -1
- package/plugins/lisa-copilot/rules/reference/pre-flight-autofill.md +1 -1
- package/plugins/lisa-copilot/rules/reference/promotion-contract.md +1 -1
- package/plugins/lisa-copilot/rules/reference/readiness-rubric.md +1 -1
- package/plugins/lisa-copilot/rules/reference/ready-role-filing.md +37 -1
- package/plugins/lisa-copilot/rules/reference/rejection-detection.md +1 -1
- package/plugins/lisa-copilot/rules/reference/repo-scope-split.md +9 -10
- package/plugins/lisa-copilot/rules/reference/reset-seed-coverage.md +1 -1
- package/plugins/lisa-copilot/rules/reference/usage-accounting.md +1 -1
- package/plugins/lisa-copilot/rules/reference/work-item-definition-of-ready.md +1 -1
- package/plugins/lisa-copilot/scripts/intake-blocker-reprobe.mjs +85 -17
- package/plugins/lisa-copilot/scripts/qa-signal-lifecycle.mjs +5 -2
- package/plugins/lisa-copilot/skills/lisa-github-build-intake/SKILL.md +38 -15
- package/plugins/lisa-copilot/skills/lisa-github-write-issue/SKILL.md +15 -1
- package/plugins/lisa-copilot/skills/lisa-jira-build-intake/SKILL.md +37 -13
- package/plugins/lisa-copilot/skills/lisa-jira-write-ticket/SKILL.md +15 -1
- package/plugins/lisa-copilot/skills/lisa-linear-access/SKILL.md +56 -7
- package/plugins/lisa-copilot/skills/lisa-linear-build-intake/SKILL.md +36 -11
- package/plugins/lisa-copilot/skills/lisa-linear-prd-intake/SKILL.md +12 -2
- package/plugins/lisa-copilot/skills/lisa-linear-validate-issue/SKILL.md +1 -18
- package/plugins/lisa-copilot/skills/lisa-linear-verify/SKILL.md +0 -17
- package/plugins/lisa-copilot/skills/lisa-linear-write-issue/SKILL.md +18 -35
- package/plugins/lisa-copilot/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
- package/plugins/lisa-copilot/skills/lisa-repair-intake/SKILL.md +66 -12
- package/plugins/lisa-copilot/skills/lisa-rework-triage/SKILL.md +2 -1
- package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/providers.mjs +2 -1
- package/plugins/lisa-copilot/skills/lisa-setup-linear/SKILL.md +1 -1
- package/plugins/lisa-copilot/skills/lisa-setup-remote-env/scripts/preflight-tools.mjs +7 -2
- package/plugins/lisa-copilot/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +11 -4
- package/plugins/lisa-copilot/skills/lisa-setup-remote-env/scripts/toolchain.mjs +17 -5
- package/plugins/lisa-copilot/skills/lisa-track/SKILL.md +32 -4
- package/plugins/lisa-copilot/skills/lisa-tracker-build-intake/SKILL.md +15 -1
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/hooks/block-blind-automerge.sh +13 -5
- package/plugins/lisa-cursor/hooks/block-direct-issue-create.sh +7 -0
- package/plugins/lisa-cursor/hooks/block-instruction-file-edits.sh +3 -0
- package/plugins/lisa-cursor/hooks/block-managed-file-edits.sh +76 -2
- package/plugins/lisa-cursor/hooks/block-no-verify.sh +3 -0
- package/plugins/lisa-cursor/hooks/block-shell-json-parsing.sh +3 -0
- package/plugins/lisa-cursor/hooks/guard-dedupe.bash +66 -29
- package/plugins/lisa-cursor/hooks/parity-safety-net-heredoc.py +3 -0
- package/plugins/lisa-cursor/hooks/parity-safety-net.sh +5 -1
- package/plugins/lisa-cursor/hooks/worktree-binding-guard.mjs +3 -0
- package/plugins/lisa-cursor/hooks/worktree-binding-guard.sh +5 -1
- package/plugins/lisa-cursor/rules/00-rule-index.mdc +1 -0
- package/plugins/lisa-cursor/rules/automation-runbook-contract-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/base-rules.mdc +3 -1
- package/plugins/lisa-cursor/rules/bdd-e2e-coverage-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/blocker-containment-reference.mdc +3 -3
- package/plugins/lisa-cursor/rules/claim-archaeology-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/claim-evidence-mapping-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/claim-time-guards-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/control-reachability-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/convergent-review-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/credential-substrate-precedence-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/dependency-decision-records-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/dependency-internalization-kit-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/dependency-trust-classes-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/deployed-state-readback-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/derived-branch-plan-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/design-source-of-truth-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/design-value-binding-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/documentation-source-paths-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/leaf-only-lifecycle-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/observability-audit-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/prd-definition-of-ready-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/prd-lifecycle-rollup-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/pre-flight-autofill-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/promotion-contract-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/readiness-rubric-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/ready-role-filing-reference.mdc +37 -1
- package/plugins/lisa-cursor/rules/rejection-detection-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/repo-scope-split-reference.mdc +9 -10
- package/plugins/lisa-cursor/rules/reset-seed-coverage-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/usage-accounting-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/withdrawn-rulings.mdc +14 -3
- package/plugins/lisa-cursor/rules/work-item-definition-of-ready-reference.mdc +1 -1
- package/plugins/lisa-cursor/scripts/intake-blocker-reprobe.mjs +85 -17
- package/plugins/lisa-cursor/scripts/qa-signal-lifecycle.mjs +5 -2
- package/plugins/lisa-cursor/skills/lisa-github-build-intake/SKILL.md +38 -15
- package/plugins/lisa-cursor/skills/lisa-github-write-issue/SKILL.md +15 -1
- package/plugins/lisa-cursor/skills/lisa-jira-build-intake/SKILL.md +37 -13
- package/plugins/lisa-cursor/skills/lisa-jira-write-ticket/SKILL.md +15 -1
- package/plugins/lisa-cursor/skills/lisa-linear-access/SKILL.md +56 -7
- package/plugins/lisa-cursor/skills/lisa-linear-build-intake/SKILL.md +36 -11
- package/plugins/lisa-cursor/skills/lisa-linear-prd-intake/SKILL.md +12 -2
- package/plugins/lisa-cursor/skills/lisa-linear-validate-issue/SKILL.md +1 -18
- package/plugins/lisa-cursor/skills/lisa-linear-verify/SKILL.md +0 -17
- package/plugins/lisa-cursor/skills/lisa-linear-write-issue/SKILL.md +18 -35
- package/plugins/lisa-cursor/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
- package/plugins/lisa-cursor/skills/lisa-repair-intake/SKILL.md +66 -12
- package/plugins/lisa-cursor/skills/lisa-rework-triage/SKILL.md +2 -1
- package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/providers.mjs +2 -1
- package/plugins/lisa-cursor/skills/lisa-setup-linear/SKILL.md +1 -1
- package/plugins/lisa-cursor/skills/lisa-setup-remote-env/scripts/preflight-tools.mjs +7 -2
- package/plugins/lisa-cursor/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +11 -4
- package/plugins/lisa-cursor/skills/lisa-setup-remote-env/scripts/toolchain.mjs +17 -5
- package/plugins/lisa-cursor/skills/lisa-track/SKILL.md +32 -4
- package/plugins/lisa-cursor/skills/lisa-tracker-build-intake/SKILL.md +15 -1
- 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/materialized-artifacts.json +11 -0
- package/plugins/src/base/hooks/block-blind-automerge.sh +10 -5
- package/plugins/src/base/hooks/block-direct-issue-create.sh +4 -0
- package/plugins/src/base/hooks/block-managed-file-edits.sh +73 -2
- package/plugins/src/base/hooks/guard-dedupe.bash +63 -29
- package/plugins/src/base/hooks/parity-safety-net.sh +2 -1
- package/plugins/src/base/hooks/worktree-binding-guard.sh +2 -1
- package/plugins/src/base/rules/eager/00-rule-index.md +1 -0
- package/plugins/src/base/rules/eager/base-rules.md +3 -1
- package/plugins/src/base/rules/eager/withdrawn-rulings.md +14 -3
- package/plugins/src/base/rules/reference/automation-runbook-contract.md +1 -1
- package/plugins/src/base/rules/reference/bdd-e2e-coverage.md +1 -1
- package/plugins/src/base/rules/reference/blocker-containment.md +3 -3
- package/plugins/src/base/rules/reference/claim-archaeology.md +1 -1
- package/plugins/src/base/rules/reference/claim-evidence-mapping.md +1 -1
- package/plugins/src/base/rules/reference/claim-time-guards.md +1 -1
- package/plugins/src/base/rules/reference/control-reachability.md +1 -1
- package/plugins/src/base/rules/reference/convergent-review.md +1 -1
- package/plugins/src/base/rules/reference/credential-substrate-precedence.md +1 -1
- package/plugins/src/base/rules/reference/dependency-decision-records.md +1 -1
- package/plugins/src/base/rules/reference/dependency-internalization-kit.md +1 -1
- package/plugins/src/base/rules/reference/dependency-trust-classes.md +1 -1
- package/plugins/src/base/rules/reference/deployed-state-readback.md +1 -1
- package/plugins/src/base/rules/reference/derived-branch-plan.md +1 -1
- package/plugins/src/base/rules/reference/design-source-of-truth.md +1 -1
- package/plugins/src/base/rules/reference/design-value-binding.md +1 -1
- package/plugins/src/base/rules/reference/documentation-source-paths.md +1 -1
- package/plugins/src/base/rules/reference/leaf-only-lifecycle.md +1 -1
- package/plugins/src/base/rules/reference/observability-audit.md +1 -1
- package/plugins/src/base/rules/reference/prd-definition-of-ready.md +1 -1
- package/plugins/src/base/rules/reference/prd-lifecycle-rollup.md +1 -1
- package/plugins/src/base/rules/reference/pre-flight-autofill.md +1 -1
- package/plugins/src/base/rules/reference/promotion-contract.md +1 -1
- package/plugins/src/base/rules/reference/readiness-rubric.md +1 -1
- package/plugins/src/base/rules/reference/ready-role-filing.md +37 -1
- package/plugins/src/base/rules/reference/rejection-detection.md +1 -1
- package/plugins/src/base/rules/reference/repo-scope-split.md +9 -10
- package/plugins/src/base/rules/reference/reset-seed-coverage.md +1 -1
- package/plugins/src/base/rules/reference/usage-accounting.md +1 -1
- package/plugins/src/base/rules/reference/work-item-definition-of-ready.md +1 -1
- package/plugins/src/base/scripts/intake-blocker-reprobe.mjs +85 -17
- package/plugins/src/base/scripts/qa-signal-lifecycle.mjs +5 -2
- package/plugins/src/base/skills/lisa-github-build-intake/SKILL.md +38 -15
- package/plugins/src/base/skills/lisa-github-write-issue/SKILL.md +15 -1
- package/plugins/src/base/skills/lisa-jira-build-intake/SKILL.md +37 -13
- package/plugins/src/base/skills/lisa-jira-write-ticket/SKILL.md +15 -1
- package/plugins/src/base/skills/lisa-linear-access/SKILL.md +56 -7
- package/plugins/src/base/skills/lisa-linear-build-intake/SKILL.md +36 -11
- package/plugins/src/base/skills/lisa-linear-prd-intake/SKILL.md +12 -2
- package/plugins/src/base/skills/lisa-linear-validate-issue/SKILL.md +1 -18
- package/plugins/src/base/skills/lisa-linear-verify/SKILL.md +0 -17
- package/plugins/src/base/skills/lisa-linear-write-issue/SKILL.md +18 -35
- package/plugins/src/base/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
- package/plugins/src/base/skills/lisa-repair-intake/SKILL.md +66 -12
- package/plugins/src/base/skills/lisa-rework-triage/SKILL.md +2 -1
- package/plugins/src/base/skills/lisa-secrets-access/scripts/providers.mjs +2 -1
- package/plugins/src/base/skills/lisa-setup-linear/SKILL.md +1 -1
- package/plugins/src/base/skills/lisa-setup-remote-env/scripts/preflight-tools.mjs +7 -2
- package/plugins/src/base/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +11 -4
- package/plugins/src/base/skills/lisa-setup-remote-env/scripts/toolchain.mjs +17 -5
- package/plugins/src/base/skills/lisa-track/SKILL.md +32 -4
- package/plugins/src/base/skills/lisa-tracker-build-intake/SKILL.md +15 -1
- package/scripts/build-plugins.sh +4 -0
- package/scripts/copy-opencode-plugin-templates.mjs +5 -1
- package/scripts/lisa-enforcement-fallback.sh +9 -1
- package/scripts/two-channel-couplings.json +5 -33
- package/typescript/copy-overwrite/scripts/check-skipped-required-checks.mjs +551 -13
- package/typescript/create-only/.github/required-checks.json +1 -1
|
@@ -6,6 +6,20 @@ allowed-tools: ["Skill", "Bash"]
|
|
|
6
6
|
|
|
7
7
|
# Linear Build Intake: $ARGUMENTS
|
|
8
8
|
|
|
9
|
+
## Human-gate release authorization
|
|
10
|
+
|
|
11
|
+
A release requires a trusted human author, not just matching comment text. Follow
|
|
12
|
+
`ready-role-filing` — **Human-gate release authorization**: preserve tracker-supplied comment
|
|
13
|
+
author IDs and bot metadata, resolve `trustedHumanActorIds` only from an explicit user instruction
|
|
14
|
+
or existing human-authored trusted project policy, and pass it with structured `comments` to every
|
|
15
|
+
hold classifier, reconciliation, normalization and release planner. Never derive trust from the
|
|
16
|
+
comment body, a display name, the actor's own assertion, or an automation posting on its own behalf.
|
|
17
|
+
Missing policy, missing/unreadable author identity, raw body strings, untrusted actors and known bots
|
|
18
|
+
cannot discharge a hold. Keep the item held and report the missing authorization; do not silently
|
|
19
|
+
replace these inputs with an empty history or an inferred allowlist. Authorized matching releases
|
|
20
|
+
continue through the existing path and never override an independently declared caller hold.
|
|
21
|
+
|
|
22
|
+
|
|
9
23
|
`$ARGUMENTS` is one of:
|
|
10
24
|
|
|
11
25
|
1. A Linear team key (e.g. `ENG`) — scans that team for ready Issues.
|
|
@@ -182,13 +196,21 @@ A blocker is a **claim with a timestamp, not a fact**. It is written once and go
|
|
|
182
196
|
|
|
183
197
|
For each pre-work candidate that is **not** in `$READY`:
|
|
184
198
|
|
|
185
|
-
1. **
|
|
199
|
+
1. **Read release comments before applying the human gate.** Pass all item comments, labels,
|
|
200
|
+
body, `trustedHumanActorIds` and configured `humanNeededLabel` to `classifyReadyCandidate(...)`. For a discharged hold,
|
|
201
|
+
call `planHumanGateRelease({ labels, body, comments, trustedHumanActorIds, humanNeededLabel, readyLabel, lifecycleLabels, alreadyNotified })`
|
|
202
|
+
and retain its plan. Apply human-marker cleanup only as planned; defer any ready-role restoration
|
|
203
|
+
until steps 2–5 have cleared the remaining blockers (map the role to the vendor's state or label).
|
|
204
|
+
A still-active hold is never auto-selected, whatever any probe says. An absent or unreadable
|
|
205
|
+
comment history cannot discharge a hold. A release removes only the human hold: continue the
|
|
206
|
+
remaining blocker checks below before selecting the item.
|
|
207
|
+
|
|
186
208
|
2. **Extract the stated discharge condition** from the description or the most recent blocking comment — the sentence naming what has to become true.
|
|
187
209
|
3. **Probe it.** Machine-testable conditions are the ones that rot fastest and are cheapest to check: a version on trunk (`git show origin/<trunk>:<manifest>`), a published package, a run history (`gh run list`), an advisory's patched status. A condition that is a human decision is not machine-testable — leave it and move on.
|
|
188
210
|
4. **Classify with the shared helper** so the ordering and the evidence requirement cannot drift per vendor:
|
|
189
211
|
|
|
190
212
|
```text
|
|
191
|
-
classifyPreWorkCandidate({ laneType, labels, body, humanNeededLabel, statedBlocker, probe })
|
|
213
|
+
classifyPreWorkCandidate({ laneType, labels, body, comments, trustedHumanActorIds, humanNeededLabel, statedBlocker, probe })
|
|
192
214
|
→ { selectable, reason, humanGated, evidence }
|
|
193
215
|
```
|
|
194
216
|
|
|
@@ -216,7 +238,7 @@ other gate's verdict — however conclusive — may promote an item a person par
|
|
|
216
238
|
drift, and a drifted gate fails *silently*, by quietly ceasing to match. Do **not** re-implement
|
|
217
239
|
the test here, and do **not** key it on `reason=`: markers in the wild carry no `reason=` key at
|
|
218
240
|
all and sit anywhere in the body, so a structured parse would miss them while appearing to work
|
|
219
|
-
on every item that happens to have one. **Pass the item's `comments` alongside its labels and
|
|
241
|
+
on every item that happens to have one. **Pass the item's structured `comments` and `trustedHumanActorIds` alongside its labels and
|
|
220
242
|
body.** A hold is ended by a release recorded in a comment, so a reader handed no comments cannot
|
|
221
243
|
see the discharge — it goes on holding an item whose question was answered weeks ago, which is
|
|
222
244
|
the defect this gate carried from the day it was written (CodySwannGT/lisa#3852). Omitting them
|
|
@@ -227,16 +249,17 @@ other gate's verdict — however conclusive — may promote an item a person par
|
|
|
227
249
|
and re-rejected every cycle forever and seen by nothing — `lisa-repair-intake` sweeps items that
|
|
228
250
|
are **not** in the ready role and excludes gated ones outright, so a ready-and-gated item falls
|
|
229
251
|
outside its filter twice over. Call
|
|
230
|
-
`planHumanGateReconciliation({ labels, body, humanNeededLabel, readyLabel, alreadyNotified })`
|
|
252
|
+
`planHumanGateReconciliation({ labels, body, comments, trustedHumanActorIds, humanNeededLabel, readyLabel, alreadyNotified })`
|
|
231
253
|
and apply exactly the actions it returns: remove `$READY`, add the configured human-needed
|
|
232
254
|
marker, and post `formatHumanGateNote()` once. The planner is idempotent by state, so an item
|
|
233
255
|
already out of the lane and already marked yields no second mutation and no second comment. This
|
|
234
256
|
is the same repair the leaf-only gate already performs for a ready item that must not be
|
|
235
257
|
dispatched.
|
|
236
258
|
4. **On `claimable: true` for an item that still carries a hold, RELEASE it — do not just proceed.**
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
`
|
|
259
|
+
This ready-lane candidate can retain a historical body marker and a human-needed label.
|
|
260
|
+
This step reconciles only candidates still in the ready lane; released holds outside it are
|
|
261
|
+
recovered by `lisa-repair-intake` step 2b (or Phase 2.5 when included in this cycle). Call
|
|
262
|
+
`planHumanGateRelease({ labels, body, comments, trustedHumanActorIds, humanNeededLabel, readyLabel, lifecycleLabels, alreadyNotified })`
|
|
240
263
|
and apply exactly the actions it returns: remove the configured human-needed marker, add the
|
|
241
264
|
configured ready role back, and post `formatHumanGateReleaseNote()` once. It is the exact inverse
|
|
242
265
|
of step 3's planner and it refuses in both directions — an item still held plans nothing, and an
|
|
@@ -268,10 +291,12 @@ A Linear team can oversee multiple repos (`frontend` / `backend` / `infrastructu
|
|
|
268
291
|
1. **Resolve the current repo** per `config-resolution` "Repo scoping" (`.repo` → `.github.repo` → `git remote get-url origin` basename). If unresolvable, stop and report.
|
|
269
292
|
2. **Cheap path first.** Prefer candidates already carrying the `repo:<current>` label. Keep the Phase 2 scan broad so unlabeled Issues are still seen, determined, and stamped.
|
|
270
293
|
3. **Per candidate, apply the repo-scope decision (`repo-scope-split`):**
|
|
271
|
-
-
|
|
272
|
-
- **
|
|
273
|
-
- **
|
|
274
|
-
- **
|
|
294
|
+
- **Count distinct repository markers first**: collect all `repo:<name>` labels and, on JIRA, recognized repository components; deduplicate by repository. A container may carry multiple `repo:<name>` labels. Do not split or claim it here; send it to the leaf-only gate.
|
|
295
|
+
- **Multi-repo leaf → split, never claim.** More than one repository takes the work-time split before any wrong-repository skip. Each sibling is **build-ready** (`build_ready: true`) and stamped with its own `repo:<name>`; the current repo's sibling becomes a normal candidate.
|
|
296
|
+
- **Exactly one other repository** (`repo:<other>`) → **skip**, leaving the item ready for that repo's intake.
|
|
297
|
+
- **No repository marker** → determine target repo(s) from the ticket and code, stamp `repo:<name>` through the vendor access layer, and re-apply from the count.
|
|
298
|
+
- **Single-repo leaf for the current repo** → fall through to 3a and 3b.
|
|
299
|
+
|
|
275
300
|
4. Continue until a claimable current-repo leaf is found (claim it; one per cycle) or the candidate set is exhausted — exit cleanly on the denominator-stated summary, naming the current repo alongside the swept lanes.
|
|
276
301
|
|
|
277
302
|
#### 3a. Leaf-only claim gate (skip / safe-block containers)
|
|
@@ -130,6 +130,16 @@ Select the first ready project returned by Phase 2 and process only that project
|
|
|
130
130
|
|
|
131
131
|
#### 3a. Claim
|
|
132
132
|
|
|
133
|
+
**Preflight project comments before any claim or destination-ticket creation.** Through
|
|
134
|
+
`lisa-linear-access`, resolve an identity-matched tier-1 GraphQL credential and the
|
|
135
|
+
`save-comment project_id` adapter, then read the candidate's complete project comment
|
|
136
|
+
history with `list-comments project_id:<id>`. The issue-only MCP is insufficient for
|
|
137
|
+
this flow. If the required credential, adapter or read is unavailable, return the
|
|
138
|
+
layer's `Error:` naming the project-comment operation and leave the project ready;
|
|
139
|
+
create no tickets and no substitute comment-holder Issue. This is a read-only
|
|
140
|
+
capability preflight, not a test comment. It establishes the available transport;
|
|
141
|
+
later permission changes or write failures still follow the normal error handler.
|
|
142
|
+
|
|
133
143
|
Transition labels via `lisa-linear-access operation: save-project({id, labels})`: pass the full new label set with `$READY` removed and `$IN_REVIEW` added. This is the idempotency lock — a re-entrant cycle running concurrently won't see this project because its query filters on `label: "$READY"`.
|
|
134
144
|
|
|
135
145
|
If the update fails (permission error, race condition), log it and skip this project. Do not proceed to validation on a project you didn't successfully claim.
|
|
@@ -152,7 +162,7 @@ This call also indirectly invokes `lisa-tracker-source-artifacts` (artifact extr
|
|
|
152
162
|
|
|
153
163
|
1. Re-invoke `lisa-linear-to-tracker` with `dry_run: false` to actually write the tickets. This re-runs Phases 1-5 and runs the preservation gate (Phase 5.5).
|
|
154
164
|
2. Capture the created ticket keys from the skill's output.
|
|
155
|
-
3. Post a comment on the project via `lisa-linear-access operation: save-comment project_id:<id>` listing the created tickets (epic, stories, sub-tasks) with
|
|
165
|
+
3. Post a comment on the project via `lisa-linear-access operation: save-comment project_id:<id>` listing the created tickets (epic, stories, sub-tasks) with the URLs returned by the configured destination tracker. Lead with: `"Ticketed by Claude. Created N tickets — see below. Add the $SHIPPED label to the Linear project after the work is delivered."`
|
|
156
166
|
4. Transition labels: remove `$IN_REVIEW`, add `$TICKETED` via `save_project`.
|
|
157
167
|
5. **Run Phase 3e (coverage audit)** before considering this PRD done.
|
|
158
168
|
|
|
@@ -396,6 +406,6 @@ Before this skill can run against a Linear workspace or team, the team must adop
|
|
|
396
406
|
1. Apply the `ready` label (default: `prd-ready`) to projects that are ready for ticketing (replaces the Notion `Status = Ready` flip and the Confluence `prd-ready` page label).
|
|
397
407
|
2. Reserve `in_review`, `blocked`, `ticketed` (defaults: `prd-in-review`, `prd-blocked`, `prd-ticketed`) for this skill — humans should not set them manually except to recover from an error.
|
|
398
408
|
3. (Optional but recommended) Add the `draft` and `shipped` labels (defaults: `prd-draft`, `prd-shipped`) for in-progress PRDs and delivered work respectively, so the full lifecycle is visible at a glance.
|
|
399
|
-
4. The labels must exist as **project labels** in Linear (`
|
|
409
|
+
4. The labels must exist as **project labels** in Linear (`list-project-labels` should return them). Issue-level labels with the same names won't work; Linear keeps the two label kinds separate.
|
|
400
410
|
|
|
401
411
|
If the workspace hasn't adopted these labels, the first run exits with a label-convention error (not the idle empty-set message) — this distinguishes a setup issue from a genuinely empty queue so operators know to apply the convention rather than assuming there is no work. See Phase 2 for how the skill detects this case.
|
|
@@ -91,24 +91,7 @@ prd_source: "https://notion.so/..." # set when the Issue was generated from a
|
|
|
91
91
|
|
|
92
92
|
If the caller passes only an identifier, fetch the item via `lisa-linear-access operation: get-issue` (Issue) or `lisa-linear-access operation: get-project` (Project), derive the same fields from the fetched data — including `runtime_behavior_change` (derived from the `## Target Backend Environment` declaration per `derived-branch-plan`, and authoritative over any caller assertion), `build_ready` (the Issue's state is the configured `ready` state) and `child_refs` (sub-issues, project-member issues, plus `blocked_by` parentage, resolved as in `lisa-linear-read-issue`) so S15 can classify the item — then run gates.
|
|
93
93
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
This is a supported entry point, not only an internal step of a caller flow.
|
|
97
|
-
Point it at a live issue and it fetches and validates the stored state:
|
|
98
|
-
|
|
99
|
-
```text
|
|
100
|
-
Skill(lisa-linear-validate-issue) with ENG-1234
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
Use it whenever the issue reached the tracker by some path other than
|
|
104
|
-
`lisa-linear-write-issue` — a team's own script, a workflow step, a cron, anything holding the
|
|
105
|
-
credentials but no skill runtime. Those paths get neither the pre-write nor the
|
|
106
|
-
post-write gate, and their own read-back substitutes for neither: a read-back
|
|
107
|
-
proves the tracker stored what was sent, never that what was sent was any good.
|
|
108
|
-
|
|
109
|
-
The gate definitions live here on purpose, so every caller picks up a change
|
|
110
|
-
automatically. Running this skill by hand is the same gate the write path runs,
|
|
111
|
-
not an approximation of it.
|
|
94
|
+
For existing items written through another path, use the [standalone entry point](#standalone-entry-point--validating-an-item-written-by-another-path). A transport read-back does not prove the stored specification passes the gates.
|
|
112
95
|
|
|
113
96
|
## Gates
|
|
114
97
|
|
|
@@ -63,20 +63,3 @@ normalize-then-compare. Byte-exact comparison of such text is forbidden.
|
|
|
63
63
|
- Never write to Linear. Read-only.
|
|
64
64
|
- Never short-circuit the validator. Always run the full gate set.
|
|
65
65
|
- If `get_issue` / `get_project` returns an access error, surface it and exit — don't pretend the item is fine.
|
|
66
|
-
|
|
67
|
-
## Comparison is semantic, never byte-exact
|
|
68
|
-
|
|
69
|
-
Re-run the validator against the live issue. Do NOT compare the stored body
|
|
70
|
-
against what was sent byte for byte.
|
|
71
|
-
|
|
72
|
-
The reason is measured rather than theoretical. Trackers normalize markdown on
|
|
73
|
-
write: `-` bullets become `*`, a bare URL is wrapped as `[url](<url>)`, bold
|
|
74
|
-
emphasis is re-segmented around inline code spans. All lossless, all
|
|
75
|
-
rendering-identical, and all of it makes a byte comparator report failure on a
|
|
76
|
-
write that was completely fine. A comparator that cannot tell vendor
|
|
77
|
-
normalization from corruption fails on healthy writes and trains its reader to
|
|
78
|
-
ignore it, which costs more than the check was ever worth.
|
|
79
|
-
|
|
80
|
-
Compare meaning: run `lisa-linear-validate-issue` against the stored item and let the gates
|
|
81
|
-
decide. Where a single field must be compared directly, normalize both sides
|
|
82
|
-
first.
|
|
@@ -6,6 +6,20 @@ allowed-tools: ["Bash", "Skill"]
|
|
|
6
6
|
|
|
7
7
|
# Write Linear Work Item: $ARGUMENTS
|
|
8
8
|
|
|
9
|
+
## Human-gate release authorization
|
|
10
|
+
|
|
11
|
+
A release requires a trusted human author, not just matching comment text. Follow
|
|
12
|
+
`ready-role-filing` — **Human-gate release authorization**: preserve tracker-supplied comment
|
|
13
|
+
author IDs and bot metadata, resolve `trustedHumanActorIds` only from an explicit user instruction
|
|
14
|
+
or existing human-authored trusted project policy, and pass it with structured `comments` to every
|
|
15
|
+
hold classifier, reconciliation, normalization and release planner. Never derive trust from the
|
|
16
|
+
comment body, a display name, the actor's own assertion, or an automation posting on its own behalf.
|
|
17
|
+
Missing policy, missing/unreadable author identity, raw body strings, untrusted actors and known bots
|
|
18
|
+
cannot discharge a hold. Keep the item held and report the missing authorization; do not silently
|
|
19
|
+
replace these inputs with an empty history or an inferred allowlist. Authorized matching releases
|
|
20
|
+
continue through the existing path and never override an independently declared caller hold.
|
|
21
|
+
|
|
22
|
+
|
|
9
23
|
Create or update a Linear work item — Project (for Epics), Issue (for Stories), or sub-Issue (for Sub-tasks) — with all required relationships, metadata, and quality gates. Every section below is mandatory. Thin items are rejected.
|
|
10
24
|
|
|
11
25
|
Repository name for scoped comments: `basename $(git rev-parse --show-toplevel)`.
|
|
@@ -33,40 +47,7 @@ Linear's data model maps Epic / Story / Sub-task to **different entity types**.
|
|
|
33
47
|
|
|
34
48
|
The build lifecycle uses native **workflow states** (`Ready`, `In Progress`, `Blocked`, `On Dev`, `On Stg`, `Done`, plus an optional review state a project may bind), resolved per role from `linear.workflow` — see "Why Linear uses states, not labels" in `config-resolution`. A new **leaf** work unit is created in the configured `ready` state only on explicit `build_ready: true`; omitted or `false` leaves it in the team's default backlog state, and a container is never put in `ready` at all (see the Build-ready control input below).
|
|
35
49
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
A team that talks to its tracker through its own script is doing a normal
|
|
39
|
-
thing — the script usually owns the credential plumbing, and Lisa neither
|
|
40
|
-
controls nor wants to control it. What that script does NOT get is either half
|
|
41
|
-
of this skill's quality gate, and nothing about the write says so.
|
|
42
|
-
|
|
43
|
-
**A read-back is not the missing check.** A bespoke path almost always re-reads
|
|
44
|
-
the issue after writing and confirms the tracker stored what was sent. That is
|
|
45
|
-
worth doing and it is not this. It proves TRANSPORT: the API accepted the
|
|
46
|
-
payload and the field values round-tripped. It cannot fail for the reason these
|
|
47
|
-
gates exist, because it never looks at whether what was sent was any good — a
|
|
48
|
-
issue with no acceptance criteria, no parent, and a human decision left sitting
|
|
49
|
-
in the middle of it round-trips perfectly. That is the dangerous half of the
|
|
50
|
-
shape: a failing control gets investigated, a misread one gets trusted.
|
|
51
|
-
|
|
52
|
-
So a write by any other path still owes both phases, and both run standalone
|
|
53
|
-
against an item that already exists:
|
|
54
|
-
|
|
55
|
-
| Phase | Skill | What it costs you |
|
|
56
|
-
|---|---|---|
|
|
57
|
-
| Pre-write validate | `lisa-linear-validate-issue` | Run it on the draft before you send it |
|
|
58
|
-
| Post-write verify | `lisa-linear-verify` | Run it on the live issue after you send it |
|
|
59
|
-
|
|
60
|
-
```text
|
|
61
|
-
Skill(lisa-linear-validate-issue) with the draft issue, or with a reference to a live one
|
|
62
|
-
Skill(lisa-linear-verify) with ENG-1234
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
**These are plugin-resident skills invoked through the Skill tool.** They are
|
|
66
|
-
not shell scripts and will not appear in any repository's `scripts/` directory,
|
|
67
|
-
including yours. An agent that searches the repo it is standing in, finds
|
|
68
|
-
nothing, and concludes the capability is absent has made the one mistake that
|
|
69
|
-
turns a local script from the convenient option into the only one.
|
|
50
|
+
For direct API or bespoke script writes, the [bespoke-path contract](#writing-by-a-bespoke-path-your-own-script-direct-api-or-graphql) still requires pre-write validation and post-write verification.
|
|
70
51
|
|
|
71
52
|
## Phase 1 — Resolve Intent
|
|
72
53
|
|
|
@@ -334,8 +315,10 @@ person scanning a board and to any path that has not yet been routed through the
|
|
|
334
315
|
If the label does not exist in the tracker, create it, or record that it could not be applied and
|
|
335
316
|
proceed — the marker still holds. Never file the label *instead of* the marker.
|
|
336
317
|
|
|
318
|
+
**Every marker reader must consult comments.** Use `classifyReadyCandidate` with labels, body, comments and the configured human-needed label, then `planHumanGateRelease` for any release actions. A historical body marker alone is not an active hold after its matching release; unreadable comments leave a hold in place.
|
|
319
|
+
|
|
337
320
|
**Write a `reason=` the release can name.** The hold's reason is not decoration: a hold ends when a
|
|
338
|
-
`[lisa-human-gate-release]` comment repeating that same `reason=` is recorded on the item, and the
|
|
321
|
+
`[lisa-human-gate-release]` comment repeating that same `reason=` is recorded on the item by an authorized human, and the
|
|
339
322
|
next intake sweep then takes the marker label off and puts the item back in the build-ready role on
|
|
340
323
|
its own. Matching is per-reason so that a hold declared *after* an earlier release is not born
|
|
341
324
|
discharged. A keyless hold is legal and is discharged by a keyless release; a hold whose reason is a
|
|
@@ -15,7 +15,7 @@ The PRD URL can be a **Notion page URL**, a **Confluence page URL**, a **Linear
|
|
|
15
15
|
|
|
16
16
|
- `notion.so` / `notion.site` → Notion. Fetch with `mcp__claude_ai_Notion__notion-fetch` (`include_discussions: true`) and `mcp__claude_ai_Notion__notion-get-comments`.
|
|
17
17
|
- Atlassian Confluence host (e.g. `*.atlassian.net/wiki/...`) → Confluence. Through `lisa-atlassian-access`, fetch the page, its descendants (for child epic pages), and its footer + inline comments including nested replies. State the operation, not a vendor tool name — the access skill owns substrate selection (`integration-access-layer`).
|
|
18
|
-
- `linear.app` host → Linear. Fetch with `lisa-linear-access operation: get-project` (capture description, labels, state, attached resources), `lisa-linear-access operation: list-documents({projectId})` + `lisa-linear-access operation: get-document` per attached document, `lisa-linear-access operation: list-issues({project})` for sub-issues that act as child epics / user stories, and `lisa-linear-access operation: list-comments({issueId})` per sub-issue for decisions and engineering notes.
|
|
18
|
+
- `linear.app` host → Linear. Fetch with `lisa-linear-access operation: get-project` (capture description, labels, state, attached resources), `lisa-linear-access operation: list-documents({projectId})` + `lisa-linear-access operation: get-document` per attached document, `lisa-linear-access operation: list-issues({project})` for sub-issues that act as child epics / user stories, and `lisa-linear-access operation: list-comments({issueId})` per sub-issue for decisions and engineering notes. Also fetch all project comments with `lisa-linear-access operation: list-comments project_id:<ID>`; the access layer pages through GraphQL even when the MCP lacks project comments. An incomplete comment read is an access failure, not an empty history.
|
|
19
19
|
- `github.com` host → GitHub Issues. Fetch with the `gh` CLI (no GitHub MCP — Lisa uses the CLI exclusively for GitHub):
|
|
20
20
|
- `gh issue view <number> --repo <org>/<repo> --json number,title,body,labels,milestone,assignees,author,createdAt,comments,url` for the PRD body and comments.
|
|
21
21
|
- `gh api graphql` with the `subIssues` field for native sub-issue children (these stand in for child epic pages — see `lisa-github-read-issue` Phase 3 for the exact query).
|
|
@@ -41,7 +41,7 @@ Per-ticket gates (`lisa-jira-validate-ticket`) prove each created ticket is well
|
|
|
41
41
|
2. Fetch the PRD using the vendor-appropriate tool surface:
|
|
42
42
|
- **Notion**: `notion-fetch` with `include_discussions: true`. Capture: title, body, child Epic pages, all comment threads.
|
|
43
43
|
- **Confluence**: `getConfluencePage` (capture title, body, labels), `getConfluencePageFooterComments` + `getConfluencePageInlineComments` (capture all comments; walk replies via `getConfluenceCommentChildren` for any thread with children).
|
|
44
|
-
- **Linear**: `get_project` (capture name, description, labels, state, attached resources). Capture sub-issues via `list_issues({project})` and per-issue comments via `list_comments({issueId})`.
|
|
44
|
+
- **Linear**: `get_project` (capture name, description, labels, state, attached resources). Capture all project comments via `lisa-linear-access operation: list-comments project_id:<ID>`, plus sub-issues via `list_issues({project})` and per-issue comments via `list_comments({issueId})`. Include both comment sources in destination URL discovery; refuse to report `NO_TICKETS_FOUND` from an incomplete read.
|
|
45
45
|
- **GitHub**: `gh issue view --json` for the source PRD issue (title, body, labels, comments). Capture sub-issues via the GraphQL `subIssues` traversal.
|
|
46
46
|
3. If the PRD has child Epic sub-pages / sub-issues (a multi-epic PRD), fetch each in parallel:
|
|
47
47
|
- **Notion**: `notion-fetch` per child page with `include_discussions: true`.
|
|
@@ -6,6 +6,20 @@ allowed-tools: ["Skill", "Bash", "Read", "Write", "Edit"]
|
|
|
6
6
|
|
|
7
7
|
# Repair Intake: $ARGUMENTS
|
|
8
8
|
|
|
9
|
+
## Human-gate release authorization
|
|
10
|
+
|
|
11
|
+
A release requires a trusted human author, not just matching comment text. Follow
|
|
12
|
+
`ready-role-filing` — **Human-gate release authorization**: preserve tracker-supplied comment
|
|
13
|
+
author IDs and bot metadata, resolve `trustedHumanActorIds` only from an explicit user instruction
|
|
14
|
+
or existing human-authored trusted project policy, and pass it with structured `comments` to every
|
|
15
|
+
hold classifier, reconciliation, normalization and release planner. Never derive trust from the
|
|
16
|
+
comment body, a display name, the actor's own assertion, or an automation posting on its own behalf.
|
|
17
|
+
Missing policy, missing/unreadable author identity, raw body strings, untrusted actors and known bots
|
|
18
|
+
cannot discharge a hold. Keep the item held and report the missing authorization; do not silently
|
|
19
|
+
replace these inputs with an empty history or an inferred allowlist. Authorized matching releases
|
|
20
|
+
continue through the existing path and never override an independently declared caller hold.
|
|
21
|
+
|
|
22
|
+
|
|
9
23
|
Run one batch-**repair** cycle against the queue identified by `$ARGUMENTS`, or by merged GitHub
|
|
10
24
|
config when the queue is omitted and a GitHub source/tracker default is resolvable. Where `lisa-intake`
|
|
11
25
|
scans the `ready` role and moves work *forward*, repair-intake scans the **stuck and
|
|
@@ -189,7 +203,7 @@ In addition to the lifecycle roles above, the build lifecycle defines the **`hum
|
|
|
189
203
|
- The blocks repair-intake **itself writes** are the auto-recoverable kind — it files a build-ready fix ticket and moves the item `blocked` *blocked by that ticket*, expecting the next cycle to self-heal. Those are **not** `human_needed`; if such an item arrives carrying a `human_needed` marker **this skill applied on an earlier cycle**, repair-intake **clears** it (the block is no longer waiting on a human).
|
|
190
204
|
- **Never remove a `human_needed` marker this skill did not apply.** "Stale" is a judgment about the block's kind, not about who applied the marker or when — so without this rule an operator's deliberate hold, applied *after* correcting a wrong transition, is indistinguishable from a leftover the sweep is designed to clear, and gets swept. Establish provenance from the label event's actor (`rejection-detection` **Automation-reversal memory** reads the same surfaces); if provenance is not readable, **leave the marker in place**. Removing a human's hold is unrecoverable within the loop; leaving a stale one costs a cycle and is visible.
|
|
191
205
|
- **The one exception is a hold that has recorded its own discharge.** A `[lisa-human-gate-release]` comment naming the hold's `reason=` is not a guess about provenance — it is the hold's stated void condition, recorded on the item by the person who answered it. Clearing the marker there is not overriding a human's judgment; it is *enacting* it. That is the whole of the exception: no other reading of "this looks stale" reopens the question above, and an item whose release cannot be read stays held. See "Release the holds that have been answered" below (#3852).
|
|
192
|
-
- The marker is consulted **before **any** repair transition**, not only before Class C. Class C's hard stop is the strictest reading of it, but a marker that is honoured on one classification path and ignored on the other three is not a guard — and Class A, dependency clearing, is exactly the path an operator reverting a wrongly-cleared blocker is trying to protect.
|
|
206
|
+
- The marker is consulted **before **any** repair transition**, not only before Class C. Class C's hard stop is the strictest reading of it, but a marker that is honoured on one classification path and ignored on the other three is not a guard — and Class A, dependency clearing, is exactly the path an operator reverting a wrongly-cleared blocker is trying to protect. Read all comments and consult `classifyReadyCandidate` / `planHumanGateRelease` before treating the marker as active; a matching release discharges the historical body marker. Use the shared helpers for robust label and declaration matching, and leave unreadable releases held.
|
|
193
207
|
- The blocks the **vendor agent** writes when repair-intake re-dispatches it (its pre-flight gate) carry `human_needed` already — the agent owns that marker. repair-intake leaves it in place.
|
|
194
208
|
|
|
195
209
|
Resolve with the standard role-read pattern (local overrides global, default fallback):
|
|
@@ -621,6 +635,41 @@ the item open. Recording "the fix reached dev and production but skipped staging
|
|
|
621
635
|
branch back-fill, not outstanding delivery" and then closing anyway is this defect exactly — the
|
|
622
636
|
condition observed, filed under the wrong heading, and overridden.
|
|
623
637
|
|
|
638
|
+
### Resolve the shipped blocker-edge module
|
|
639
|
+
|
|
640
|
+
The helper ships in the plugin and npm package. Only the runtime-supplied plugin roots
|
|
641
|
+
and installed package are trusted here; do not search arbitrary checkout-local plugin folders.
|
|
642
|
+
Write the evaluated edge inputs to a JSON array file, then call `blocker_edge_decisions`.
|
|
643
|
+
An absent module, unreadable input or import failure stops this repair without tracker writes.
|
|
644
|
+
|
|
645
|
+
```bash
|
|
646
|
+
resolve_blocker_guard() {
|
|
647
|
+
local candidate
|
|
648
|
+
for candidate in \
|
|
649
|
+
"${CLAUDE_PLUGIN_ROOT:+$CLAUDE_PLUGIN_ROOT/scripts/blocker-edge-resolution.mjs}" \
|
|
650
|
+
"${PLUGIN_ROOT:+$PLUGIN_ROOT/scripts/blocker-edge-resolution.mjs}" \
|
|
651
|
+
node_modules/@codyswann/lisa/plugins/lisa/scripts/blocker-edge-resolution.mjs; do
|
|
652
|
+
[ -n "$candidate" ] && [ -f "$candidate" ] && { printf '%s\n' "$candidate"; return; }
|
|
653
|
+
done
|
|
654
|
+
echo "Error: could not locate blocker-edge-resolution.mjs; refusing repair." >&2
|
|
655
|
+
return 1
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
blocker_edge_decisions() { # JSON array file -> decision object
|
|
659
|
+
local guard
|
|
660
|
+
guard=$(resolve_blocker_guard) || return 1
|
|
661
|
+
node --input-type=module - "$guard" "$1" <<'LISA_BLOCKER_NODE'
|
|
662
|
+
import { readFileSync } from "node:fs";
|
|
663
|
+
import { resolve } from "node:path";
|
|
664
|
+
import { pathToFileURL } from "node:url";
|
|
665
|
+
const { resolveBlockerEdges } = await import(pathToFileURL(resolve(process.argv[2])).href);
|
|
666
|
+
const edges = JSON.parse(readFileSync(process.argv[3], "utf8"));
|
|
667
|
+
if (!Array.isArray(edges)) throw new Error("Expected an array of blocker edges");
|
|
668
|
+
console.log(JSON.stringify(resolveBlockerEdges(edges)));
|
|
669
|
+
LISA_BLOCKER_NODE
|
|
670
|
+
}
|
|
671
|
+
```
|
|
672
|
+
|
|
624
673
|
### Build `blocked` → re-evaluate, unblock if cleared
|
|
625
674
|
|
|
626
675
|
1. Read the block reason and classify the blocker (see Blocker classification & clearing). An item
|
|
@@ -629,8 +678,11 @@ condition observed, filed under the wrong heading, and overridden.
|
|
|
629
678
|
Re-check **every** class present — do not stop at "no `is blocked by` links, therefore nothing
|
|
630
679
|
to do." A self-block has zero dependencies by definition, yet is fully re-checkable.
|
|
631
680
|
2. **Dependency cleared** — decide each parsed `is blocked by` edge with
|
|
632
|
-
`scripts/blocker-edge-resolution.mjs`, feeding it the
|
|
633
|
-
blocker's state and closure reason.
|
|
681
|
+
the shipped plugin helper `scripts/blocker-edge-resolution.mjs`, feeding it the
|
|
682
|
+
`blocker-containment` verdict plus the blocker's state and closure reason. This is a module,
|
|
683
|
+
not a CLI and not a required host `scripts/` file. Resolve a trusted plugin/package path and
|
|
684
|
+
invoke `resolveBlockerEdges` as shown above; never create a second resolver in the host.
|
|
685
|
+
It returns `dissolve` / `keep` / `escalate` per edge.
|
|
634
686
|
**Dissolve the edge in the SAME write that records the ruling, then read the relation back and
|
|
635
687
|
confirm it is gone.** Only when every edge dissolves → move `blocked → claimed`, then run the
|
|
636
688
|
same agent-dispatch + post-agent `claimed → done` sequence as the stalled-`claimed` path above
|
|
@@ -1033,7 +1085,7 @@ with labels like `build-ready`, or with no Lisa status label at all, that are in
|
|
|
1033
1085
|
`intake_mode=build`, every non-PRD issue is normalized as a build ticket. If `intake_mode=both`,
|
|
1034
1086
|
classify PRDs first and normalize all remaining issues as build tickets.
|
|
1035
1087
|
2a. **Ask whether a person is holding it, before anything else.** Call
|
|
1036
|
-
`planLabelNormalization({ labels, body, humanNeededLabel, lifecycleLabels, readyLabel })` from
|
|
1088
|
+
`planLabelNormalization({ labels, body, comments, trustedHumanActorIds, humanNeededLabel, lifecycleLabels, readyLabel })` from
|
|
1037
1089
|
`scripts/intake-blocker-reprobe.mjs` for every candidate and apply exactly the verdict it
|
|
1038
1090
|
returns. Do **not** re-implement the test here and do **not** decide held-ness from labels
|
|
1039
1091
|
alone: the vendor writers stamp the `[lisa-human-gate]` marker into the body of a deliberate
|
|
@@ -1050,7 +1102,7 @@ with labels like `build-ready`, or with no Lisa status label at all, that are in
|
|
|
1050
1102
|
the safe failure direction without the latch. Count these under `held_for_person`, never under
|
|
1051
1103
|
`normalized_ready`.
|
|
1052
1104
|
|
|
1053
|
-
**Pass the item's `comments`.** The planner reads a recorded `[lisa-human-gate-release]` comment
|
|
1105
|
+
**Pass the item's `comments` with author identity and `trustedHumanActorIds`.** The planner reads a recorded `[lisa-human-gate-release]` comment
|
|
1054
1106
|
as the discharge of the hold naming the same `reason=`, and an item read without its comments is
|
|
1055
1107
|
an item whose discharge cannot be seen. That fails closed — it stays held — which is the safe
|
|
1056
1108
|
direction and precisely why the omission is invisible.
|
|
@@ -1064,7 +1116,7 @@ with labels like `build-ready`, or with no Lisa status label at all, that are in
|
|
|
1064
1116
|
|
|
1065
1117
|
Enumerate items carrying the configured `human_needed` marker **or** a `[lisa-human-gate]` marker
|
|
1066
1118
|
in the body, and for each call
|
|
1067
|
-
`planHumanGateRelease({ labels, body, comments, humanNeededLabel, readyLabel, lifecycleLabels, alreadyNotified })`
|
|
1119
|
+
`planHumanGateRelease({ labels, body, comments, trustedHumanActorIds, humanNeededLabel, readyLabel, lifecycleLabels, alreadyNotified })`
|
|
1068
1120
|
from `scripts/intake-blocker-reprobe.mjs`. Apply exactly the actions it returns: remove the
|
|
1069
1121
|
human-needed marker, add the configured build `ready` label back, and post
|
|
1070
1122
|
`formatHumanGateReleaseNote()` once. Do **not** re-implement the discharge test, and do **not**
|
|
@@ -1081,10 +1133,10 @@ with labels like `build-ready`, or with no Lisa status label at all, that are in
|
|
|
1081
1133
|
item carries no other configured lifecycle label.
|
|
1082
1134
|
|
|
1083
1135
|
This is a genuine exception to "never remove a `human_needed` marker this skill did not apply",
|
|
1084
|
-
and the exception is narrow enough to state exactly:
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1136
|
+
and the exception is narrow enough to state exactly: the release author must first be verified against `trustedHumanActorIds`; only then does the
|
|
1137
|
+
matching release satisfy the hold's stated void condition. The actor who originally applied the
|
|
1138
|
+
marker does not need to match that authorized release author. The general rule
|
|
1139
|
+
stands because "stale" is otherwise a judgment about the block's kind; here an authorized matching release is required; arbitrary matching text is not enough.
|
|
1088
1140
|
|
|
1089
1141
|
**Never edit a description to clear a hold**, here or anywhere. The only body write this plugin
|
|
1090
1142
|
has is a whole-body replacement, so deleting one line means rewriting the record and hoping
|
|
@@ -1187,9 +1239,11 @@ layer, and test ancestry against the remote.
|
|
|
1187
1239
|
remote, ancestry query errored) → **still blocking**, with the rule's reason key in the run
|
|
1188
1240
|
record.
|
|
1189
1241
|
- **Ships no code** — the blocker is closed as completed, positively declares
|
|
1190
|
-
|
|
1242
|
+
`## Target Backend Environment` reading `None — no runtime behavior change: <kind>`
|
|
1243
|
+
with kind `doc-only`, `config-only`, or `type-only`, and has no linked PR and no merge commit →
|
|
1191
1244
|
**cleared** under the rule's carve-out. This is a positive determination, never an absence:
|
|
1192
|
-
"no PR found" is `no-pr` and stays blocking.
|
|
1245
|
+
"no PR found" is `no-pr` and stays blocking. A missing kind does not qualify; any linked
|
|
1246
|
+
open or unmerged PR stays blocking under the normal containment test.
|
|
1193
1247
|
- **Human override** — an explicit human statement on this item that the dependency is satisfied
|
|
1194
1248
|
clears it and outranks a failed containment check. Name it in the run record.
|
|
1195
1249
|
- **Human hold** — the override runs in both directions. `human_needed` is checked here as well as
|
|
@@ -53,7 +53,8 @@ first-attempt work.
|
|
|
53
53
|
# bundle.json: { "labels": [...], "comments": [<bodies, oldest first>], "role": "<current>" }
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
Branch on `
|
|
56
|
+
Branch on `outcome`, never on the label being there. The resolver's separate
|
|
57
|
+
`action` field is `keep` / `clear` / `none`; it is not the liveness verdict:
|
|
57
58
|
|
|
58
59
|
| `outcome` | Meaning | What triage does |
|
|
59
60
|
|---|---|---|
|
|
@@ -357,7 +357,7 @@ jq -e '.linear.workspace' .lisa.config.json >/dev/null
|
|
|
357
357
|
[ "$(jq -r '.tracker // empty' .lisa.config.json)" = "linear" ] && jq -e '.linear.teamKey' .lisa.config.json >/dev/null
|
|
358
358
|
```
|
|
359
359
|
|
|
360
|
-
Confirm what was scaffolded is present: `list-workflow-states` for every build role when Linear is the tracker, `
|
|
360
|
+
Confirm what was scaffolded is present: `list-workflow-states` for every build role when Linear is the tracker, `list-project-labels` for `prd-*` (including the terminal `prd-verified`) when Linear is the PRD source. Do NOT expect a `status:*` namespace — it is not part of this model. Report success with the resolved workspace, team key (if any), which namespaces were scaffolded (created vs. already existed), any non-default overrides, and whether `tracker` / `source` were set. Direct the user to `/lisa:intake` to test.
|
|
361
361
|
|
|
362
362
|
## Idempotency
|
|
363
363
|
|
|
@@ -70,7 +70,7 @@ const BLOCKING = new Set(["missing", "invalid"]);
|
|
|
70
70
|
/**
|
|
71
71
|
* Whether an unpinnable entry is nonetheless usable on this machine.
|
|
72
72
|
*
|
|
73
|
-
*
|
|
73
|
+
* Executability is required, even when no version floor is declared. Dropping the entry entirely would
|
|
74
74
|
* report clean for a tool that is neither pinned nor installed, which is the
|
|
75
75
|
* vacuous green this module refuses everywhere else. So the probe still decides
|
|
76
76
|
* — it just gets asked, which on this branch it previously never was.
|
|
@@ -83,7 +83,12 @@ const BLOCKING = new Set(["missing", "invalid"]);
|
|
|
83
83
|
* @returns {boolean} Whether the tool is present and good enough to use.
|
|
84
84
|
*/
|
|
85
85
|
function usableWithoutPin(step, minVersions) {
|
|
86
|
-
if (
|
|
86
|
+
if (
|
|
87
|
+
!step.unpinnedForPlatform ||
|
|
88
|
+
!step.found?.present ||
|
|
89
|
+
step.found.executable !== true
|
|
90
|
+
)
|
|
91
|
+
return false;
|
|
87
92
|
const floor = minVersions[step.name];
|
|
88
93
|
return !floor || compareVersions(step.found.version ?? "0", floor) >= 0;
|
|
89
94
|
}
|
|
@@ -120,7 +120,7 @@ export function readRemoteEnvConfig(cwd = process.cwd()) {
|
|
|
120
120
|
* on which quirky binaries happen to exist on the machine running the tests.
|
|
121
121
|
* @param {string} name Executable name.
|
|
122
122
|
* @param {Function} [exec] Command runner, for tests.
|
|
123
|
-
* @returns {{version: string|null, present: boolean}} Probe result.
|
|
123
|
+
* @returns {{version: string|null, present: boolean, executable: boolean}} Probe result.
|
|
124
124
|
*/
|
|
125
125
|
export function probe(name, exec = boundedChildOutput) {
|
|
126
126
|
try {
|
|
@@ -128,12 +128,19 @@ export function probe(name, exec = boundedChildOutput) {
|
|
|
128
128
|
encoding: "utf8",
|
|
129
129
|
stdio: ["ignore", "pipe", "pipe"],
|
|
130
130
|
});
|
|
131
|
-
return { present: true, version: extractVersion(out) };
|
|
131
|
+
return { present: true, executable: true, version: extractVersion(out) };
|
|
132
132
|
} catch (err) {
|
|
133
|
-
if (err.code === "ENOENT") return { present: false, version: null };
|
|
134
133
|
if (err.code === "ETIMEDOUT") throw err;
|
|
134
|
+
// A numeric exit status proves the child started, even when --version is
|
|
135
|
+
// unsupported. EACCES and other spawn failures carry no exit status: a
|
|
136
|
+
// file being discoverable does not mean the agent can execute it.
|
|
137
|
+
const executable = typeof err.status === "number";
|
|
135
138
|
const output = `${err.stdout ?? ""}${err.stderr ?? ""}`;
|
|
136
|
-
return {
|
|
139
|
+
return {
|
|
140
|
+
present: err.code !== "ENOENT",
|
|
141
|
+
executable,
|
|
142
|
+
version: executable ? extractVersion(output) : null,
|
|
143
|
+
};
|
|
137
144
|
}
|
|
138
145
|
}
|
|
139
146
|
|
|
@@ -56,7 +56,7 @@ export function extractVersion(output) {
|
|
|
56
56
|
/**
|
|
57
57
|
* Classify one required tool against what the environment actually provides.
|
|
58
58
|
* @param {object} tool Manifest entry.
|
|
59
|
-
* @param {{version: string|null, present: boolean}} found Probe result.
|
|
59
|
+
* @param {{version: string|null, present: boolean, executable: boolean}} found Probe result.
|
|
60
60
|
* @returns {{name: string, action: string, reason: string}} The decision.
|
|
61
61
|
*/
|
|
62
62
|
function planRequired(tool, found) {
|
|
@@ -70,6 +70,13 @@ function planRequired(tool, found) {
|
|
|
70
70
|
`Either add an install entry or pin a different image.`,
|
|
71
71
|
};
|
|
72
72
|
}
|
|
73
|
+
if (found.executable !== true) {
|
|
74
|
+
return {
|
|
75
|
+
name: tool.name,
|
|
76
|
+
action: "missing",
|
|
77
|
+
reason: `${tool.name} was found but cannot be executed. Repair its permissions or replace the binary before using it.`,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
73
80
|
if (
|
|
74
81
|
tool.minVersion &&
|
|
75
82
|
compareVersions(found.version ?? "0", tool.minVersion) < 0
|
|
@@ -97,7 +104,7 @@ function planRequired(tool, found) {
|
|
|
97
104
|
* and maintenance the same script, and it is the cheap path when a container
|
|
98
105
|
* resumes from cache rather than being built fresh.
|
|
99
106
|
* @param {object} tool Manifest entry.
|
|
100
|
-
* @param {{version: string|null, present: boolean}} found Probe result.
|
|
107
|
+
* @param {{version: string|null, present: boolean, executable: boolean}} found Probe result.
|
|
101
108
|
* @returns {{name: string, action: string, reason: string}} The decision.
|
|
102
109
|
*/
|
|
103
110
|
function planInstallable(tool, found, pinIsFloor = false) {
|
|
@@ -108,7 +115,11 @@ function planInstallable(tool, found, pinIsFloor = false) {
|
|
|
108
115
|
reason: `${tool.name} has no pinned version. An unpinned install is not reproducible.`,
|
|
109
116
|
};
|
|
110
117
|
}
|
|
111
|
-
if (
|
|
118
|
+
if (
|
|
119
|
+
found.present &&
|
|
120
|
+
found.executable === true &&
|
|
121
|
+
found.version === tool.version
|
|
122
|
+
) {
|
|
112
123
|
return {
|
|
113
124
|
name: tool.name,
|
|
114
125
|
action: "skip",
|
|
@@ -125,6 +136,7 @@ function planInstallable(tool, found, pinIsFloor = false) {
|
|
|
125
136
|
if (
|
|
126
137
|
pinIsFloor &&
|
|
127
138
|
found.present &&
|
|
139
|
+
found.executable === true &&
|
|
128
140
|
found.version &&
|
|
129
141
|
compareVersions(found.version, tool.version) > 0
|
|
130
142
|
) {
|
|
@@ -286,10 +298,10 @@ export function appliesToSurface(tool, surface) {
|
|
|
286
298
|
* asking about availability rather than provisioning has the answer instead of
|
|
287
299
|
* having to infer one from the other.
|
|
288
300
|
* @param {{require?: object[], install?: object[]}} tools Manifest.
|
|
289
|
-
* @param {(name: string) => {version: string|null, present: boolean}} probe Version probe.
|
|
301
|
+
* @param {(name: string) => {version: string|null, present: boolean, executable: boolean}} probe Version probe.
|
|
290
302
|
* @param {string} [surface] Surface being provisioned.
|
|
291
303
|
* @param {string} [platform] Platform key to resolve install entries against.
|
|
292
|
-
* @returns {Array<{name: string, action: string, reason: string, tool?: object, found?: {version: string|null, present: boolean}, unpinnedForPlatform?: boolean}>} Ordered decisions.
|
|
304
|
+
* @returns {Array<{name: string, action: string, reason: string, tool?: object, found?: {version: string|null, present: boolean, executable: boolean}, unpinnedForPlatform?: boolean}>} Ordered decisions.
|
|
293
305
|
*/
|
|
294
306
|
export function planToolchain(
|
|
295
307
|
tools,
|