@codyswann/lisa 4.74.9 → 4.75.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +60 -0
- package/dist/core/lisa-skill-sources.d.ts +3 -3
- package/dist/core/lisa-skill-sources.d.ts.map +1 -1
- package/dist/core/lisa-skill-sources.js +3 -2
- package/dist/core/lisa-skill-sources.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 +730 -5
- package/dist/core/upstream-evidence-manifest.js.map +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-agy/plugin.json +1 -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-cdk-devin/.claude-plugin/plugin.json +11 -0
- package/plugins/lisa-cdk-devin/.devin-plugin/plugin.json +8 -0
- package/plugins/lisa-cdk-devin/skills/setup-aws-accounts/SKILL.md +292 -0
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-devin/.claude-plugin/plugin.json +8 -0
- package/plugins/lisa-devin/.devin-plugin/plugin.json +8 -0
- package/plugins/lisa-devin/.mcp.json +8 -0
- package/plugins/lisa-devin/agents/architecture-specialist.md +32 -0
- package/plugins/lisa-devin/agents/bug-fixer.md +43 -0
- package/plugins/lisa-devin/agents/builder.md +44 -0
- package/plugins/lisa-devin/agents/confluence-prd-intake.md +65 -0
- package/plugins/lisa-devin/agents/debug-specialist.md +34 -0
- package/plugins/lisa-devin/agents/eval-specialist.md +33 -0
- package/plugins/lisa-devin/agents/git-history-analyzer.md +183 -0
- package/plugins/lisa-devin/agents/github-agent.md +155 -0
- package/plugins/lisa-devin/agents/github-build-intake.md +64 -0
- package/plugins/lisa-devin/agents/github-prd-intake.md +66 -0
- package/plugins/lisa-devin/agents/jira-agent.md +135 -0
- package/plugins/lisa-devin/agents/jira-build-intake.md +64 -0
- package/plugins/lisa-devin/agents/learner.md +85 -0
- package/plugins/lisa-devin/agents/learning-judge.md +119 -0
- package/plugins/lisa-devin/agents/learnings-synthesizer.md +155 -0
- package/plugins/lisa-devin/agents/linear-agent.md +138 -0
- package/plugins/lisa-devin/agents/linear-build-intake.md +64 -0
- package/plugins/lisa-devin/agents/linear-prd-intake.md +66 -0
- package/plugins/lisa-devin/agents/notion-prd-intake.md +63 -0
- package/plugins/lisa-devin/agents/performance-specialist.md +26 -0
- package/plugins/lisa-devin/agents/pr-mining-specialist.md +85 -0
- package/plugins/lisa-devin/agents/product-specialist.md +30 -0
- package/plugins/lisa-devin/agents/quality-specialist.md +30 -0
- package/plugins/lisa-devin/agents/security-specialist.md +43 -0
- package/plugins/lisa-devin/agents/skill-evaluator.md +205 -0
- package/plugins/lisa-devin/agents/spec-conformance-specialist.md +56 -0
- package/plugins/lisa-devin/agents/test-specialist.md +32 -0
- package/plugins/lisa-devin/agents/tracker-mining-specialist.md +85 -0
- package/plugins/lisa-devin/agents/verification-specialist.md +145 -0
- package/plugins/lisa-devin/hooks/auto-update.mjs +824 -0
- package/plugins/lisa-devin/hooks/auto-update.sh +31 -0
- package/plugins/lisa-devin/hooks/block-blind-automerge.sh +1242 -0
- package/plugins/lisa-devin/hooks/block-direct-issue-create.sh +2603 -0
- package/plugins/lisa-devin/hooks/block-host-name-leak.mjs +412 -0
- package/plugins/lisa-devin/hooks/block-host-name-leak.sh +61 -0
- package/plugins/lisa-devin/hooks/block-instruction-file-edits.sh +207 -0
- package/plugins/lisa-devin/hooks/block-managed-file-edits.sh +1175 -0
- package/plugins/lisa-devin/hooks/block-no-verify.sh +2288 -0
- package/plugins/lisa-devin/hooks/block-shell-json-parsing.sh +263 -0
- package/plugins/lisa-devin/hooks/cleanup-stale-worktrees.sh +122 -0
- package/plugins/lisa-devin/hooks/devin-tool-name-shim.sh +30 -0
- package/plugins/lisa-devin/hooks/discharge-work-item-gates.sh +90 -0
- package/plugins/lisa-devin/hooks/enforce-verification-gate.sh +506 -0
- package/plugins/lisa-devin/hooks/enforcement-vintage-npm.mjs +320 -0
- package/plugins/lisa-devin/hooks/enforcement-vintage.mjs +472 -0
- package/plugins/lisa-devin/hooks/enforcement-vintage.sh +48 -0
- package/plugins/lisa-devin/hooks/failure-signature-index.mjs +717 -0
- package/plugins/lisa-devin/hooks/failure-signature-index.sh +26 -0
- package/plugins/lisa-devin/hooks/guard-dedupe.bash +374 -0
- package/plugins/lisa-devin/hooks/inject-resolved-config.mjs +903 -0
- package/plugins/lisa-devin/hooks/inject-resolved-config.sh +107 -0
- package/plugins/lisa-devin/hooks/inject-rules.sh +49 -0
- package/plugins/lisa-devin/hooks/install-pkgs.sh +84 -0
- package/plugins/lisa-devin/hooks/operational-hazards.mjs +736 -0
- package/plugins/lisa-devin/hooks/operational-hazards.sh +28 -0
- package/plugins/lisa-devin/hooks/parity-safety-net-heredoc.py +1004 -0
- package/plugins/lisa-devin/hooks/parity-safety-net.sh +3275 -0
- package/plugins/lisa-devin/hooks/secrets-preflight.sh +72 -0
- package/plugins/lisa-devin/hooks/setup-jira-cli.sh +205 -0
- package/plugins/lisa-devin/hooks/shell-write-nudge.sh +86 -0
- package/plugins/lisa-devin/hooks/sonar-secrets.sh +205 -0
- package/plugins/lisa-devin/hooks/threshold-ratchet-compare.mjs +518 -0
- package/plugins/lisa-devin/hooks/threshold-ratchet-families.mjs +543 -0
- package/plugins/lisa-devin/hooks/threshold-ratchet.mjs +568 -0
- package/plugins/lisa-devin/hooks/threshold-ratchet.sh +22 -0
- package/plugins/lisa-devin/hooks/withdrawn-rulings.mjs +600 -0
- package/plugins/lisa-devin/hooks/withdrawn-rulings.sh +24 -0
- package/plugins/lisa-devin/hooks/worktree-binding-guard.mjs +1383 -0
- package/plugins/lisa-devin/hooks/worktree-binding-guard.sh +79 -0
- package/plugins/lisa-devin/hooks.json +247 -0
- package/plugins/lisa-devin/rules/eager/00-rule-index.md +82 -0
- package/plugins/lisa-devin/rules/eager/base-rules.md +85 -0
- package/plugins/lisa-devin/rules/eager/coding-philosophy.md +27 -0
- package/plugins/lisa-devin/rules/eager/config-resolution.md +37 -0
- package/plugins/lisa-devin/rules/eager/do-it-now.md +11 -0
- package/plugins/lisa-devin/rules/eager/empirical-inquiry.md +24 -0
- package/plugins/lisa-devin/rules/eager/falsifiable-checks.md +48 -0
- package/plugins/lisa-devin/rules/eager/history-audit.md +27 -0
- package/plugins/lisa-devin/rules/eager/integration-access-layer.md +19 -0
- package/plugins/lisa-devin/rules/eager/intent-routing.md +18 -0
- package/plugins/lisa-devin/rules/eager/learnings-ladder.md +18 -0
- package/plugins/lisa-devin/rules/eager/local-ci-first.md +15 -0
- package/plugins/lisa-devin/rules/eager/measurement-integrity.md +18 -0
- package/plugins/lisa-devin/rules/eager/never-name-a-downstream-project.md +9 -0
- package/plugins/lisa-devin/rules/eager/not-blocked-just-waiting.md +13 -0
- package/plugins/lisa-devin/rules/eager/operational-hazards.md +50 -0
- package/plugins/lisa-devin/rules/eager/report-actionability.md +26 -0
- package/plugins/lisa-devin/rules/eager/security-audit-handling.md +40 -0
- package/plugins/lisa-devin/rules/eager/session-status-updates.md +20 -0
- package/plugins/lisa-devin/rules/eager/settled-decisions.md +75 -0
- package/plugins/lisa-devin/rules/eager/stale-state-claims.md +26 -0
- package/plugins/lisa-devin/rules/eager/tool-access-gate.md +23 -0
- package/plugins/lisa-devin/rules/eager/tracked-work.md +9 -0
- package/plugins/lisa-devin/rules/eager/upstream-to-lisa.md +14 -0
- package/plugins/lisa-devin/rules/eager/verification.md +33 -0
- package/plugins/lisa-devin/rules/eager/wiki-knowledge-source.md +13 -0
- package/plugins/lisa-devin/rules/eager/withdrawn-rulings.md +102 -0
- package/plugins/lisa-devin/rules/reference/automation-runbook-contract.md +355 -0
- package/plugins/lisa-devin/rules/reference/base-rules.md +136 -0
- package/plugins/lisa-devin/rules/reference/bdd-e2e-coverage.md +301 -0
- package/plugins/lisa-devin/rules/reference/blocker-containment.md +165 -0
- package/plugins/lisa-devin/rules/reference/claim-archaeology.md +184 -0
- package/plugins/lisa-devin/rules/reference/claim-evidence-mapping.md +362 -0
- package/plugins/lisa-devin/rules/reference/claim-time-guards.md +135 -0
- package/plugins/lisa-devin/rules/reference/coding-philosophy.md +428 -0
- package/plugins/lisa-devin/rules/reference/config-resolution.md +1225 -0
- package/plugins/lisa-devin/rules/reference/control-reachability.md +166 -0
- package/plugins/lisa-devin/rules/reference/convergent-review.md +145 -0
- package/plugins/lisa-devin/rules/reference/credential-substrate-precedence.md +249 -0
- package/plugins/lisa-devin/rules/reference/dependency-decision-records.md +177 -0
- package/plugins/lisa-devin/rules/reference/dependency-internalization-kit.md +244 -0
- package/plugins/lisa-devin/rules/reference/dependency-trust-classes.md +291 -0
- package/plugins/lisa-devin/rules/reference/deployed-state-readback.md +142 -0
- package/plugins/lisa-devin/rules/reference/derived-branch-plan.md +214 -0
- package/plugins/lisa-devin/rules/reference/design-source-of-truth.md +260 -0
- package/plugins/lisa-devin/rules/reference/design-value-binding.md +311 -0
- package/plugins/lisa-devin/rules/reference/do-it-now.md +19 -0
- package/plugins/lisa-devin/rules/reference/documentation-source-paths.md +31 -0
- package/plugins/lisa-devin/rules/reference/empirical-inquiry.md +28 -0
- package/plugins/lisa-devin/rules/reference/factory-model.md +111 -0
- package/plugins/lisa-devin/rules/reference/falsifiable-checks.md +275 -0
- package/plugins/lisa-devin/rules/reference/history-audit.md +42 -0
- package/plugins/lisa-devin/rules/reference/integration-access-layer.md +89 -0
- package/plugins/lisa-devin/rules/reference/intent-routing.md +428 -0
- package/plugins/lisa-devin/rules/reference/leaf-only-lifecycle.md +227 -0
- package/plugins/lisa-devin/rules/reference/learnings-ladder.md +41 -0
- package/plugins/lisa-devin/rules/reference/local-ci-first.md +34 -0
- package/plugins/lisa-devin/rules/reference/measurement-integrity.md +119 -0
- package/plugins/lisa-devin/rules/reference/never-name-a-downstream-project.md +37 -0
- package/plugins/lisa-devin/rules/reference/not-blocked-just-waiting.md +41 -0
- package/plugins/lisa-devin/rules/reference/observability-audit.md +146 -0
- package/plugins/lisa-devin/rules/reference/operational-hazards.md +115 -0
- package/plugins/lisa-devin/rules/reference/prd-definition-of-ready.md +118 -0
- package/plugins/lisa-devin/rules/reference/prd-lifecycle-rollup.md +192 -0
- package/plugins/lisa-devin/rules/reference/pre-flight-autofill.md +250 -0
- package/plugins/lisa-devin/rules/reference/project-learnings.md +159 -0
- package/plugins/lisa-devin/rules/reference/promotion-contract.md +148 -0
- package/plugins/lisa-devin/rules/reference/readiness-rubric.md +242 -0
- package/plugins/lisa-devin/rules/reference/ready-role-filing.md +212 -0
- package/plugins/lisa-devin/rules/reference/rejection-detection.md +308 -0
- package/plugins/lisa-devin/rules/reference/repo-scope-split.md +119 -0
- package/plugins/lisa-devin/rules/reference/report-actionability.md +61 -0
- package/plugins/lisa-devin/rules/reference/reset-seed-coverage.md +286 -0
- package/plugins/lisa-devin/rules/reference/security-audit-handling.md +55 -0
- package/plugins/lisa-devin/rules/reference/session-status-updates.md +111 -0
- package/plugins/lisa-devin/rules/reference/settled-decisions.md +39 -0
- package/plugins/lisa-devin/rules/reference/stale-state-claims.md +88 -0
- package/plugins/lisa-devin/rules/reference/tool-access-gate.md +114 -0
- package/plugins/lisa-devin/rules/reference/tracked-work.md +49 -0
- package/plugins/lisa-devin/rules/reference/upstream-to-lisa.md +26 -0
- package/plugins/lisa-devin/rules/reference/usage-accounting.md +261 -0
- package/plugins/lisa-devin/rules/reference/verification.md +278 -0
- package/plugins/lisa-devin/rules/reference/wiki-knowledge-source.md +37 -0
- package/plugins/lisa-devin/rules/reference/withdrawn-rulings.md +148 -0
- package/plugins/lisa-devin/rules/reference/work-item-definition-of-ready.md +177 -0
- package/plugins/lisa-devin/rules/reference/work-item-trailer-definition.md +129 -0
- package/plugins/lisa-devin/scripts/automation-run-record.mjs +678 -0
- package/plugins/lisa-devin/scripts/automation-status-claude-adapter.mjs +804 -0
- package/plugins/lisa-devin/scripts/automation-status-codex-adapter.mjs +1081 -0
- package/plugins/lisa-devin/scripts/automation-status-contract-drift.mjs +392 -0
- package/plugins/lisa-devin/scripts/automation-status-expected-fleet.mjs +508 -0
- package/plugins/lisa-devin/scripts/automation-status-report.mjs +200 -0
- package/plugins/lisa-devin/scripts/automation-status-run-history.mjs +216 -0
- package/plugins/lisa-devin/scripts/automation-status-unrecorded-runs.mjs +127 -0
- package/plugins/lisa-devin/scripts/blocker-edge-resolution.mjs +150 -0
- package/plugins/lisa-devin/scripts/cross-pollinate.mjs +763 -0
- package/plugins/lisa-devin/scripts/design-bindings-probe.mjs +713 -0
- package/plugins/lisa-devin/scripts/design-intake-gate.mjs +470 -0
- package/plugins/lisa-devin/scripts/design-source-gate.mjs +610 -0
- package/plugins/lisa-devin/scripts/design-variable-ids.mjs +567 -0
- package/plugins/lisa-devin/scripts/doctor-report.mjs +635 -0
- package/plugins/lisa-devin/scripts/install-remote-agent-aws.mjs +443 -0
- package/plugins/lisa-devin/scripts/intake-blocker-reprobe.mjs +1065 -0
- package/plugins/lisa-devin/scripts/intake-prework-denominator.mjs +249 -0
- package/plugins/lisa-devin/scripts/lifecycle-label-trust.mjs +593 -0
- package/plugins/lisa-devin/scripts/linear-state-write-target.mjs +362 -0
- package/plugins/lisa-devin/scripts/plugin-sync-explain.mjs +654 -0
- package/plugins/lisa-devin/scripts/pr-arming-sweep.mjs +561 -0
- package/plugins/lisa-devin/scripts/project-ideation-idempotency-harness.mjs +338 -0
- package/plugins/lisa-devin/scripts/qa-signal-lifecycle.mjs +523 -0
- package/plugins/lisa-devin/scripts/queue-contract-resolution.mjs +583 -0
- package/plugins/lisa-devin/scripts/queue-health-classification.mjs +157 -0
- package/plugins/lisa-devin/scripts/queue-status-build-readers.mjs +561 -0
- package/plugins/lisa-devin/scripts/queue-status-prd-readers.mjs +452 -0
- package/plugins/lisa-devin/scripts/remote-agent-aws-setup.sh +677 -0
- package/plugins/lisa-devin/scripts/repo-scope-vocabulary-audit.mjs +458 -0
- package/plugins/lisa-devin/scripts/resolve-lifecycle-role.mjs +347 -0
- package/plugins/lisa-devin/scripts/rollup-blocker-classification.mjs +616 -0
- package/plugins/lisa-devin/scripts/scoping-label-audit.mjs +474 -0
- package/plugins/lisa-devin/skills/lisa-acceptance-criteria/SKILL.md +73 -0
- package/plugins/lisa-devin/skills/lisa-agent-design-best-practices/SKILL.md +242 -0
- package/plugins/lisa-devin/skills/lisa-agent-ready/SKILL.md +271 -0
- package/plugins/lisa-devin/skills/lisa-analyze-claude-remote/SKILL.md +434 -0
- package/plugins/lisa-devin/skills/lisa-atlassian-access/SKILL.md +469 -0
- package/plugins/lisa-devin/skills/lisa-atlassian-access/scripts/markdown-to-adf.mjs +236 -0
- package/plugins/lisa-devin/skills/lisa-attribute-failure/SKILL.md +142 -0
- package/plugins/lisa-devin/skills/lisa-automation-status/SKILL.md +149 -0
- package/plugins/lisa-devin/skills/lisa-bug-triage/SKILL.md +23 -0
- package/plugins/lisa-devin/skills/lisa-capability-drift/SKILL.md +71 -0
- package/plugins/lisa-devin/skills/lisa-codebase-research/SKILL.md +87 -0
- package/plugins/lisa-devin/skills/lisa-codify-verification/SKILL.md +213 -0
- package/plugins/lisa-devin/skills/lisa-confluence-prd-intake/SKILL.md +417 -0
- package/plugins/lisa-devin/skills/lisa-confluence-to-tracker/SKILL.md +469 -0
- package/plugins/lisa-devin/skills/lisa-confluence-write-prd/SKILL.md +111 -0
- package/plugins/lisa-devin/skills/lisa-cross-pollinate/SKILL.md +175 -0
- package/plugins/lisa-devin/skills/lisa-debrief/SKILL.md +96 -0
- package/plugins/lisa-devin/skills/lisa-debrief-apply/SKILL.md +106 -0
- package/plugins/lisa-devin/skills/lisa-delivery-effectiveness/SKILL.md +62 -0
- package/plugins/lisa-devin/skills/lisa-design-intake/SKILL.md +198 -0
- package/plugins/lisa-devin/skills/lisa-detect-tooling/SKILL.md +110 -0
- package/plugins/lisa-devin/skills/lisa-detect-tooling/scripts/commands.mjs +479 -0
- package/plugins/lisa-devin/skills/lisa-detect-tooling/scripts/detect-tooling.mjs +658 -0
- package/plugins/lisa-devin/skills/lisa-doctor/SKILL.md +743 -0
- package/plugins/lisa-devin/skills/lisa-drive-pr-to-merge/SKILL.md +1587 -0
- package/plugins/lisa-devin/skills/lisa-epic-triage/SKILL.md +28 -0
- package/plugins/lisa-devin/skills/lisa-evaluation-suite/SKILL.md +63 -0
- package/plugins/lisa-devin/skills/lisa-exploratory-qa/SKILL.md +185 -0
- package/plugins/lisa-devin/skills/lisa-fix-linter-error/SKILL.md +45 -0
- package/plugins/lisa-devin/skills/lisa-generate-claude-remote-build-script/SKILL.md +235 -0
- package/plugins/lisa-devin/skills/lisa-git-commit/SKILL.md +53 -0
- package/plugins/lisa-devin/skills/lisa-git-prune/SKILL.md +35 -0
- package/plugins/lisa-devin/skills/lisa-git-submit-pr/SKILL.md +170 -0
- package/plugins/lisa-devin/skills/lisa-github-add-journey/SKILL.md +118 -0
- package/plugins/lisa-devin/skills/lisa-github-build-intake/SKILL.md +745 -0
- package/plugins/lisa-devin/skills/lisa-github-claim/SKILL.md +27 -0
- package/plugins/lisa-devin/skills/lisa-github-create/SKILL.md +105 -0
- package/plugins/lisa-devin/skills/lisa-github-evidence/SKILL.md +120 -0
- package/plugins/lisa-devin/skills/lisa-github-journey/SKILL.md +134 -0
- package/plugins/lisa-devin/skills/lisa-github-prd-intake/SKILL.md +424 -0
- package/plugins/lisa-devin/skills/lisa-github-project-v2/SKILL.md +227 -0
- package/plugins/lisa-devin/skills/lisa-github-read-issue/SKILL.md +305 -0
- package/plugins/lisa-devin/skills/lisa-github-sync/SKILL.md +201 -0
- package/plugins/lisa-devin/skills/lisa-github-to-tracker/SKILL.md +456 -0
- package/plugins/lisa-devin/skills/lisa-github-validate-issue/SKILL.md +598 -0
- package/plugins/lisa-devin/skills/lisa-github-verify/SKILL.md +60 -0
- package/plugins/lisa-devin/skills/lisa-github-write-issue/SKILL.md +531 -0
- package/plugins/lisa-devin/skills/lisa-github-write-prd/SKILL.md +156 -0
- package/plugins/lisa-devin/skills/lisa-health/SKILL.md +142 -0
- package/plugins/lisa-devin/skills/lisa-health-drift-cron/SKILL.md +80 -0
- package/plugins/lisa-devin/skills/lisa-implement/SKILL.md +372 -0
- package/plugins/lisa-devin/skills/lisa-improve-code-complexity/SKILL.md +44 -0
- package/plugins/lisa-devin/skills/lisa-improve-harness/SKILL.md +487 -0
- package/plugins/lisa-devin/skills/lisa-improve-max-lines/SKILL.md +45 -0
- package/plugins/lisa-devin/skills/lisa-improve-max-lines-per-function/SKILL.md +46 -0
- package/plugins/lisa-devin/skills/lisa-improve-test-coverage/SKILL.md +47 -0
- package/plugins/lisa-devin/skills/lisa-improve-tests/SKILL.md +50 -0
- package/plugins/lisa-devin/skills/lisa-intake/SKILL.md +208 -0
- package/plugins/lisa-devin/skills/lisa-intake-explain/SKILL.md +279 -0
- package/plugins/lisa-devin/skills/lisa-jam-access/SKILL.md +128 -0
- package/plugins/lisa-devin/skills/lisa-jira-add-journey/SKILL.md +139 -0
- package/plugins/lisa-devin/skills/lisa-jira-build-intake/SKILL.md +556 -0
- package/plugins/lisa-devin/skills/lisa-jira-claim/SKILL.md +27 -0
- package/plugins/lisa-devin/skills/lisa-jira-create/SKILL.md +157 -0
- package/plugins/lisa-devin/skills/lisa-jira-evidence/SKILL.md +106 -0
- package/plugins/lisa-devin/skills/lisa-jira-evidence/scripts/post-evidence.sh +262 -0
- package/plugins/lisa-devin/skills/lisa-jira-journey/SKILL.md +168 -0
- package/plugins/lisa-devin/skills/lisa-jira-journey/scripts/generate-templates.py +239 -0
- package/plugins/lisa-devin/skills/lisa-jira-journey/scripts/parse-plan.py +570 -0
- package/plugins/lisa-devin/skills/lisa-jira-read-ticket/SKILL.md +199 -0
- package/plugins/lisa-devin/skills/lisa-jira-read-ticket/scripts/download-attachment.sh +211 -0
- package/plugins/lisa-devin/skills/lisa-jira-sync/SKILL.md +117 -0
- package/plugins/lisa-devin/skills/lisa-jira-validate-ticket/SKILL.md +525 -0
- package/plugins/lisa-devin/skills/lisa-jira-verify/SKILL.md +61 -0
- package/plugins/lisa-devin/skills/lisa-jira-write-ticket/SKILL.md +440 -0
- package/plugins/lisa-devin/skills/lisa-jsdoc-best-practices/SKILL.md +491 -0
- package/plugins/lisa-devin/skills/lisa-kane-browser/SKILL.md +80 -0
- package/plugins/lisa-devin/skills/lisa-learnings-audit/SKILL.md +490 -0
- package/plugins/lisa-devin/skills/lisa-linear-access/SKILL.md +483 -0
- package/plugins/lisa-devin/skills/lisa-linear-add-journey/SKILL.md +109 -0
- package/plugins/lisa-devin/skills/lisa-linear-build-intake/SKILL.md +548 -0
- package/plugins/lisa-devin/skills/lisa-linear-claim/SKILL.md +28 -0
- package/plugins/lisa-devin/skills/lisa-linear-create/SKILL.md +150 -0
- package/plugins/lisa-devin/skills/lisa-linear-evidence/SKILL.md +124 -0
- package/plugins/lisa-devin/skills/lisa-linear-journey/SKILL.md +147 -0
- package/plugins/lisa-devin/skills/lisa-linear-prd-intake/SKILL.md +411 -0
- package/plugins/lisa-devin/skills/lisa-linear-read-issue/SKILL.md +201 -0
- package/plugins/lisa-devin/skills/lisa-linear-sync/SKILL.md +164 -0
- package/plugins/lisa-devin/skills/lisa-linear-to-tracker/SKILL.md +454 -0
- package/plugins/lisa-devin/skills/lisa-linear-validate-issue/SKILL.md +504 -0
- package/plugins/lisa-devin/skills/lisa-linear-verify/SKILL.md +65 -0
- package/plugins/lisa-devin/skills/lisa-linear-write-issue/SKILL.md +448 -0
- package/plugins/lisa-devin/skills/lisa-linear-write-prd/SKILL.md +98 -0
- package/plugins/lisa-devin/skills/lisa-monitor/SKILL.md +224 -0
- package/plugins/lisa-devin/skills/lisa-nightly-add-test-coverage/SKILL.md +40 -0
- package/plugins/lisa-devin/skills/lisa-nightly-improve-tests/SKILL.md +29 -0
- package/plugins/lisa-devin/skills/lisa-nightly-lower-code-complexity/SKILL.md +42 -0
- package/plugins/lisa-devin/skills/lisa-notion-access/SKILL.md +301 -0
- package/plugins/lisa-devin/skills/lisa-notion-prd-intake/SKILL.md +360 -0
- package/plugins/lisa-devin/skills/lisa-notion-to-tracker/SKILL.md +467 -0
- package/plugins/lisa-devin/skills/lisa-notion-write-prd/SKILL.md +111 -0
- package/plugins/lisa-devin/skills/lisa-parity-code-review/SKILL.md +83 -0
- package/plugins/lisa-devin/skills/lisa-parity-code-simplifier/SKILL.md +76 -0
- package/plugins/lisa-devin/skills/lisa-parity-coderabbit/SKILL.md +87 -0
- package/plugins/lisa-devin/skills/lisa-parity-sentry-sdk-setup/SKILL.md +375 -0
- package/plugins/lisa-devin/skills/lisa-parity-sentry-seer/SKILL.md +168 -0
- package/plugins/lisa-devin/skills/lisa-parity-skill-creator/SKILL.md +155 -0
- package/plugins/lisa-devin/skills/lisa-performance-review/SKILL.md +94 -0
- package/plugins/lisa-devin/skills/lisa-persist-learning/SKILL.md +247 -0
- package/plugins/lisa-devin/skills/lisa-plan/SKILL.md +64 -0
- package/plugins/lisa-devin/skills/lisa-plugin-sync-explain/SKILL.md +53 -0
- package/plugins/lisa-devin/skills/lisa-posthog-access/SKILL.md +140 -0
- package/plugins/lisa-devin/skills/lisa-prd-backlink/SKILL.md +274 -0
- package/plugins/lisa-devin/skills/lisa-prd-source-write/SKILL.md +104 -0
- package/plugins/lisa-devin/skills/lisa-prd-ticket-coverage/SKILL.md +187 -0
- package/plugins/lisa-devin/skills/lisa-product-walkthrough/SKILL.md +106 -0
- package/plugins/lisa-devin/skills/lisa-project-ideation/SKILL.md +417 -0
- package/plugins/lisa-devin/skills/lisa-project-ideation/examples/evidence-card-format.md +21 -0
- package/plugins/lisa-devin/skills/lisa-project-ideation/examples/host-project-only.md +22 -0
- package/plugins/lisa-devin/skills/lisa-project-ideation/examples/idempotency-verification-harness.md +57 -0
- package/plugins/lisa-devin/skills/lisa-project-ideation/examples/public-external-inspiration.md +22 -0
- package/plugins/lisa-devin/skills/lisa-project-ideation/examples/unavailable-data-rejection.md +22 -0
- package/plugins/lisa-devin/skills/lisa-pull-request-review/SKILL.md +132 -0
- package/plugins/lisa-devin/skills/lisa-quality-review/SKILL.md +63 -0
- package/plugins/lisa-devin/skills/lisa-queue-status/SKILL.md +215 -0
- package/plugins/lisa-devin/skills/lisa-remote-dispatch/SKILL.md +109 -0
- package/plugins/lisa-devin/skills/lisa-remote-dispatch/scripts/dispatch.mjs +535 -0
- package/plugins/lisa-devin/skills/lisa-repair-intake/SKILL.md +1621 -0
- package/plugins/lisa-devin/skills/lisa-reproduce-bug/SKILL.md +75 -0
- package/plugins/lisa-devin/skills/lisa-research/SKILL.md +92 -0
- package/plugins/lisa-devin/skills/lisa-review-implementation/SKILL.md +209 -0
- package/plugins/lisa-devin/skills/lisa-review-local/SKILL.md +141 -0
- package/plugins/lisa-devin/skills/lisa-rework-triage/SKILL.md +206 -0
- package/plugins/lisa-devin/skills/lisa-root-cause-analysis/SKILL.md +135 -0
- package/plugins/lisa-devin/skills/lisa-secrets-access/SKILL.md +430 -0
- package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/aws-bootstrap.mjs +433 -0
- package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/bootstrap-store.mjs +288 -0
- package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/doctor-secrets.mjs +273 -0
- package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/envfile.mjs +80 -0
- package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/inspect-vault.mjs +142 -0
- package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +1085 -0
- package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/note-format.mjs +179 -0
- package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/owner.mjs +96 -0
- package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/preflight-secrets.mjs +342 -0
- package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/prompt-secret.mjs +79 -0
- package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/providers.mjs +805 -0
- package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +680 -0
- package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/read-secret-note.mjs +105 -0
- package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/resolve-expo-token.mjs +90 -0
- package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/resolve-secret.mjs +285 -0
- package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/rotate-secret.mjs +297 -0
- package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/routing-floor.mjs +153 -0
- package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/surfaces.mjs +480 -0
- package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/sync-secret-to-ci.mjs +510 -0
- package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/tools-from-notes.mjs +63 -0
- package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/validate-config.mjs +550 -0
- package/plugins/lisa-devin/skills/lisa-security-review/SKILL.md +124 -0
- package/plugins/lisa-devin/skills/lisa-security-zap-scan/SKILL.md +53 -0
- package/plugins/lisa-devin/skills/lisa-sentry-access/SKILL.md +140 -0
- package/plugins/lisa-devin/skills/lisa-setup-atlassian/SKILL.md +407 -0
- package/plugins/lisa-devin/skills/lisa-setup-automations/SKILL.md +430 -0
- package/plugins/lisa-devin/skills/lisa-setup-automations/scripts/generate-workflow.mjs +288 -0
- package/plugins/lisa-devin/skills/lisa-setup-confluence/SKILL.md +254 -0
- package/plugins/lisa-devin/skills/lisa-setup-github/SKILL.md +319 -0
- package/plugins/lisa-devin/skills/lisa-setup-github-repo/SKILL.md +128 -0
- package/plugins/lisa-devin/skills/lisa-setup-jira/SKILL.md +198 -0
- package/plugins/lisa-devin/skills/lisa-setup-kane/SKILL.md +96 -0
- package/plugins/lisa-devin/skills/lisa-setup-linear/SKILL.md +375 -0
- package/plugins/lisa-devin/skills/lisa-setup-local-env/SKILL.md +95 -0
- package/plugins/lisa-devin/skills/lisa-setup-local-env/scripts/local-env.mjs +196 -0
- package/plugins/lisa-devin/skills/lisa-setup-notion/SKILL.md +376 -0
- package/plugins/lisa-devin/skills/lisa-setup-remote-aws/SKILL.md +149 -0
- package/plugins/lisa-devin/skills/lisa-setup-remote-env/SKILL.md +382 -0
- package/plugins/lisa-devin/skills/lisa-setup-remote-env/assets/materialized-env-authority.mjs +262 -0
- package/plugins/lisa-devin/skills/lisa-setup-remote-env/assets/session-start.sh +87 -0
- package/plugins/lisa-devin/skills/lisa-setup-remote-env/assets/setup.sh +216 -0
- package/plugins/lisa-devin/skills/lisa-setup-remote-env/scripts/environment.mjs +227 -0
- package/plugins/lisa-devin/skills/lisa-setup-remote-env/scripts/preflight-tools.mjs +378 -0
- package/plugins/lisa-devin/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +1632 -0
- package/plugins/lisa-devin/skills/lisa-setup-remote-env/scripts/tool-floor.mjs +94 -0
- package/plugins/lisa-devin/skills/lisa-setup-remote-env/scripts/toolchain.mjs +448 -0
- package/plugins/lisa-devin/skills/lisa-setup-remote-env/scripts/verify-remote-env.mjs +250 -0
- package/plugins/lisa-devin/skills/lisa-setup-sonar/SKILL.md +153 -0
- package/plugins/lisa-devin/skills/lisa-setup-workstation/SKILL.md +143 -0
- package/plugins/lisa-devin/skills/lisa-setup-workstation/scripts/bounded-child.mjs +168 -0
- package/plugins/lisa-devin/skills/lisa-setup-workstation/scripts/catalogue.mjs +293 -0
- package/plugins/lisa-devin/skills/lisa-setup-workstation/scripts/cli.mjs +333 -0
- package/plugins/lisa-devin/skills/lisa-setup-workstation/scripts/workstation.mjs +511 -0
- package/plugins/lisa-devin/skills/lisa-sonarcloud-access/SKILL.md +202 -0
- package/plugins/lisa-devin/skills/lisa-spec-conformance/SKILL.md +205 -0
- package/plugins/lisa-devin/skills/lisa-starter-sync/SKILL.md +35 -0
- package/plugins/lisa-devin/skills/lisa-sync-down/SKILL.md +209 -0
- package/plugins/lisa-devin/skills/lisa-task-decomposition/SKILL.md +195 -0
- package/plugins/lisa-devin/skills/lisa-task-triage/SKILL.md +23 -0
- package/plugins/lisa-devin/skills/lisa-tdd-implementation/SKILL.md +91 -0
- package/plugins/lisa-devin/skills/lisa-tear-down-automations/SKILL.md +85 -0
- package/plugins/lisa-devin/skills/lisa-test-strategy/SKILL.md +66 -0
- package/plugins/lisa-devin/skills/lisa-ticket-triage/SKILL.md +214 -0
- package/plugins/lisa-devin/skills/lisa-track/SKILL.md +129 -0
- package/plugins/lisa-devin/skills/lisa-tracker-add-journey/SKILL.md +28 -0
- package/plugins/lisa-devin/skills/lisa-tracker-build-intake/SKILL.md +134 -0
- package/plugins/lisa-devin/skills/lisa-tracker-claim/SKILL.md +35 -0
- package/plugins/lisa-devin/skills/lisa-tracker-create/SKILL.md +28 -0
- package/plugins/lisa-devin/skills/lisa-tracker-evidence/SKILL.md +63 -0
- package/plugins/lisa-devin/skills/lisa-tracker-journey/SKILL.md +27 -0
- package/plugins/lisa-devin/skills/lisa-tracker-read/SKILL.md +28 -0
- package/plugins/lisa-devin/skills/lisa-tracker-source-artifacts/SKILL.md +111 -0
- package/plugins/lisa-devin/skills/lisa-tracker-sync/SKILL.md +150 -0
- package/plugins/lisa-devin/skills/lisa-tracker-validate/SKILL.md +37 -0
- package/plugins/lisa-devin/skills/lisa-tracker-verify/SKILL.md +29 -0
- package/plugins/lisa-devin/skills/lisa-tracker-write/SKILL.md +55 -0
- package/plugins/lisa-devin/skills/lisa-usage-accounting/SKILL.md +205 -0
- package/plugins/lisa-devin/skills/lisa-usage-accounting/references/effectiveness.md +63 -0
- package/plugins/lisa-devin/skills/lisa-use-the-product/SKILL.md +86 -0
- package/plugins/lisa-devin/skills/lisa-validate-tracker-mapping/SKILL.md +467 -0
- package/plugins/lisa-devin/skills/lisa-verification-lifecycle/SKILL.md +384 -0
- package/plugins/lisa-devin/skills/lisa-verify/SKILL.md +55 -0
- package/plugins/lisa-devin/skills/lisa-verify-prd/SKILL.md +394 -0
- package/plugins/lisa-devin/skills/lisa-verify-workflow-change/SKILL.md +154 -0
- package/plugins/lisa-devin/skills/lisa-wiki-install/SKILL.md +101 -0
- 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-expo-devin/.claude-plugin/plugin.json +11 -0
- package/plugins/lisa-expo-devin/.devin-plugin/plugin.json +8 -0
- package/plugins/lisa-expo-devin/.mcp.json +8 -0
- package/plugins/lisa-expo-devin/THIRD-PARTY-NOTICES.md +84 -0
- package/plugins/lisa-expo-devin/agents/ops-specialist.md +124 -0
- package/plugins/lisa-expo-devin/hooks/devin-tool-name-shim.sh +30 -0
- package/plugins/lisa-expo-devin/hooks/register-maestro-mcp.sh +84 -0
- package/plugins/lisa-expo-devin/hooks.json +14 -0
- package/plugins/lisa-expo-devin/skills/add-app-clip/SKILL.md +280 -0
- package/plugins/lisa-expo-devin/skills/add-app-clip/references/native-module.md +96 -0
- package/plugins/lisa-expo-devin/skills/apollo-client/SKILL.md +238 -0
- package/plugins/lisa-expo-devin/skills/apollo-client/references/mutation-patterns.md +360 -0
- package/plugins/lisa-expo-devin/skills/atomic-design-gluestack/SKILL.md +369 -0
- package/plugins/lisa-expo-devin/skills/atomic-design-gluestack/references/atomic-levels.md +417 -0
- package/plugins/lisa-expo-devin/skills/atomic-design-gluestack/references/folder-structure.md +257 -0
- package/plugins/lisa-expo-devin/skills/atomic-design-gluestack/references/gluestack-mapping.md +233 -0
- package/plugins/lisa-expo-devin/skills/atomic-design-gluestack/scripts/test_validate_atomic_structure.py +240 -0
- package/plugins/lisa-expo-devin/skills/atomic-design-gluestack/scripts/validate_atomic_structure.py +438 -0
- package/plugins/lisa-expo-devin/skills/building-native-ui/SKILL.md +321 -0
- package/plugins/lisa-expo-devin/skills/building-native-ui/references/animations.md +220 -0
- package/plugins/lisa-expo-devin/skills/building-native-ui/references/controls.md +272 -0
- package/plugins/lisa-expo-devin/skills/building-native-ui/references/form-sheet.md +253 -0
- package/plugins/lisa-expo-devin/skills/building-native-ui/references/gradients.md +106 -0
- package/plugins/lisa-expo-devin/skills/building-native-ui/references/icons.md +213 -0
- package/plugins/lisa-expo-devin/skills/building-native-ui/references/media.md +198 -0
- package/plugins/lisa-expo-devin/skills/building-native-ui/references/route-structure.md +229 -0
- package/plugins/lisa-expo-devin/skills/building-native-ui/references/search.md +248 -0
- package/plugins/lisa-expo-devin/skills/building-native-ui/references/storage.md +121 -0
- package/plugins/lisa-expo-devin/skills/building-native-ui/references/tabs.md +433 -0
- package/plugins/lisa-expo-devin/skills/building-native-ui/references/toolbar-and-headers.md +284 -0
- package/plugins/lisa-expo-devin/skills/building-native-ui/references/visual-effects.md +197 -0
- package/plugins/lisa-expo-devin/skills/building-native-ui/references/webgpu-three.md +605 -0
- package/plugins/lisa-expo-devin/skills/building-native-ui/references/zoom-transitions.md +158 -0
- package/plugins/lisa-expo-devin/skills/container-view-pattern/SKILL.md +355 -0
- package/plugins/lisa-expo-devin/skills/container-view-pattern/references/examples.md +749 -0
- package/plugins/lisa-expo-devin/skills/container-view-pattern/references/patterns.md +318 -0
- package/plugins/lisa-expo-devin/skills/container-view-pattern/scripts/create_component.py +200 -0
- package/plugins/lisa-expo-devin/skills/container-view-pattern/scripts/validate_component.py +332 -0
- package/plugins/lisa-expo-devin/skills/cross-platform-compatibility/SKILL.md +268 -0
- package/plugins/lisa-expo-devin/skills/cross-platform-compatibility/references/common-issues.md +619 -0
- package/plugins/lisa-expo-devin/skills/cross-platform-compatibility/references/file-extensions.md +340 -0
- package/plugins/lisa-expo-devin/skills/cross-platform-compatibility/references/platform-api.md +276 -0
- package/plugins/lisa-expo-devin/skills/cross-platform-compatibility/scripts/validate_cross_platform.py +416 -0
- package/plugins/lisa-expo-devin/skills/directory-structure/SKILL.md +214 -0
- package/plugins/lisa-expo-devin/skills/directory-structure/scripts/validate_structure.py +454 -0
- package/plugins/lisa-expo-devin/skills/e2e-coverage-gaps/SKILL.md +117 -0
- package/plugins/lisa-expo-devin/skills/eas-update-insights/SKILL.md +228 -0
- package/plugins/lisa-expo-devin/skills/eas-update-insights/references/channel-insights-schema.md +47 -0
- package/plugins/lisa-expo-devin/skills/eas-update-insights/references/update-insights-schema.md +69 -0
- package/plugins/lisa-expo-devin/skills/expo-api-routes/SKILL.md +369 -0
- package/plugins/lisa-expo-devin/skills/expo-brownfield/SKILL.md +54 -0
- package/plugins/lisa-expo-devin/skills/expo-brownfield/references/brownfield-integrated.md +526 -0
- package/plugins/lisa-expo-devin/skills/expo-brownfield/references/brownfield-isolated.md +402 -0
- package/plugins/lisa-expo-devin/skills/expo-brownfield/references/comparison.md +63 -0
- package/plugins/lisa-expo-devin/skills/expo-brownfield/references/troubleshooting.md +88 -0
- package/plugins/lisa-expo-devin/skills/expo-cicd-workflows/SKILL.md +92 -0
- package/plugins/lisa-expo-devin/skills/expo-cicd-workflows/scripts/fetch.js +113 -0
- package/plugins/lisa-expo-devin/skills/expo-cicd-workflows/scripts/package.json +11 -0
- package/plugins/lisa-expo-devin/skills/expo-cicd-workflows/scripts/validate.js +85 -0
- package/plugins/lisa-expo-devin/skills/expo-deployment/SKILL.md +193 -0
- package/plugins/lisa-expo-devin/skills/expo-deployment/references/app-store-metadata.md +479 -0
- package/plugins/lisa-expo-devin/skills/expo-deployment/references/ios-app-store.md +355 -0
- package/plugins/lisa-expo-devin/skills/expo-deployment/references/play-store.md +264 -0
- package/plugins/lisa-expo-devin/skills/expo-deployment/references/testflight.md +58 -0
- package/plugins/lisa-expo-devin/skills/expo-deployment/references/workflows.md +200 -0
- package/plugins/lisa-expo-devin/skills/expo-dev-client/SKILL.md +164 -0
- package/plugins/lisa-expo-devin/skills/expo-env-config/SKILL.md +309 -0
- package/plugins/lisa-expo-devin/skills/expo-env-config/references/validation-patterns.md +417 -0
- package/plugins/lisa-expo-devin/skills/expo-module/SKILL.md +141 -0
- package/plugins/lisa-expo-devin/skills/expo-module/references/config-plugin.md +90 -0
- package/plugins/lisa-expo-devin/skills/expo-module/references/create-expo-module.md +206 -0
- package/plugins/lisa-expo-devin/skills/expo-module/references/lifecycle.md +127 -0
- package/plugins/lisa-expo-devin/skills/expo-module/references/module-config.md +48 -0
- package/plugins/lisa-expo-devin/skills/expo-module/references/native-module.md +286 -0
- package/plugins/lisa-expo-devin/skills/expo-module/references/native-view.md +171 -0
- package/plugins/lisa-expo-devin/skills/expo-router-best-practices/SKILL.md +432 -0
- package/plugins/lisa-expo-devin/skills/expo-router-best-practices/references/official-docs.md +290 -0
- package/plugins/lisa-expo-devin/skills/expo-router-best-practices/references/static-export-verification.md +54 -0
- package/plugins/lisa-expo-devin/skills/expo-router-best-practices/scripts/generate-route.py +171 -0
- package/plugins/lisa-expo-devin/skills/expo-tailwind-setup/SKILL.md +487 -0
- package/plugins/lisa-expo-devin/skills/expo-ui-jetpack-compose/SKILL.md +40 -0
- package/plugins/lisa-expo-devin/skills/expo-ui-swift-ui/SKILL.md +39 -0
- package/plugins/lisa-expo-devin/skills/gluestack-nativewind/SKILL.md +419 -0
- package/plugins/lisa-expo-devin/skills/gluestack-nativewind/references/color-tokens.md +343 -0
- package/plugins/lisa-expo-devin/skills/gluestack-nativewind/references/component-mapping.md +307 -0
- package/plugins/lisa-expo-devin/skills/gluestack-nativewind/references/spacing-scale.md +300 -0
- package/plugins/lisa-expo-devin/skills/gluestack-nativewind/scripts/test_validate_styling.py +240 -0
- package/plugins/lisa-expo-devin/skills/gluestack-nativewind/scripts/validate_styling.py +424 -0
- package/plugins/lisa-expo-devin/skills/jira-add-journey/SKILL.md +140 -0
- package/plugins/lisa-expo-devin/skills/jira-create/SKILL.md +161 -0
- package/plugins/lisa-expo-devin/skills/jira-evidence/SKILL.md +84 -0
- package/plugins/lisa-expo-devin/skills/jira-evidence/scripts/post-evidence.sh +262 -0
- package/plugins/lisa-expo-devin/skills/jira-journey/SKILL.md +196 -0
- package/plugins/lisa-expo-devin/skills/jira-journey/scripts/generate-templates.py +281 -0
- package/plugins/lisa-expo-devin/skills/jira-journey/scripts/parse-plan.py +400 -0
- package/plugins/lisa-expo-devin/skills/jira-verify/SKILL.md +27 -0
- package/plugins/lisa-expo-devin/skills/local-state/SKILL.md +362 -0
- package/plugins/lisa-expo-devin/skills/local-state/references/async-storage.md +505 -0
- package/plugins/lisa-expo-devin/skills/local-state/references/persistence-patterns.md +711 -0
- package/plugins/lisa-expo-devin/skills/local-state/references/reactive-variables.md +446 -0
- package/plugins/lisa-expo-devin/skills/maestro-mcp-setup/SKILL.md +144 -0
- package/plugins/lisa-expo-devin/skills/native-data-fetching/SKILL.md +507 -0
- package/plugins/lisa-expo-devin/skills/native-data-fetching/references/expo-router-loaders.md +344 -0
- package/plugins/lisa-expo-devin/skills/ops-browser-uat/SKILL.md +124 -0
- package/plugins/lisa-expo-devin/skills/ops-check-logs/SKILL.md +217 -0
- package/plugins/lisa-expo-devin/skills/ops-db-ops/SKILL.md +214 -0
- package/plugins/lisa-expo-devin/skills/ops-deploy/SKILL.md +123 -0
- package/plugins/lisa-expo-devin/skills/ops-monitor-errors/SKILL.md +99 -0
- package/plugins/lisa-expo-devin/skills/ops-performance/SKILL.md +165 -0
- package/plugins/lisa-expo-devin/skills/ops-run-local/SKILL.md +169 -0
- package/plugins/lisa-expo-devin/skills/ops-verify-health/SKILL.md +101 -0
- package/plugins/lisa-expo-devin/skills/owasp-zap/SKILL.md +61 -0
- package/plugins/lisa-expo-devin/skills/play-store-access/SKILL.md +226 -0
- package/plugins/lisa-expo-devin/skills/playwright-ci-debugging/SKILL.md +140 -0
- package/plugins/lisa-expo-devin/skills/playwright-selectors/SKILL.md +496 -0
- package/plugins/lisa-expo-devin/skills/reduce-complexity/SKILL.md +251 -0
- package/plugins/lisa-expo-devin/skills/reduce-complexity/references/extraction-strategies.md +456 -0
- package/plugins/lisa-expo-devin/skills/reduce-complexity/references/refactoring-patterns.md +557 -0
- package/plugins/lisa-expo-devin/skills/testing-library/SKILL.md +314 -0
- package/plugins/lisa-expo-devin/skills/testing-library/references/async-patterns.md +420 -0
- package/plugins/lisa-expo-devin/skills/testing-library/references/expo-router-testing.md +556 -0
- package/plugins/lisa-expo-devin/skills/testing-library/references/mocking-patterns.md +612 -0
- package/plugins/lisa-expo-devin/skills/testing-library/references/query-priority.md +291 -0
- package/plugins/lisa-expo-devin/skills/upgrading-expo/SKILL.md +134 -0
- package/plugins/lisa-expo-devin/skills/upgrading-expo/references/expo-av-to-audio.md +132 -0
- package/plugins/lisa-expo-devin/skills/upgrading-expo/references/expo-av-to-video.md +160 -0
- package/plugins/lisa-expo-devin/skills/upgrading-expo/references/native-tabs.md +124 -0
- package/plugins/lisa-expo-devin/skills/upgrading-expo/references/new-architecture.md +79 -0
- package/plugins/lisa-expo-devin/skills/upgrading-expo/references/react-19.md +79 -0
- package/plugins/lisa-expo-devin/skills/upgrading-expo/references/react-compiler.md +59 -0
- package/plugins/lisa-expo-devin/skills/upgrading-expo/references/react-navigation-to-expo-router.md +61 -0
- package/plugins/lisa-expo-devin/skills/use-dom/SKILL.md +417 -0
- 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-harper-fabric-devin/.claude-plugin/plugin.json +11 -0
- package/plugins/lisa-harper-fabric-devin/.devin-plugin/plugin.json +8 -0
- package/plugins/lisa-harper-fabric-devin/generated-artifact-globs.txt +5 -0
- package/plugins/lisa-harper-fabric-devin/hooks/block-generated-artifact-edits.sh +141 -0
- package/plugins/lisa-harper-fabric-devin/hooks/devin-tool-name-shim.sh +30 -0
- package/plugins/lisa-harper-fabric-devin/hooks/enforce-config-extensions.mjs +196 -0
- package/plugins/lisa-harper-fabric-devin/hooks/enforce-config-extensions.sh +46 -0
- package/plugins/lisa-harper-fabric-devin/hooks/inject-rules.sh +27 -0
- package/plugins/lisa-harper-fabric-devin/hooks.json +36 -0
- package/plugins/lisa-harper-fabric-devin/rules/eager/harper-fabric.md +31 -0
- package/plugins/lisa-harper-fabric-devin/rules/reference/harper-fabric.md +52 -0
- package/plugins/lisa-harper-fabric-devin/skills/e2e-coverage-gaps/SKILL.md +117 -0
- package/plugins/lisa-harper-fabric-devin/skills/harper-auth/SKILL.md +368 -0
- package/plugins/lisa-harper-fabric-devin/skills/harper-build-and-deploy/SKILL.md +198 -0
- package/plugins/lisa-harper-fabric-devin/skills/harper-caching/SKILL.md +265 -0
- package/plugins/lisa-harper-fabric-devin/skills/harper-component-model/SKILL.md +87 -0
- package/plugins/lisa-harper-fabric-devin/skills/harper-config-yaml/SKILL.md +283 -0
- package/plugins/lisa-harper-fabric-devin/skills/harper-operations/SKILL.md +239 -0
- package/plugins/lisa-harper-fabric-devin/skills/harper-realtime/SKILL.md +187 -0
- package/plugins/lisa-harper-fabric-devin/skills/harper-resources/SKILL.md +142 -0
- package/plugins/lisa-harper-fabric-devin/skills/harper-rest-queries/SKILL.md +403 -0
- package/plugins/lisa-harper-fabric-devin/skills/harper-schema-graphql/SKILL.md +123 -0
- package/plugins/lisa-harper-fabric-devin/skills/harper-testing/SKILL.md +254 -0
- 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-nestjs-devin/.claude-plugin/plugin.json +11 -0
- package/plugins/lisa-nestjs-devin/.devin-plugin/plugin.json +8 -0
- package/plugins/lisa-nestjs-devin/hooks/block-migration-edits.sh +125 -0
- package/plugins/lisa-nestjs-devin/hooks/devin-tool-name-shim.sh +30 -0
- package/plugins/lisa-nestjs-devin/hooks/lisa-edit-gate.sh +152 -0
- package/plugins/lisa-nestjs-devin/hooks.json +15 -0
- package/plugins/lisa-nestjs-devin/skills/nestjs-graphql/SKILL.md +176 -0
- package/plugins/lisa-nestjs-devin/skills/nestjs-graphql/references/advanced-features.md +527 -0
- package/plugins/lisa-nestjs-devin/skills/nestjs-graphql/references/project-patterns.md +531 -0
- package/plugins/lisa-nestjs-devin/skills/nestjs-graphql/references/quick-start.md +257 -0
- package/plugins/lisa-nestjs-devin/skills/nestjs-graphql/references/resolvers-mutations.md +413 -0
- package/plugins/lisa-nestjs-devin/skills/nestjs-graphql/references/types-scalars.md +513 -0
- package/plugins/lisa-nestjs-devin/skills/nestjs-rules/SKILL.md +560 -0
- package/plugins/lisa-nestjs-devin/skills/typeorm-patterns/SKILL.md +275 -0
- package/plugins/lisa-nestjs-devin/skills/typeorm-patterns/references/configuration-patterns.md +487 -0
- package/plugins/lisa-nestjs-devin/skills/typeorm-patterns/references/entity-patterns.md +450 -0
- package/plugins/lisa-nestjs-devin/skills/typeorm-patterns/references/observability-patterns.md +536 -0
- 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-openclaw-devin/.claude-plugin/plugin.json +8 -0
- package/plugins/lisa-openclaw-devin/.devin-plugin/plugin.json +8 -0
- package/plugins/lisa-openclaw-devin/skills/lisa-openclaw-connect-repo-topic/SKILL.md +163 -0
- package/plugins/lisa-openclaw-devin/skills/lisa-openclaw-connect-repo-topic/references/repo-topic-config.md +185 -0
- package/plugins/lisa-openclaw-devin/skills/lisa-openclaw-connect-staff/SKILL.md +175 -0
- package/plugins/lisa-openclaw-devin/skills/lisa-openclaw-connect-staff/references/platform-routing.md +123 -0
- package/plugins/lisa-openclaw-devin/skills/lisa-openclaw-connect-staff/references/prompts.md +78 -0
- package/plugins/lisa-openclaw-devin/skills/lisa-openclaw-setup/SKILL.md +141 -0
- 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-phaser-devin/.claude-plugin/plugin.json +11 -0
- package/plugins/lisa-phaser-devin/.devin-plugin/plugin.json +8 -0
- package/plugins/lisa-phaser-devin/agents/accessibility-advocate.md +55 -0
- package/plugins/lisa-phaser-devin/agents/art-director.md +90 -0
- package/plugins/lisa-phaser-devin/agents/audio-director.md +65 -0
- package/plugins/lisa-phaser-devin/agents/combat-designer.md +61 -0
- package/plugins/lisa-phaser-devin/agents/economy-designer.md +59 -0
- package/plugins/lisa-phaser-devin/agents/game-designer.md +62 -0
- package/plugins/lisa-phaser-devin/agents/game-feel-specialist.md +56 -0
- package/plugins/lisa-phaser-devin/agents/level-designer.md +59 -0
- package/plugins/lisa-phaser-devin/agents/localization-manager.md +61 -0
- package/plugins/lisa-phaser-devin/agents/marketing-strategist.md +59 -0
- package/plugins/lisa-phaser-devin/agents/monetization-designer.md +59 -0
- package/plugins/lisa-phaser-devin/agents/narrative-designer.md +56 -0
- package/plugins/lisa-phaser-devin/agents/onboarding-advocate.md +59 -0
- package/plugins/lisa-phaser-devin/agents/player-advocate.md +57 -0
- package/plugins/lisa-phaser-devin/agents/producer.md +61 -0
- package/plugins/lisa-phaser-devin/agents/product-analyst.md +62 -0
- package/plugins/lisa-phaser-devin/agents/publisher.md +59 -0
- package/plugins/lisa-phaser-devin/agents/qa-playtester.md +57 -0
- package/plugins/lisa-phaser-devin/agents/target-player.md +52 -0
- package/plugins/lisa-phaser-devin/agents/ux-ui-designer.md +60 -0
- package/plugins/lisa-phaser-devin/hooks/devin-tool-name-shim.sh +30 -0
- package/plugins/lisa-phaser-devin/hooks/inject-rules.sh +27 -0
- package/plugins/lisa-phaser-devin/hooks.json +14 -0
- package/plugins/lisa-phaser-devin/rules/eager/phaser.md +44 -0
- package/plugins/lisa-phaser-devin/rules/reference/phaser.md +184 -0
- package/plugins/lisa-phaser-devin/skills/phaser-accessibility/SKILL.md +135 -0
- package/plugins/lisa-phaser-devin/skills/phaser-asset-pipeline/SKILL.md +222 -0
- package/plugins/lisa-phaser-devin/skills/phaser-asset-sourcing/SKILL.md +151 -0
- package/plugins/lisa-phaser-devin/skills/phaser-build-deploy/SKILL.md +153 -0
- package/plugins/lisa-phaser-devin/skills/phaser-i18n/SKILL.md +122 -0
- package/plugins/lisa-phaser-devin/skills/phaser-project-structure/SKILL.md +89 -0
- package/plugins/lisa-phaser-devin/skills/phaser-services/SKILL.md +208 -0
- package/plugins/lisa-phaser-devin/skills/phaser-testing/SKILL.md +192 -0
- 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-rails-devin/.claude-plugin/plugin.json +11 -0
- package/plugins/lisa-rails-devin/.devin-plugin/plugin.json +8 -0
- package/plugins/lisa-rails-devin/agents/ops-specialist.md +226 -0
- package/plugins/lisa-rails-devin/hooks/devin-tool-name-shim.sh +30 -0
- package/plugins/lisa-rails-devin/hooks/inject-rules.sh +40 -0
- package/plugins/lisa-rails-devin/hooks/lisa-edit-gate.sh +152 -0
- package/plugins/lisa-rails-devin/hooks/rubocop-on-edit.sh +101 -0
- package/plugins/lisa-rails-devin/hooks/sg-scan-on-edit.sh +97 -0
- package/plugins/lisa-rails-devin/hooks.json +29 -0
- package/plugins/lisa-rails-devin/rules/eager/rails-conventions.md +23 -0
- package/plugins/lisa-rails-devin/rules/reference/rails-conventions.md +176 -0
- package/plugins/lisa-rails-devin/skills/action-controller-best-practices/SKILL.md +374 -0
- package/plugins/lisa-rails-devin/skills/action-view-best-practices/SKILL.md +335 -0
- package/plugins/lisa-rails-devin/skills/active-record-model-best-practices/SKILL.md +166 -0
- package/plugins/lisa-rails-devin/skills/e2e-coverage-gaps/SKILL.md +117 -0
- package/plugins/lisa-rails-devin/skills/fix-linter-error/SKILL.md +45 -0
- package/plugins/lisa-rails-devin/skills/improve-code-complexity/SKILL.md +51 -0
- package/plugins/lisa-rails-devin/skills/improve-max-lines/SKILL.md +46 -0
- package/plugins/lisa-rails-devin/skills/improve-max-lines-per-function/SKILL.md +46 -0
- package/plugins/lisa-rails-devin/skills/improve-test-coverage/SKILL.md +48 -0
- package/plugins/lisa-rails-devin/skills/jira-add-journey/SKILL.md +79 -0
- package/plugins/lisa-rails-devin/skills/jira-create/SKILL.md +100 -0
- package/plugins/lisa-rails-devin/skills/jira-evidence/SKILL.md +76 -0
- package/plugins/lisa-rails-devin/skills/jira-evidence/scripts/post-evidence.sh +262 -0
- package/plugins/lisa-rails-devin/skills/jira-journey/SKILL.md +65 -0
- package/plugins/lisa-rails-devin/skills/jira-verify/SKILL.md +26 -0
- package/plugins/lisa-rails-devin/skills/ops-check-logs/SKILL.md +191 -0
- package/plugins/lisa-rails-devin/skills/ops-deploy/SKILL.md +153 -0
- package/plugins/lisa-rails-devin/skills/ops-run-local/SKILL.md +169 -0
- package/plugins/lisa-rails-devin/skills/ops-verify-jobs/SKILL.md +157 -0
- package/plugins/lisa-rails-devin/skills/ops-verify-telemetry/SKILL.md +226 -0
- 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-typescript-devin/.claude-plugin/plugin.json +11 -0
- package/plugins/lisa-typescript-devin/.devin-plugin/plugin.json +8 -0
- package/plugins/lisa-typescript-devin/hooks/block-suppress-directives.sh +141 -0
- package/plugins/lisa-typescript-devin/hooks/devin-tool-name-shim.sh +30 -0
- package/plugins/lisa-typescript-devin/hooks/format-on-edit.sh +102 -0
- package/plugins/lisa-typescript-devin/hooks/lint-on-edit.sh +117 -0
- package/plugins/lisa-typescript-devin/hooks/lisa-edit-gate.sh +152 -0
- package/plugins/lisa-typescript-devin/hooks/sg-scan-on-edit.sh +94 -0
- package/plugins/lisa-typescript-devin/hooks.json +34 -0
- 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/lisa-wiki-devin/.claude-plugin/plugin.json +8 -0
- package/plugins/lisa-wiki-devin/.devin-plugin/plugin.json +8 -0
- package/plugins/lisa-wiki-devin/ci/lisa-wiki-validate.yml +33 -0
- package/plugins/lisa-wiki-devin/schema/lisa-wiki-config.schema.json +162 -0
- package/plugins/lisa-wiki-devin/schema/wiki-structure.schema.json +51 -0
- package/plugins/lisa-wiki-devin/scripts/_wiki-lib.mjs +204 -0
- package/plugins/lisa-wiki-devin/scripts/diff-guard.mjs +117 -0
- package/plugins/lisa-wiki-devin/scripts/ensure-gitignore.mjs +131 -0
- package/plugins/lisa-wiki-devin/scripts/ensure-wiki.mjs +268 -0
- package/plugins/lisa-wiki-devin/scripts/ingest-git.mjs +198 -0
- package/plugins/lisa-wiki-devin/scripts/ingest-memory.mjs +135 -0
- package/plugins/lisa-wiki-devin/scripts/ingest-roles.mjs +95 -0
- package/plugins/lisa-wiki-devin/scripts/ingest_slack_channel.py +361 -0
- package/plugins/lisa-wiki-devin/scripts/lib/bounded-child.mjs +159 -0
- package/plugins/lisa-wiki-devin/scripts/lint-wiki.mjs +513 -0
- package/plugins/lisa-wiki-devin/scripts/mcp-doctor.mjs +72 -0
- package/plugins/lisa-wiki-devin/scripts/render-contract.mjs +107 -0
- package/plugins/lisa-wiki-devin/scripts/rewrite-refs.mjs +144 -0
- package/plugins/lisa-wiki-devin/scripts/slack_oauth_user.py +179 -0
- package/plugins/lisa-wiki-devin/scripts/validate-config.mjs +321 -0
- package/plugins/lisa-wiki-devin/scripts/verify-migration.mjs +203 -0
- package/plugins/lisa-wiki-devin/scripts/verify-wiki-safety.mjs +126 -0
- package/plugins/lisa-wiki-devin/scripts/wiki-safety.mjs +378 -0
- package/plugins/lisa-wiki-devin/scripts/wiki-status.mjs +345 -0
- package/plugins/lisa-wiki-devin/skills/lisa-wiki-add-ingest/SKILL.md +34 -0
- package/plugins/lisa-wiki-devin/skills/lisa-wiki-add-role/SKILL.md +35 -0
- package/plugins/lisa-wiki-devin/skills/lisa-wiki-connector-confluence/SKILL.md +25 -0
- package/plugins/lisa-wiki-devin/skills/lisa-wiki-connector-docs/SKILL.md +30 -0
- package/plugins/lisa-wiki-devin/skills/lisa-wiki-connector-git/SKILL.md +25 -0
- package/plugins/lisa-wiki-devin/skills/lisa-wiki-connector-jira/SKILL.md +28 -0
- package/plugins/lisa-wiki-devin/skills/lisa-wiki-connector-memory/SKILL.md +28 -0
- package/plugins/lisa-wiki-devin/skills/lisa-wiki-connector-notion/SKILL.md +25 -0
- package/plugins/lisa-wiki-devin/skills/lisa-wiki-connector-roles/SKILL.md +22 -0
- package/plugins/lisa-wiki-devin/skills/lisa-wiki-connector-slack/SKILL.md +30 -0
- package/plugins/lisa-wiki-devin/skills/lisa-wiki-connector-web/SKILL.md +23 -0
- package/plugins/lisa-wiki-devin/skills/lisa-wiki-doctor/SKILL.md +47 -0
- package/plugins/lisa-wiki-devin/skills/lisa-wiki-ingest/SKILL.md +106 -0
- package/plugins/lisa-wiki-devin/skills/lisa-wiki-lint/SKILL.md +32 -0
- package/plugins/lisa-wiki-devin/skills/lisa-wiki-migrate/SKILL.md +43 -0
- package/plugins/lisa-wiki-devin/skills/lisa-wiki-onboard-me/SKILL.md +33 -0
- package/plugins/lisa-wiki-devin/skills/lisa-wiki-query/SKILL.md +40 -0
- package/plugins/lisa-wiki-devin/skills/lisa-wiki-setup/SKILL.md +75 -0
- package/plugins/lisa-wiki-devin/skills/lisa-wiki-setup-automations/SKILL.md +83 -0
- package/plugins/lisa-wiki-devin/skills/lisa-wiki-status/SKILL.md +47 -0
- package/plugins/lisa-wiki-devin/skills/lisa-wiki-tear-down-automations/SKILL.md +34 -0
- package/plugins/lisa-wiki-devin/skills/lisa-wiki-usage/SKILL.md +50 -0
- package/plugins/lisa-wiki-devin/templates/agents/role-agent.claude.md +16 -0
- package/plugins/lisa-wiki-devin/templates/agents/role-agent.codex.toml +15 -0
- package/plugins/lisa-wiki-devin/templates/index.md +17 -0
- package/plugins/lisa-wiki-devin/templates/llm-wiki-contract.md +72 -0
- package/plugins/lisa-wiki-devin/templates/log.md +8 -0
- package/plugins/lisa-wiki-devin/templates/page-types/architecture.md +18 -0
- package/plugins/lisa-wiki-devin/templates/page-types/concept.md +18 -0
- package/plugins/lisa-wiki-devin/templates/page-types/decision.md +18 -0
- package/plugins/lisa-wiki-devin/templates/page-types/entity.md +19 -0
- package/plugins/lisa-wiki-devin/templates/page-types/open-question.md +18 -0
- package/plugins/lisa-wiki-devin/templates/page-types/playbook.md +18 -0
- package/plugins/lisa-wiki-devin/templates/page-types/project.md +19 -0
- package/plugins/lisa-wiki-devin/templates/page-types/requirement.md +19 -0
- package/plugins/lisa-wiki-devin/templates/page-types/staff.md +26 -0
- package/plugins/lisa-wiki-devin/templates/start-here.md +24 -0
- package/plugins/lisa-wiki-devin/templates/state-readme.md +20 -0
- package/plugins/lisa-wiki-devin/templates/wrapper-gitignore.txt +19 -0
- package/scripts/build-plugins.sh +2 -2
- package/scripts/deployed-guard-advice.mjs +1 -0
- package/scripts/generate-devin-plugin-artifacts.mjs +263 -0
- package/scripts/lib/hook-registration-audit.mjs +3 -1
- package/scripts/lib/per-agent-hook-filter.mjs +174 -5
- package/scripts/lib/plugin-rule-citations.mjs +2 -2
|
@@ -0,0 +1,1065 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Blocker re-probe gate for pre-work build-intake candidates.
|
|
4
|
+
*
|
|
5
|
+
* A blocker is a claim with a timestamp, not a fact. It is written once, and it
|
|
6
|
+
* decays the moment its condition goes true — a dependency lands on trunk, a
|
|
7
|
+
* CVE gets patched, a package publishes. Nothing in the old intake loop ever
|
|
8
|
+
* re-read one, so a discharged blocker held its item out of the queue forever.
|
|
9
|
+
*
|
|
10
|
+
* This module decides, per candidate, whether intake may select it. It never
|
|
11
|
+
* probes anything itself: the caller runs the probe and hands back the result,
|
|
12
|
+
* which keeps the decision auditable and testable apart from the network.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { isPreWorkLaneType } from "./intake-prework-denominator.mjs";
|
|
16
|
+
|
|
17
|
+
/** Marker a writer stamps on an item a human deliberately parked. */
|
|
18
|
+
export const HUMAN_GATE_MARKER = "[lisa-human-gate]";
|
|
19
|
+
|
|
20
|
+
/** Default label naming a block only a human can clear. */
|
|
21
|
+
export const DEFAULT_HUMAN_NEEDED_LABEL = "human-needed";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {unknown} labels
|
|
25
|
+
* @returns {readonly string[]}
|
|
26
|
+
*/
|
|
27
|
+
function normalizeLabels(labels) {
|
|
28
|
+
return (Array.isArray(labels) ? labels : [])
|
|
29
|
+
.map(label =>
|
|
30
|
+
typeof label === "string"
|
|
31
|
+
? label
|
|
32
|
+
: typeof label?.name === "string"
|
|
33
|
+
? label.name
|
|
34
|
+
: ""
|
|
35
|
+
)
|
|
36
|
+
.map(label => label.trim().toLowerCase())
|
|
37
|
+
.filter(label => label.length > 0);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Decoration a declaration may sit behind, and nothing more.
|
|
42
|
+
*
|
|
43
|
+
* Whitespace, blockquote arrows, list bullets or numbers, emphasis, a comment
|
|
44
|
+
* hash, and an opening HTML comment. `#` is there on EVIDENCE rather than
|
|
45
|
+
* taste: a shell script declares a hold as `# <marker> reason=…` — a bare
|
|
46
|
+
* marker behind a SHELL comment, with no HTML comment anywhere — and that form
|
|
47
|
+
* is in this repository's own guard fixtures. A single character class plus two
|
|
48
|
+
* optional groups —
|
|
49
|
+
* deliberately not a nested-quantifier pattern, because this runs over
|
|
50
|
+
* untrusted work-item bodies and `sonarjs/slow-regex` is right about that
|
|
51
|
+
* shape.
|
|
52
|
+
*/
|
|
53
|
+
const LEADING_DECORATION =
|
|
54
|
+
/^[ \t>*_+#-]*(?:\d+[.)][ \t]*)?(?:<!--[ \t]*)?[ \t]*/u;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Decode one stored Markdown escape layer without changing the provider record.
|
|
58
|
+
* Linear escapes marker brackets and punctuation in reason keys. A single pass
|
|
59
|
+
* keeps literal backslash pairs intact instead of recursively inventing markers.
|
|
60
|
+
* Callers doing bookkeeping-marker searches use this same projection; hold and
|
|
61
|
+
* release parsers receive original bodies and apply it after excluding code.
|
|
62
|
+
* @param {unknown} body - Original provider text
|
|
63
|
+
* @returns {string} One-pass Markdown punctuation projection
|
|
64
|
+
*/
|
|
65
|
+
export function normalizeProviderMarkdown(body) {
|
|
66
|
+
return String(body ?? "").replace(
|
|
67
|
+
/\\([\u0021-\u002f\u003a-\u0040\u005b-\u0060\u007b-\u007e])/gu,
|
|
68
|
+
"$1"
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The body with fenced blocks and inline code spans removed.
|
|
74
|
+
*
|
|
75
|
+
* Documentation of a declaration is not a declaration, and a fenced example is
|
|
76
|
+
* how the declaration form gets written ABOUT. The same move
|
|
77
|
+
* `pr-arming-sweep.mjs` makes for the auto-merge-off marker
|
|
78
|
+
* (CodySwannGT/lisa#3986), and the same one `block-direct-issue-create.sh`
|
|
79
|
+
* makes when it strips heredoc bodies before tokenising argv.
|
|
80
|
+
* @param {unknown} body - The raw item body
|
|
81
|
+
* @returns {string} The body with quoted and code regions blanked out
|
|
82
|
+
*/
|
|
83
|
+
function declarativeText(body) {
|
|
84
|
+
const withoutCode = String(body ?? "")
|
|
85
|
+
.replace(/```[\s\S]*?```/gu, "")
|
|
86
|
+
.replace(/`[^`\n]*`/gu, "");
|
|
87
|
+
return normalizeProviderMarkdown(withoutCode);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Whether an HTML comment on this line carries the given marker.
|
|
92
|
+
*
|
|
93
|
+
* The second declaration form, and it is not a concession: an HTML comment is
|
|
94
|
+
* invisible when the body is rendered, so nobody writes one to TALK about the
|
|
95
|
+
* marker — a quotation has to be visible to be a quotation. Prose about the
|
|
96
|
+
* marker is written in sentences, code spans and fenced examples, all of which
|
|
97
|
+
* this rule already excludes.
|
|
98
|
+
*
|
|
99
|
+
* Scanned rather than pattern-matched. A regular expression with two lazy
|
|
100
|
+
* `[^\n]*?` runs around a literal is the ambiguous shape this module avoids
|
|
101
|
+
* elsewhere, and an indexOf walk is both linear and easier to be sure about.
|
|
102
|
+
* @param {string} line - One line of the body
|
|
103
|
+
* @param {string} marker - The literal marker to look for
|
|
104
|
+
* @returns {boolean} True when a comment on this line contains the marker
|
|
105
|
+
*/
|
|
106
|
+
function commentCarriesMarker(line, marker) {
|
|
107
|
+
const segments = line.split("<!--");
|
|
108
|
+
for (let index = 1; index < segments.length; index += 1) {
|
|
109
|
+
const close = segments[index].indexOf("-->");
|
|
110
|
+
const inside =
|
|
111
|
+
close === -1 ? segments[index] : segments[index].slice(0, close);
|
|
112
|
+
if (inside.includes(marker)) return true;
|
|
113
|
+
}
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Whether one line DECLARES a hold rather than mentioning one.
|
|
119
|
+
*
|
|
120
|
+
* Two accepted forms, and the corpus says they cost nothing to combine:
|
|
121
|
+
* measured over this repository's 42 matching bodies, line-leading alone and
|
|
122
|
+
* line-leading-or-comment hold the SAME 29. The comment branch exists because
|
|
123
|
+
* the filing guard reads inputs that are not markdown documents — a one-line
|
|
124
|
+
* `--body` string and a shell script — where a declaration legitimately sits
|
|
125
|
+
* after other text on its line.
|
|
126
|
+
* @param {string} line - One line of the body
|
|
127
|
+
* @param {string} [marker] - The declaration marker to test for
|
|
128
|
+
* @returns {boolean} True when the line declares with that marker
|
|
129
|
+
*/
|
|
130
|
+
function declaresOnLine(line, marker = HUMAN_GATE_MARKER) {
|
|
131
|
+
if (line.replace(LEADING_DECORATION, "").startsWith(marker)) {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
return commentCarriesMarker(line, marker);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Count what a body says about the hold marker, split by what it MEANS.
|
|
139
|
+
*
|
|
140
|
+
* ## Why the substring test had to go
|
|
141
|
+
*
|
|
142
|
+
* `isHumanGated` asked one question — does the body contain the marker
|
|
143
|
+
* anywhere — and that form was deliberate, documented, and correct when it was
|
|
144
|
+
* written: *"it is a marker with no other meaning, so its presence IS the
|
|
145
|
+
* declaration."* The premise expired. The marker acquired a second meaning —
|
|
146
|
+
* **being discussed** — the moment the feature became something people file
|
|
147
|
+
* tickets about, so a sentence quoting it, a Gherkin line naming it, and a
|
|
148
|
+
* ticket about it all read as declared holds (CodySwannGT/lisa#3815).
|
|
149
|
+
*
|
|
150
|
+
* The consequence is not one skipped cycle. `planHumanGateReconciliation`
|
|
151
|
+
* removes the ready role and applies the human-needed label, so a false
|
|
152
|
+
* positive rewrites the item's own metadata and every later sweep agrees with
|
|
153
|
+
* the first. And the affected population GROWS with the documentation: 38
|
|
154
|
+
* matching bodies measured 2026-09-04, 42 on 2026-09-05.
|
|
155
|
+
*
|
|
156
|
+
* ## The rule
|
|
157
|
+
*
|
|
158
|
+
* A declaration is POSITIONAL — the marker leads its line, behind at most
|
|
159
|
+
* blockquote, list, emphasis or opening-comment decoration — evaluated after
|
|
160
|
+
* code regions are removed. Measured over this repository's 42 matching bodies:
|
|
161
|
+
* this holds 29 of them and correctly releases the two live ready-lane items
|
|
162
|
+
* that only discussed the marker.
|
|
163
|
+
*
|
|
164
|
+
* The stricter HTML-comment-only rule was measured and REJECTED: it holds only
|
|
165
|
+
* 18, dropping declarations that carry `human-needed` today. Losing a real hold
|
|
166
|
+
* is the unsafe direction and would need a retrofit of the tracker.
|
|
167
|
+
*
|
|
168
|
+
* ## Why it counts rather than answering yes or no
|
|
169
|
+
*
|
|
170
|
+
* A heuristic that silently drops candidates is indistinguishable from one that
|
|
171
|
+
* found none. Every occurrence this rule declines to honour is counted and
|
|
172
|
+
* reported, so "the rule demoted 33 mentions" is a fact an operator can read
|
|
173
|
+
* rather than an absence they must infer.
|
|
174
|
+
* @param {unknown} body - The item body
|
|
175
|
+
* @returns {{ total: number, declared: number, demoted: number }} Occurrences,
|
|
176
|
+
* those that declare a hold, and those demoted to mentions
|
|
177
|
+
*/
|
|
178
|
+
export function humanGateMentions(body) {
|
|
179
|
+
const raw = String(body ?? "");
|
|
180
|
+
const total =
|
|
181
|
+
normalizeProviderMarkdown(raw).split(HUMAN_GATE_MARKER).length - 1;
|
|
182
|
+
const declared = declarativeText(raw)
|
|
183
|
+
.split("\n")
|
|
184
|
+
.filter(line => declaresOnLine(line)).length;
|
|
185
|
+
return { total, declared, demoted: total - declared };
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Whether a body declares a hold, as opposed to discussing one.
|
|
190
|
+
* @param {unknown} body - The item body
|
|
191
|
+
* @returns {boolean} True when at least one line declares a hold
|
|
192
|
+
*/
|
|
193
|
+
export function bodyDeclaresHold(body) {
|
|
194
|
+
return humanGateMentions(body).declared > 0;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Marker a comment carries to DISCHARGE a hold.
|
|
199
|
+
*
|
|
200
|
+
* ## Why a comment and not the body
|
|
201
|
+
*
|
|
202
|
+
* The hold lives in the description, and the only description write this plugin
|
|
203
|
+
* has is a whole-body replacement — re-read everything, change one line, write
|
|
204
|
+
* it all back. On an item carrying acceptance criteria, a validation journey
|
|
205
|
+
* and a managed usage section, "delete one HTML comment" is therefore "rewrite
|
|
206
|
+
* the record and hope nothing was dropped". A release procedure whose only
|
|
207
|
+
* implementation risks destroying what it releases is not a release procedure:
|
|
208
|
+
* the rational move is always to leave the hold, so holds only accumulate
|
|
209
|
+
* (CodySwannGT/lisa#3852).
|
|
210
|
+
*
|
|
211
|
+
* A comment is append-only. It cannot drop a section it never held, and the
|
|
212
|
+
* same reader that reads the hold reads the discharge.
|
|
213
|
+
*
|
|
214
|
+
* ## Why it is not a superstring of the hold marker
|
|
215
|
+
*
|
|
216
|
+
* `HUMAN_GATE_MARKER` closes with `]`, so `[lisa-human-gate-release]` does not
|
|
217
|
+
* contain it. That is load-bearing rather than incidental: a release record
|
|
218
|
+
* that matched the hold test would declare a fresh hold every time one was
|
|
219
|
+
* lifted, which is the same trap `NORMALIZATION_HOLD_NOTE_MARKER` documents.
|
|
220
|
+
*/
|
|
221
|
+
export const HUMAN_GATE_RELEASE_MARKER = "[lisa-human-gate-release]";
|
|
222
|
+
|
|
223
|
+
/** Structured key a hold and its release both name, so they pair up. */
|
|
224
|
+
const REASON_KEY = "reason=";
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* The comparable form of a hold reason.
|
|
228
|
+
*
|
|
229
|
+
* Case and internal whitespace drift between the hand that writes the hold and
|
|
230
|
+
* the hand that writes the release; the identity of the question does not.
|
|
231
|
+
* @param {unknown} value - A raw reason string
|
|
232
|
+
* @returns {string} Its comparable form, empty when there is none
|
|
233
|
+
*/
|
|
234
|
+
function normalizeReason(value) {
|
|
235
|
+
return String(value ?? "")
|
|
236
|
+
.replace(/\s+/gu, " ")
|
|
237
|
+
.trim()
|
|
238
|
+
.toLowerCase();
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* The reason a declaring line names, or the empty key when it names none.
|
|
243
|
+
*
|
|
244
|
+
* A keyless declaration is not a defect to be rejected — markers in the wild
|
|
245
|
+
* carry no `reason=` at all, which is why the hold test is not keyed on one.
|
|
246
|
+
* The empty string is a real key here: a keyless hold is discharged by a
|
|
247
|
+
* keyless release and by nothing else, so the two surfaces stay symmetric
|
|
248
|
+
* whether or not a reason was ever written.
|
|
249
|
+
* @param {string} line - A line already known to declare
|
|
250
|
+
* @param {string} marker - The declaration marker it carries
|
|
251
|
+
* @returns {string} The normalized reason key
|
|
252
|
+
*/
|
|
253
|
+
function reasonOnLine(line, marker) {
|
|
254
|
+
const at = line.indexOf(marker);
|
|
255
|
+
if (at === -1) return "";
|
|
256
|
+
const tail = line.slice(at + marker.length).split("-->")[0];
|
|
257
|
+
const key = tail.indexOf(REASON_KEY);
|
|
258
|
+
if (key === -1) return "";
|
|
259
|
+
return normalizeReason(tail.slice(key + REASON_KEY.length));
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* The reason keys of every hold a body DECLARES, deduplicated.
|
|
264
|
+
*
|
|
265
|
+
* Reuses the precision rule rather than restating it, so a body that merely
|
|
266
|
+
* discusses the marker yields no holds here for the same reason it reads as
|
|
267
|
+
* unheld in {@link bodyDeclaresHold}.
|
|
268
|
+
* @param {unknown} body - The item body
|
|
269
|
+
* @returns {string[]} One key per declared hold
|
|
270
|
+
*/
|
|
271
|
+
export function humanGateHolds(body) {
|
|
272
|
+
const keys = declarativeText(body)
|
|
273
|
+
.split("\n")
|
|
274
|
+
.filter(line => declaresOnLine(line))
|
|
275
|
+
.map(line => reasonOnLine(line, HUMAN_GATE_MARKER));
|
|
276
|
+
return [...new Set(keys)];
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Normalize stable provider IDs without case folding or trusting display names.
|
|
281
|
+
* @param {unknown} value - Provider actor ID
|
|
282
|
+
* @returns {string} Stable comparison key, or empty when invalid
|
|
283
|
+
*/
|
|
284
|
+
function stableActorId(value) {
|
|
285
|
+
if (typeof value === "string") return value.trim();
|
|
286
|
+
return Number.isSafeInteger(value) && value > 0 ? String(value) : "";
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Recognize explicit provider bot metadata even for an allowlisted identity.
|
|
291
|
+
* @param {unknown} actor - Provider or normalized author metadata
|
|
292
|
+
* @returns {boolean} Whether the metadata identifies automation
|
|
293
|
+
*/
|
|
294
|
+
function isKnownBot(actor) {
|
|
295
|
+
if (!actor || typeof actor !== "object") return false;
|
|
296
|
+
const kinds = [
|
|
297
|
+
actor.type,
|
|
298
|
+
actor.__typename,
|
|
299
|
+
actor.accountType,
|
|
300
|
+
actor.authorType,
|
|
301
|
+
];
|
|
302
|
+
return (
|
|
303
|
+
actor.botActor != null ||
|
|
304
|
+
actor.isBot === true ||
|
|
305
|
+
actor.bot === true ||
|
|
306
|
+
kinds.some(kind => /^(?:bot|app)$/i.test(String(kind ?? "").trim()))
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Require authenticated provider identity and separately supplied human trust.
|
|
312
|
+
* Adapters may normalize the ID to authorId, but must preserve bot metadata.
|
|
313
|
+
* Names, body text and self-asserted authorization flags never confer trust.
|
|
314
|
+
* @param {unknown} comment - Structured provider comment
|
|
315
|
+
* @param {ReadonlySet<string>} trustedIds - Explicitly trusted human actor IDs
|
|
316
|
+
* @returns {boolean} Whether the comment may discharge a human hold
|
|
317
|
+
*/
|
|
318
|
+
function isTrustedHumanComment(comment, trustedIds) {
|
|
319
|
+
if (!comment || typeof comment !== "object" || Array.isArray(comment))
|
|
320
|
+
return false;
|
|
321
|
+
if ([comment, comment.user, comment.author].some(isKnownBot)) return false;
|
|
322
|
+
const id = stableActorId(
|
|
323
|
+
comment.authorId ??
|
|
324
|
+
comment.user?.id ??
|
|
325
|
+
comment.author?.id ??
|
|
326
|
+
comment.author?.accountId
|
|
327
|
+
);
|
|
328
|
+
return id.length > 0 && trustedIds.has(id);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* The reason keys released by explicitly trusted human authors, deduplicated.
|
|
333
|
+
*
|
|
334
|
+
* Comments must retain authenticated provider authorship: normalized authorId,
|
|
335
|
+
* user.id, author.id or author.accountId. The caller supplies trusted human IDs
|
|
336
|
+
* independently of comment content. Raw strings, missing IDs, known bots and
|
|
337
|
+
* an absent or empty allowlist fail closed and cannot discharge a hold.
|
|
338
|
+
* @param {unknown} comments - Structured comments, any order
|
|
339
|
+
* @param {unknown} trustedHumanActorIds - Explicit trusted human provider IDs
|
|
340
|
+
* @returns {string[]} One key per authorized recorded release
|
|
341
|
+
*/
|
|
342
|
+
export function humanGateReleases(comments, trustedHumanActorIds = []) {
|
|
343
|
+
const trustedIds = new Set(
|
|
344
|
+
(Array.isArray(trustedHumanActorIds) ? trustedHumanActorIds : [])
|
|
345
|
+
.map(stableActorId)
|
|
346
|
+
.filter(Boolean)
|
|
347
|
+
);
|
|
348
|
+
const bodies = (Array.isArray(comments) ? comments : [])
|
|
349
|
+
.filter(entry => isTrustedHumanComment(entry, trustedIds))
|
|
350
|
+
.map(entry => entry.body ?? "");
|
|
351
|
+
const keys = bodies.flatMap(body =>
|
|
352
|
+
declarativeText(body)
|
|
353
|
+
.split("\n")
|
|
354
|
+
.filter(line => declaresOnLine(line, HUMAN_GATE_RELEASE_MARKER))
|
|
355
|
+
.map(line => reasonOnLine(line, HUMAN_GATE_RELEASE_MARKER))
|
|
356
|
+
);
|
|
357
|
+
return [...new Set(keys)];
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Whether every hold on this item has a release recorded against it.
|
|
362
|
+
*
|
|
363
|
+
* Matching is per-reason on purpose. A blanket "any release clears everything"
|
|
364
|
+
* rule would make a hold declared AFTER a release be born discharged, which is
|
|
365
|
+
* the unsafe direction — the one this fix must not introduce while correcting
|
|
366
|
+
* the safe one. An item with no declared body hold is discharged only by a
|
|
367
|
+
* keyless release, which is the form that pairs with a label-only hold.
|
|
368
|
+
* @param {{ body?: unknown, comments?: unknown, trustedHumanActorIds?: unknown }} input - The item's surfaces
|
|
369
|
+
* @returns {boolean} True when nothing is left outstanding
|
|
370
|
+
*/
|
|
371
|
+
export function humanGateDischarged(input = {}) {
|
|
372
|
+
const released = new Set(
|
|
373
|
+
humanGateReleases(input.comments, input.trustedHumanActorIds)
|
|
374
|
+
);
|
|
375
|
+
const holds = humanGateHolds(input.body);
|
|
376
|
+
if (holds.length === 0) return released.has("");
|
|
377
|
+
return holds.every(reason => released.has(reason));
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* The full held-ness verdict for an item, on every surface that carries a hold.
|
|
382
|
+
*
|
|
383
|
+
* Split out of {@link isHumanGated} because the release path needs to know more
|
|
384
|
+
* than yes-or-no: whether a hold existed at all, which reasons are still
|
|
385
|
+
* outstanding, and whether the durable label needs removing. A caller that only
|
|
386
|
+
* wants the boolean still gets exactly the boolean.
|
|
387
|
+
*
|
|
388
|
+
* The label is treated as a MIRROR of a declared body hold, never as a second
|
|
389
|
+
* independent hold, because that is how it is written: the vendor writers stamp
|
|
390
|
+
* both surfaces for one hold, and `planHumanGateReconciliation` adds the label
|
|
391
|
+
* to an item already carrying the marker. Counting it separately would leave
|
|
392
|
+
* every mirrored hold permanently outstanding under a keyed release — the exact
|
|
393
|
+
* defect this function exists to end, one layer down. Only when the body
|
|
394
|
+
* declares nothing does the label stand as a hold in its own right, and then it
|
|
395
|
+
* is a keyless one.
|
|
396
|
+
*
|
|
397
|
+
* Fails CLOSED on an unreadable discharge: with no comments supplied there are
|
|
398
|
+
* no releases, so a held item stays held. Holding a gate that may be stale
|
|
399
|
+
* beats releasing one that is not, and every caller that never passes comments
|
|
400
|
+
* keeps its current behaviour by construction.
|
|
401
|
+
* @param {{ labels?: unknown, body?: unknown, comments?: unknown, trustedHumanActorIds?: unknown, humanNeededLabel?: unknown }} input - Candidate surfaces
|
|
402
|
+
* @returns {{ held: boolean, reason: string, declared: number, outstanding: string[], released: string[], labelPresent: boolean }} Held-ness verdict
|
|
403
|
+
*/
|
|
404
|
+
export function humanGateVerdict(input = {}) {
|
|
405
|
+
const configured = String(
|
|
406
|
+
input.humanNeededLabel ?? DEFAULT_HUMAN_NEEDED_LABEL
|
|
407
|
+
)
|
|
408
|
+
.trim()
|
|
409
|
+
.toLowerCase();
|
|
410
|
+
const labelPresent =
|
|
411
|
+
configured.length > 0 && normalizeLabels(input.labels).includes(configured);
|
|
412
|
+
const released = humanGateReleases(
|
|
413
|
+
input.comments,
|
|
414
|
+
input.trustedHumanActorIds
|
|
415
|
+
);
|
|
416
|
+
const releasedSet = new Set(released);
|
|
417
|
+
const holds = humanGateHolds(input.body);
|
|
418
|
+
const outstanding = holds.filter(reason => !releasedSet.has(reason));
|
|
419
|
+
const base = {
|
|
420
|
+
declared: holds.length,
|
|
421
|
+
released,
|
|
422
|
+
labelPresent,
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
if (outstanding.length > 0) {
|
|
426
|
+
return { held: true, reason: "hold-outstanding", outstanding, ...base };
|
|
427
|
+
}
|
|
428
|
+
if (holds.length > 0) {
|
|
429
|
+
return { held: false, reason: "hold-released", outstanding: [], ...base };
|
|
430
|
+
}
|
|
431
|
+
if (labelPresent) {
|
|
432
|
+
return releasedSet.has("")
|
|
433
|
+
? { held: false, reason: "hold-released", outstanding: [], ...base }
|
|
434
|
+
: { held: true, reason: "hold-outstanding", outstanding: [""], ...base };
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
return { held: false, reason: "no-hold", outstanding: [], ...base };
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Whether an item is held for a person, on either surface.
|
|
442
|
+
*
|
|
443
|
+
* Exported deliberately, and it is the ONLY answer to that question anywhere in
|
|
444
|
+
* the intake machinery. Every selection and promotion path calls this rather
|
|
445
|
+
* than inspecting labels itself, because the label surface alone is a partial
|
|
446
|
+
* answer: the vendor writers stamp the body marker on a deliberate hold, so an
|
|
447
|
+
* item held exactly as the filing contract instructs carries no label at all.
|
|
448
|
+
* A path that read labels alone judged such an item unheld and promoted it —
|
|
449
|
+
* which is #3805, and is why this is a shared function rather than a shared
|
|
450
|
+
* convention.
|
|
451
|
+
*
|
|
452
|
+
* It is also the only place a hold ENDS, which is why the release lives behind
|
|
453
|
+
* the same call rather than beside it: a reader that could see the hold but not
|
|
454
|
+
* its discharge is how the gate became one-way in the first place. Pass the
|
|
455
|
+
* item's structured comments and trustedHumanActorIds to honor an authorized
|
|
456
|
+
* release; omit either and the item stays held.
|
|
457
|
+
* @param {{ labels?: unknown, body?: unknown, comments?: unknown, trustedHumanActorIds?: unknown, humanNeededLabel?: unknown }} input - Candidate surfaces
|
|
458
|
+
* @returns {boolean} True when a person is holding this item
|
|
459
|
+
*/
|
|
460
|
+
export function isHumanGated(input) {
|
|
461
|
+
return humanGateVerdict(input).held;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* @param {unknown} value
|
|
466
|
+
* @returns {string}
|
|
467
|
+
*/
|
|
468
|
+
function trimmedString(value) {
|
|
469
|
+
return typeof value === "string" ? value.trim() : "";
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* @param {{ discharged?: unknown, evidence?: unknown }} probe
|
|
474
|
+
* @returns {{ selectable: boolean, reason: string, evidence: string }}
|
|
475
|
+
*/
|
|
476
|
+
function judgeProbe(probe) {
|
|
477
|
+
const evidence = trimmedString(probe.evidence);
|
|
478
|
+
|
|
479
|
+
if (probe.discharged !== true) {
|
|
480
|
+
return {
|
|
481
|
+
selectable: false,
|
|
482
|
+
reason: "blocker-holds",
|
|
483
|
+
evidence,
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
if (evidence.length === 0) {
|
|
487
|
+
return {
|
|
488
|
+
selectable: false,
|
|
489
|
+
reason: "blocker-discharge-unevidenced",
|
|
490
|
+
evidence,
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
return { selectable: true, reason: "blocker-discharged", evidence };
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Decide whether a pre-work item may be selected as a build candidate.
|
|
499
|
+
*
|
|
500
|
+
* Order is load-bearing. The human gate is checked before anything else, so no
|
|
501
|
+
* probe result — however conclusive — can promote an item a human parked.
|
|
502
|
+
*
|
|
503
|
+
* @param {{
|
|
504
|
+
* laneType?: unknown
|
|
505
|
+
* labels?: unknown
|
|
506
|
+
* body?: unknown
|
|
507
|
+
* comments?: unknown
|
|
508
|
+
* trustedHumanActorIds?: unknown
|
|
509
|
+
* humanNeededLabel?: unknown
|
|
510
|
+
* statedBlocker?: unknown
|
|
511
|
+
* probe?: { discharged?: unknown, evidence?: unknown } | null
|
|
512
|
+
* }} input
|
|
513
|
+
* @returns {{ selectable: boolean, reason: string, humanGated: boolean, evidence: string }}
|
|
514
|
+
*/
|
|
515
|
+
export function classifyPreWorkCandidate(input = {}) {
|
|
516
|
+
if (isHumanGated(input)) {
|
|
517
|
+
return {
|
|
518
|
+
selectable: false,
|
|
519
|
+
reason: "human-gate",
|
|
520
|
+
humanGated: true,
|
|
521
|
+
evidence: "",
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
if (!isPreWorkLaneType(input.laneType)) {
|
|
525
|
+
return {
|
|
526
|
+
selectable: false,
|
|
527
|
+
reason: "not-pre-work",
|
|
528
|
+
humanGated: false,
|
|
529
|
+
evidence: "",
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
if (trimmedString(input.statedBlocker).length === 0) {
|
|
533
|
+
return {
|
|
534
|
+
selectable: true,
|
|
535
|
+
reason: "no-blocker",
|
|
536
|
+
humanGated: false,
|
|
537
|
+
evidence: "",
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
if (!input.probe || typeof input.probe !== "object") {
|
|
541
|
+
return {
|
|
542
|
+
selectable: false,
|
|
543
|
+
reason: "blocker-unprobed",
|
|
544
|
+
humanGated: false,
|
|
545
|
+
evidence: "",
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
return { ...judgeProbe(input.probe), humanGated: false };
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/** Plain-English wording for each verdict, for the note left on the item. */
|
|
553
|
+
const REASON_COPY = Object.freeze({
|
|
554
|
+
"human-gate": "A person parked this one on purpose, so intake left it alone.",
|
|
555
|
+
"not-pre-work": "This item is not sitting in a not-yet-started lane.",
|
|
556
|
+
"no-blocker": "No blocker was written on this item, so it is buildable.",
|
|
557
|
+
"blocker-unprobed":
|
|
558
|
+
"This item states a blocker that was not re-checked this cycle, so it stays put.",
|
|
559
|
+
"blocker-holds":
|
|
560
|
+
"The blocker was re-checked and still holds, so it stays put.",
|
|
561
|
+
"blocker-discharge-unevidenced":
|
|
562
|
+
"The blocker looked clear but no proof was recorded, so it stays put.",
|
|
563
|
+
"blocker-discharged":
|
|
564
|
+
"The blocker was re-checked and no longer applies, so this item is buildable again.",
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Render the re-probe result to leave on the item, so the next cycle reads the
|
|
569
|
+
* answer instead of deriving it again.
|
|
570
|
+
*
|
|
571
|
+
* @param {{
|
|
572
|
+
* statedBlocker?: unknown
|
|
573
|
+
* checkedAt?: string | Date
|
|
574
|
+
* }} candidate
|
|
575
|
+
* @param {{ reason: string, evidence?: string }} verdict
|
|
576
|
+
* @returns {string}
|
|
577
|
+
*/
|
|
578
|
+
export function formatReprobeNote(candidate = {}, verdict) {
|
|
579
|
+
const checkedAt =
|
|
580
|
+
candidate.checkedAt instanceof Date
|
|
581
|
+
? candidate.checkedAt.toISOString()
|
|
582
|
+
: trimmedString(candidate.checkedAt) || new Date().toISOString();
|
|
583
|
+
const lines = [
|
|
584
|
+
"**Blocker re-check**",
|
|
585
|
+
"",
|
|
586
|
+
`- What has to be true: ${trimmedString(candidate.statedBlocker) || "(none written on this item)"}`,
|
|
587
|
+
`- What we found: ${REASON_COPY[verdict.reason] ?? verdict.reason}`,
|
|
588
|
+
];
|
|
589
|
+
const evidence = trimmedString(verdict.evidence);
|
|
590
|
+
if (evidence.length > 0) {
|
|
591
|
+
lines.push(`- Proof: ${evidence}`);
|
|
592
|
+
}
|
|
593
|
+
lines.push(`- Checked at: ${checkedAt}`);
|
|
594
|
+
|
|
595
|
+
return lines.join("\n");
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* Marker on the note this module leaves, so a later cycle recognises its own
|
|
600
|
+
* work instead of commenting again.
|
|
601
|
+
*/
|
|
602
|
+
export const HUMAN_GATE_NOTE_MARKER = "<!-- [lisa-human-gate-reconciled] -->";
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Decide whether a candidate ALREADY IN THE READY LANE may be claimed.
|
|
606
|
+
*
|
|
607
|
+
* `classifyPreWorkCandidate` was the only caller of the human-gate test, and it
|
|
608
|
+
* runs on candidates outside the ready lane. An item that reached the ready
|
|
609
|
+
* lane was therefore claimed with the gate never consulted — the check was
|
|
610
|
+
* correct and simply unreachable from the path that matters.
|
|
611
|
+
*
|
|
612
|
+
* This shares `isHumanGated` with the pre-work classifier deliberately. Two
|
|
613
|
+
* copies of a substring test drift, and a drifted gate fails silently: it stops
|
|
614
|
+
* matching, and nothing reports that it stopped.
|
|
615
|
+
*
|
|
616
|
+
* The test stays a plain literal-substring match and is NOT keyed on `reason=`.
|
|
617
|
+
* Markers in the wild carry no `reason=` at all and sit anywhere in the body, so
|
|
618
|
+
* a parser keyed on the structured field would miss those while appearing to
|
|
619
|
+
* work on every item that happens to have one — reproducing this defect one
|
|
620
|
+
* layer down.
|
|
621
|
+
* @param {{ labels?: unknown, body?: unknown, comments?: unknown, trustedHumanActorIds?: unknown, humanNeededLabel?: unknown }} input - Candidate surfaces
|
|
622
|
+
* @returns {{ claimable: boolean, reason: string, humanGated: boolean }} Claim verdict
|
|
623
|
+
*/
|
|
624
|
+
export function classifyReadyCandidate(input = {}) {
|
|
625
|
+
if (isHumanGated(input)) {
|
|
626
|
+
return { claimable: false, reason: "human-gate", humanGated: true };
|
|
627
|
+
}
|
|
628
|
+
return { claimable: true, reason: "ready-eligible", humanGated: false };
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Plan the state repair for a ready-lane item that is held for a person.
|
|
633
|
+
*
|
|
634
|
+
* Skipping such an item is not enough. `lisa-repair-intake` sweeps items that
|
|
635
|
+
* are NOT in the ready role and excludes gated ones outright, so a ready AND
|
|
636
|
+
* gated item falls outside its filter twice over. Skipping alone would leave it
|
|
637
|
+
* re-evaluated and re-rejected every cycle forever, seen by nothing — trading a
|
|
638
|
+
* loud failure for a silent one.
|
|
639
|
+
*
|
|
640
|
+
* So the lane is reconciled to match the hold: the item leaves the pickup queue
|
|
641
|
+
* and gains the human-needed marker. That is the same repair the leaf-only gate
|
|
642
|
+
* already performs for a ready item that must not be dispatched.
|
|
643
|
+
*
|
|
644
|
+
* Idempotent by state rather than by memory: an item already out of the queue
|
|
645
|
+
* and already marked needs nothing, so asking twice yields no second mutation.
|
|
646
|
+
* @param {{
|
|
647
|
+
* labels?: unknown
|
|
648
|
+
* body?: unknown
|
|
649
|
+
* comments?: unknown
|
|
650
|
+
* trustedHumanActorIds?: unknown
|
|
651
|
+
* humanNeededLabel?: unknown
|
|
652
|
+
* readyLabel?: unknown
|
|
653
|
+
* alreadyNotified?: unknown
|
|
654
|
+
* }} input - Candidate surfaces plus the configured lane and marker labels
|
|
655
|
+
* @returns {{ gated: boolean, reason: string, actions: { removeReadyRole: boolean, addHumanNeededLabel: boolean, comment: boolean } }} Repair plan
|
|
656
|
+
*/
|
|
657
|
+
export function planHumanGateReconciliation(input = {}) {
|
|
658
|
+
const idle = Object.freeze({
|
|
659
|
+
removeReadyRole: false,
|
|
660
|
+
addHumanNeededLabel: false,
|
|
661
|
+
comment: false,
|
|
662
|
+
});
|
|
663
|
+
if (!isHumanGated(input)) {
|
|
664
|
+
return { gated: false, reason: "not-gated", actions: idle };
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
const labels = normalizeLabels(input.labels);
|
|
668
|
+
const needed = String(input.humanNeededLabel ?? DEFAULT_HUMAN_NEEDED_LABEL)
|
|
669
|
+
.trim()
|
|
670
|
+
.toLowerCase();
|
|
671
|
+
const ready = String(input.readyLabel ?? "")
|
|
672
|
+
.trim()
|
|
673
|
+
.toLowerCase();
|
|
674
|
+
const inReadyLane = ready.length > 0 && labels.includes(ready);
|
|
675
|
+
const marked = needed.length > 0 && labels.includes(needed);
|
|
676
|
+
const actions = {
|
|
677
|
+
removeReadyRole: inReadyLane,
|
|
678
|
+
addHumanNeededLabel: needed.length > 0 && !marked,
|
|
679
|
+
comment:
|
|
680
|
+
input.alreadyNotified !== true &&
|
|
681
|
+
(inReadyLane || (needed.length > 0 && !marked)),
|
|
682
|
+
};
|
|
683
|
+
const changed =
|
|
684
|
+
actions.removeReadyRole || actions.addHumanNeededLabel || actions.comment;
|
|
685
|
+
|
|
686
|
+
return {
|
|
687
|
+
gated: true,
|
|
688
|
+
reason: changed ? "reconcile" : "already-reconciled",
|
|
689
|
+
actions,
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* Marker on the note the release path leaves, so a later cycle recognises its
|
|
695
|
+
* own work instead of commenting again.
|
|
696
|
+
*
|
|
697
|
+
* A superstring of neither declaration marker, for the reason
|
|
698
|
+
* {@link HUMAN_GATE_RELEASE_MARKER} gives: a note ABOUT a release must not read
|
|
699
|
+
* as a release, or the note announcing one item's discharge would discharge
|
|
700
|
+
* every item it names.
|
|
701
|
+
*/
|
|
702
|
+
export const HUMAN_GATE_RELEASE_NOTE_MARKER =
|
|
703
|
+
"<!-- [lisa-human-gate-released] -->";
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* The one sentence every hold note gives an operator to END the hold.
|
|
707
|
+
*
|
|
708
|
+
* One constant, two notes, because the instruction IS the release path as far
|
|
709
|
+
* as the person reading it is concerned. Two copies of it drift, and a drifted
|
|
710
|
+
* instruction sends someone to a mechanism that no longer exists — which is
|
|
711
|
+
* worse than the prose it replaced, since that at least described something
|
|
712
|
+
* real. It names a comment because the alternative it replaces — "remove the
|
|
713
|
+
* hold note from the description" — asks for a whole-body rewrite the tooling
|
|
714
|
+
* has no safe way to perform.
|
|
715
|
+
*/
|
|
716
|
+
const RESUME_INSTRUCTION = [
|
|
717
|
+
"- To resume it: leave a comment on this item that starts with ",
|
|
718
|
+
HUMAN_GATE_RELEASE_MARKER,
|
|
719
|
+
" and repeats the reason the hold in the description names. The next sweep ",
|
|
720
|
+
"puts it back in the queue on its own. Nothing else has to change — do not ",
|
|
721
|
+
"edit the description, and do not move it by hand.",
|
|
722
|
+
].join("");
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* Plan the state repair for an item whose hold has been discharged.
|
|
726
|
+
*
|
|
727
|
+
* The exact inverse of {@link planHumanGateReconciliation}, and deliberately
|
|
728
|
+
* the same shape: that one takes the ready role away and adds the marker label,
|
|
729
|
+
* this one takes the marker label away and puts the ready role back. A state
|
|
730
|
+
* change with no inverse is the defect class this pair exists to close
|
|
731
|
+
* (`state-changes-without-inverses`), and an inverse that is merely *possible*
|
|
732
|
+
* is not one — it has to sit on a path something actually runs, which is why
|
|
733
|
+
* this is a planner the intake sweeps call rather than an instruction to an
|
|
734
|
+
* operator.
|
|
735
|
+
*
|
|
736
|
+
* Two refusals are load-bearing:
|
|
737
|
+
*
|
|
738
|
+
* - **A still-held item plans nothing.** Every outstanding reason holds the
|
|
739
|
+
* whole item, so an item whose second hold has not been answered is not
|
|
740
|
+
* half-released.
|
|
741
|
+
* - **An item that was never held plans nothing.** Without that, this would be
|
|
742
|
+
* a path that adds the build-ready role to arbitrary items — a promotion
|
|
743
|
+
* mechanism wearing a release mechanism's name.
|
|
744
|
+
*
|
|
745
|
+
* The ready role is restored only when the item carries none of the configured
|
|
746
|
+
* lifecycle labels, mirroring {@link planLabelNormalization}. An item that was
|
|
747
|
+
* held and has since reached a terminal lane must not be dragged back to the
|
|
748
|
+
* queue by its own release.
|
|
749
|
+
*
|
|
750
|
+
* Idempotent by state rather than by memory: an item already unmarked and
|
|
751
|
+
* already back in the queue needs nothing, so asking twice yields no second
|
|
752
|
+
* mutation.
|
|
753
|
+
* @param {{
|
|
754
|
+
* labels?: unknown
|
|
755
|
+
* body?: unknown
|
|
756
|
+
* comments?: unknown
|
|
757
|
+
* trustedHumanActorIds?: unknown
|
|
758
|
+
* humanNeededLabel?: unknown
|
|
759
|
+
* readyLabel?: unknown
|
|
760
|
+
* lifecycleLabels?: unknown
|
|
761
|
+
* alreadyNotified?: unknown
|
|
762
|
+
* }} input - Candidate surfaces plus the configured lane vocabulary
|
|
763
|
+
* @returns {{ released: boolean, reason: string, discharged: string[], actions: { removeHumanNeededLabel: boolean, addReadyLabel: string | null, comment: boolean } }} Release plan
|
|
764
|
+
*/
|
|
765
|
+
export function planHumanGateRelease(input = {}) {
|
|
766
|
+
const idle = Object.freeze({
|
|
767
|
+
removeHumanNeededLabel: false,
|
|
768
|
+
addReadyLabel: null,
|
|
769
|
+
comment: false,
|
|
770
|
+
});
|
|
771
|
+
const verdict = humanGateVerdict(input);
|
|
772
|
+
if (verdict.held) {
|
|
773
|
+
return {
|
|
774
|
+
released: false,
|
|
775
|
+
reason: "hold-outstanding",
|
|
776
|
+
discharged: [],
|
|
777
|
+
actions: idle,
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
if (verdict.declared === 0 && !verdict.labelPresent) {
|
|
781
|
+
return {
|
|
782
|
+
released: false,
|
|
783
|
+
reason: "no-hold",
|
|
784
|
+
discharged: [],
|
|
785
|
+
actions: idle,
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
const needed = String(input.humanNeededLabel ?? DEFAULT_HUMAN_NEEDED_LABEL)
|
|
790
|
+
.trim()
|
|
791
|
+
.toLowerCase();
|
|
792
|
+
// The marker label is excluded from the lane test on both sides. It is one of
|
|
793
|
+
// the configured lifecycle labels AND it is the label this plan removes, so
|
|
794
|
+
// counting it would let the hold's own marker prove the item is already in a
|
|
795
|
+
// lane and veto the restoration — the release would clear the flag and leave
|
|
796
|
+
// the item in no queue at all, which is the original defect with one fewer
|
|
797
|
+
// symptom.
|
|
798
|
+
const labels = normalizeLabels(input.labels).filter(name => name !== needed);
|
|
799
|
+
const lifecycle = normalizeLabels(input.lifecycleLabels).filter(
|
|
800
|
+
name => name !== needed
|
|
801
|
+
);
|
|
802
|
+
const ready = trimmedString(input.readyLabel);
|
|
803
|
+
const inLifecycle = lifecycle.some(name => labels.includes(name));
|
|
804
|
+
const addReadyLabel =
|
|
805
|
+
ready.length > 0 && !inLifecycle && !labels.includes(ready.toLowerCase())
|
|
806
|
+
? ready
|
|
807
|
+
: null;
|
|
808
|
+
const actions = {
|
|
809
|
+
removeHumanNeededLabel: verdict.labelPresent,
|
|
810
|
+
addReadyLabel,
|
|
811
|
+
comment:
|
|
812
|
+
input.alreadyNotified !== true &&
|
|
813
|
+
(verdict.labelPresent || addReadyLabel !== null),
|
|
814
|
+
};
|
|
815
|
+
const changed =
|
|
816
|
+
actions.removeHumanNeededLabel || addReadyLabel !== null || actions.comment;
|
|
817
|
+
|
|
818
|
+
return {
|
|
819
|
+
released: true,
|
|
820
|
+
reason: changed ? "release" : "already-released",
|
|
821
|
+
discharged: verdict.released,
|
|
822
|
+
actions,
|
|
823
|
+
};
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
/**
|
|
827
|
+
* Render the discharge record a person or a skill leaves to END a hold.
|
|
828
|
+
*
|
|
829
|
+
* Generated rather than retyped, because the release names the hold it ends by
|
|
830
|
+
* its reason and a mistyped reason discharges nothing while looking like it
|
|
831
|
+
* did. The reason is echoed verbatim from the hold, so the pairing is visible
|
|
832
|
+
* to a reader as well as to the matcher.
|
|
833
|
+
* @param {{ reason?: unknown, decidedBy?: unknown, decision?: unknown }} discharge - What was decided, and by whom
|
|
834
|
+
* @returns {string} Comment body carrying the release marker
|
|
835
|
+
*/
|
|
836
|
+
export function formatHumanGateRelease(discharge = {}) {
|
|
837
|
+
const reason = trimmedString(discharge.reason);
|
|
838
|
+
const declaration =
|
|
839
|
+
reason.length > 0
|
|
840
|
+
? `${HUMAN_GATE_RELEASE_MARKER} ${REASON_KEY}${reason}`
|
|
841
|
+
: HUMAN_GATE_RELEASE_MARKER;
|
|
842
|
+
const lines = [declaration, "", "**The hold on this item is lifted.**", ""];
|
|
843
|
+
lines.push(
|
|
844
|
+
`- What was being asked: ${reason.length > 0 ? reason : "(the hold named no reason)"}`
|
|
845
|
+
);
|
|
846
|
+
const decision = trimmedString(discharge.decision);
|
|
847
|
+
if (decision.length > 0) lines.push(`- What was decided: ${decision}`);
|
|
848
|
+
const decidedBy = trimmedString(discharge.decidedBy);
|
|
849
|
+
if (decidedBy.length > 0) lines.push(`- Decided by: ${decidedBy}`);
|
|
850
|
+
lines.push(
|
|
851
|
+
"- What happens next: this item goes back into the queue that agents build from."
|
|
852
|
+
);
|
|
853
|
+
|
|
854
|
+
return lines.join("\n");
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
/**
|
|
858
|
+
* Render the notice for an item this sweep released.
|
|
859
|
+
*
|
|
860
|
+
* Distinct from {@link formatHumanGateNote} for the same reason
|
|
861
|
+
* {@link formatNormalizationHoldNote} is: the two report opposite events, and
|
|
862
|
+
* reusing one to report the other tells an operator the wrong thing happened.
|
|
863
|
+
* @returns {string} Comment body, carrying the marker that keeps a re-run quiet
|
|
864
|
+
*/
|
|
865
|
+
export function formatHumanGateReleaseNote() {
|
|
866
|
+
return [
|
|
867
|
+
"**Back in the queue: the hold was answered**",
|
|
868
|
+
"",
|
|
869
|
+
"- What was found: this item was being held for a person, and the " +
|
|
870
|
+
"decision it was waiting for has since been recorded on it.",
|
|
871
|
+
"- What changed: the hold flag has been taken off and the item has been " +
|
|
872
|
+
"put back into the queue that agents build from.",
|
|
873
|
+
"- Nothing was rewritten: the description is exactly as it was, hold note " +
|
|
874
|
+
"and all, so the history of why it was held stays readable.",
|
|
875
|
+
"",
|
|
876
|
+
HUMAN_GATE_RELEASE_NOTE_MARKER,
|
|
877
|
+
].join("\n");
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
/**
|
|
881
|
+
* Marker on the note the normalization sweep leaves, so a later cycle
|
|
882
|
+
* recognises its own work instead of commenting again.
|
|
883
|
+
*
|
|
884
|
+
* Deliberately NOT the hold marker and deliberately not a superstring of it:
|
|
885
|
+
* `HUMAN_GATE_MARKER` closes with `]`, so neither this nor
|
|
886
|
+
* `HUMAN_GATE_NOTE_MARKER` matches it. A note that read as a hold declaration
|
|
887
|
+
* would make every reported item look held to the next body-reading sweep,
|
|
888
|
+
* including items the report merely names.
|
|
889
|
+
*/
|
|
890
|
+
export const NORMALIZATION_HOLD_NOTE_MARKER =
|
|
891
|
+
"<!-- [lisa-human-gate-normalization-held] -->";
|
|
892
|
+
|
|
893
|
+
/**
|
|
894
|
+
* Decide whether an item carrying NO configured lifecycle label may be
|
|
895
|
+
* normalized into a ready lane.
|
|
896
|
+
*
|
|
897
|
+
* This is the promotion path, and it was keyed on labels alone. The configured
|
|
898
|
+
* `human_needed` label is one of the lifecycle labels whose *absence* the sweep
|
|
899
|
+
* enumerates on, so an item held only by the body marker was a member of the
|
|
900
|
+
* swept population by definition and got the build-ready label applied to it.
|
|
901
|
+
* The `[lisa-human-gate]` exclusion existed, in a different and read-only sweep
|
|
902
|
+
* further down the same contract: the one sweep that writes was the one that
|
|
903
|
+
* could not see the marker.
|
|
904
|
+
*
|
|
905
|
+
* Order is load-bearing for the same reason it is in `classifyPreWorkCandidate`:
|
|
906
|
+
* the hold is checked before lane membership and before any classification, so
|
|
907
|
+
* nothing downstream — however confident — can promote an item a person parked.
|
|
908
|
+
*
|
|
909
|
+
* On a match this plans NO write of its own. `planHumanGateReconciliation`
|
|
910
|
+
* turns a match into durable state, so a false positive there latches and every
|
|
911
|
+
* later cycle agrees with the first. The gate test is a plain substring match
|
|
912
|
+
* whose imprecision is tracked separately, so this path refuses and reports
|
|
913
|
+
* read-only instead — the same treatment the ungated-filing sweep already gives
|
|
914
|
+
* a hold it finds.
|
|
915
|
+
* @param {{
|
|
916
|
+
* labels?: unknown
|
|
917
|
+
* body?: unknown
|
|
918
|
+
* comments?: unknown
|
|
919
|
+
* trustedHumanActorIds?: unknown
|
|
920
|
+
* humanNeededLabel?: unknown
|
|
921
|
+
* lifecycleLabels?: unknown
|
|
922
|
+
* readyLabel?: unknown
|
|
923
|
+
* }} input - Candidate surfaces plus the configured lifecycle vocabulary
|
|
924
|
+
* @returns {{ normalize: boolean, reason: string, humanGated: boolean, actions: { addReadyLabel: string | null, reportHold: boolean } }} Normalization plan
|
|
925
|
+
*/
|
|
926
|
+
export function planLabelNormalization(input = {}) {
|
|
927
|
+
const idle = Object.freeze({ addReadyLabel: null, reportHold: false });
|
|
928
|
+
if (isHumanGated(input)) {
|
|
929
|
+
return {
|
|
930
|
+
normalize: false,
|
|
931
|
+
reason: "human-gate",
|
|
932
|
+
humanGated: true,
|
|
933
|
+
actions: Object.freeze({ addReadyLabel: null, reportHold: true }),
|
|
934
|
+
};
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
const labels = normalizeLabels(input.labels);
|
|
938
|
+
if (normalizeLabels(input.lifecycleLabels).some(l => labels.includes(l))) {
|
|
939
|
+
return {
|
|
940
|
+
normalize: false,
|
|
941
|
+
reason: "already-in-lifecycle",
|
|
942
|
+
humanGated: false,
|
|
943
|
+
actions: idle,
|
|
944
|
+
};
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
const ready = trimmedString(input.readyLabel);
|
|
948
|
+
if (ready.length === 0) {
|
|
949
|
+
return {
|
|
950
|
+
normalize: false,
|
|
951
|
+
reason: "no-ready-label",
|
|
952
|
+
humanGated: false,
|
|
953
|
+
actions: idle,
|
|
954
|
+
};
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
return {
|
|
958
|
+
normalize: true,
|
|
959
|
+
reason: "normalize",
|
|
960
|
+
humanGated: false,
|
|
961
|
+
actions: Object.freeze({ addReadyLabel: ready, reportHold: false }),
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
/**
|
|
966
|
+
* Render the notice for an item the normalization sweep left alone.
|
|
967
|
+
*
|
|
968
|
+
* Distinct from `formatHumanGateNote` because the two say opposite things
|
|
969
|
+
* about what happened: that one reports a lane that WAS changed, this one
|
|
970
|
+
* reports a promotion that was declined and nothing else. Reusing it would tell
|
|
971
|
+
* an operator their item had been moved when it had not.
|
|
972
|
+
* @returns {string} Comment body, carrying the marker that keeps a re-run quiet
|
|
973
|
+
*/
|
|
974
|
+
export function formatNormalizationHoldNote() {
|
|
975
|
+
return [
|
|
976
|
+
"**Left alone: a person is holding this**",
|
|
977
|
+
"",
|
|
978
|
+
"- What was found: the description says a person is holding this one, so " +
|
|
979
|
+
"it was not put into the queue that agents work from.",
|
|
980
|
+
"- What changed: nothing at all. It was left exactly as it is, and " +
|
|
981
|
+
"nothing will pick it up on its own.",
|
|
982
|
+
RESUME_INSTRUCTION,
|
|
983
|
+
"",
|
|
984
|
+
NORMALIZATION_HOLD_NOTE_MARKER,
|
|
985
|
+
].join("\n");
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
/**
|
|
989
|
+
* Render the hold notice for a reader who does not know this subsystem.
|
|
990
|
+
*
|
|
991
|
+
* Written for a non-technical operator on purpose — that is who stands at this
|
|
992
|
+
* gate. It names what was found, what changed, and how to undo it, and uses no
|
|
993
|
+
* skill name, label syntax, or phase number, none of which a reader can act on.
|
|
994
|
+
* @returns {string} Comment body, carrying the marker that keeps a re-run quiet
|
|
995
|
+
*/
|
|
996
|
+
export function formatHumanGateNote() {
|
|
997
|
+
return [
|
|
998
|
+
"**On hold for a person**",
|
|
999
|
+
"",
|
|
1000
|
+
"- What was found: this item is marked as held for a person, but it was " +
|
|
1001
|
+
"also sitting in the queue that agents build from — so it would have " +
|
|
1002
|
+
"been picked up and built anyway.",
|
|
1003
|
+
"- What changed: it has been taken out of that queue and flagged as " +
|
|
1004
|
+
"needing a person, so nothing will build it automatically.",
|
|
1005
|
+
RESUME_INSTRUCTION,
|
|
1006
|
+
"",
|
|
1007
|
+
HUMAN_GATE_NOTE_MARKER,
|
|
1008
|
+
].join("\n");
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
/**
|
|
1012
|
+
* Render the cycle-summary line naming what was held.
|
|
1013
|
+
*
|
|
1014
|
+
* A lane mutation nobody can see afterwards is the same class of problem as the
|
|
1015
|
+
* one this fixes, so the run says what it moved — and it keeps "nothing was
|
|
1016
|
+
* eligible" distinguishable from "something eligible was held".
|
|
1017
|
+
* @param {readonly unknown[]} held - Item references held this cycle
|
|
1018
|
+
* @returns {string} One summary line
|
|
1019
|
+
*/
|
|
1020
|
+
/**
|
|
1021
|
+
* Render the cycle-summary line naming what the precision rule DEMOTED.
|
|
1022
|
+
*
|
|
1023
|
+
* The counterpart of {@link summarizeHumanGateHolds}, and it exists for the
|
|
1024
|
+
* same reason: a mutation nobody can see afterwards is the problem this whole
|
|
1025
|
+
* area keeps having. A rule that quietly declines to honour half the marker
|
|
1026
|
+
* occurrences it sees reads exactly like a rule that saw none, so the count is
|
|
1027
|
+
* printed even when it is zero — measured across this repository's matching
|
|
1028
|
+
* bodies, 33 of 62 occurrences are mentions rather than declarations.
|
|
1029
|
+
* @param {unknown} demoted - How many occurrences were mentions, not declarations
|
|
1030
|
+
* @returns {string} One summary line
|
|
1031
|
+
*/
|
|
1032
|
+
export function summarizeHumanGateMentions(demoted = 0) {
|
|
1033
|
+
const count = Number.isFinite(Number(demoted))
|
|
1034
|
+
? Math.trunc(Number(demoted))
|
|
1035
|
+
: 0;
|
|
1036
|
+
const shown = count > 0 ? String(count) : "none";
|
|
1037
|
+
return `Marker mentions demoted (not declarations): ${shown}.`;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
export function summarizeHumanGateHolds(held = []) {
|
|
1041
|
+
const names = (Array.isArray(held) ? held : [])
|
|
1042
|
+
.map(item => trimmedString(item))
|
|
1043
|
+
.filter(name => name.length > 0);
|
|
1044
|
+
if (names.length === 0) return "Held for a person: none.";
|
|
1045
|
+
return `Held for a person (${String(names.length)}): ${names.join(", ")}.`;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
/**
|
|
1049
|
+
* Render the cycle-summary line naming what was RELEASED.
|
|
1050
|
+
*
|
|
1051
|
+
* The counterpart of {@link summarizeHumanGateHolds}, printed even when it is
|
|
1052
|
+
* zero. Without it a release path that has stopped working is indistinguishable
|
|
1053
|
+
* from a cycle where nothing needed releasing — which is exactly how the
|
|
1054
|
+
* missing inverse went unnoticed for as long as it did, and a fix that cannot
|
|
1055
|
+
* be observed to fire is a fix nobody can tell has regressed.
|
|
1056
|
+
* @param {readonly unknown[]} released - Item references released this cycle
|
|
1057
|
+
* @returns {string} One summary line
|
|
1058
|
+
*/
|
|
1059
|
+
export function summarizeHumanGateReleases(released = []) {
|
|
1060
|
+
const names = (Array.isArray(released) ? released : [])
|
|
1061
|
+
.map(item => trimmedString(item))
|
|
1062
|
+
.filter(name => name.length > 0);
|
|
1063
|
+
if (names.length === 0) return "Released back to the queue: none.";
|
|
1064
|
+
return `Released back to the queue (${String(names.length)}): ${names.join(", ")}.`;
|
|
1065
|
+
}
|