@codyswann/lisa 4.22.8 → 4.22.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/all/copy-overwrite/scripts/lib/process-tree-runner.mjs +127 -0
- package/all/copy-overwrite/scripts/lisa-floor-collisions.mjs +63 -8
- package/all/copy-overwrite/scripts/lisa-hooks/parity-safety-net.sh +36 -6
- package/all/copy-overwrite/scripts/lisa-postinstall.mjs +35 -13
- package/all/copy-overwrite/scripts/lisa-reconcile-policy.mjs +11 -3
- package/all/copy-overwrite/scripts/lisa-run-gates.mjs +41 -8
- package/all/copy-overwrite/scripts/lisa-schema-validate.mjs +2 -2
- package/all/copy-overwrite/scripts/lisa-work-item.mjs +2 -1
- package/cdk/package-lisa/package.lisa.json +1 -1
- package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.js +24 -0
- package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
- package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
- package/dist/core/nightly-e2e-guard-behavior-certificate.js.map +1 -1
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +61 -51
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/dist/opencode/plugin-templates/parity-safety-net.sh +36 -6
- package/nestjs/package-lisa/package.lisa.json +1 -1
- package/package.json +3 -3
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-atlassian-access/SKILL.md +10 -13
- package/plugins/lisa/.codex-plugin/skills/lisa-doctor/SKILL.md +4 -2
- package/plugins/lisa/.codex-plugin/skills/lisa-drive-pr-to-merge/SKILL.md +29 -4
- package/plugins/lisa/.codex-plugin/skills/lisa-github-sync/SKILL.md +8 -3
- package/plugins/lisa/.codex-plugin/skills/lisa-jam-access/SKILL.md +7 -10
- package/plugins/lisa/.codex-plugin/skills/lisa-jira-journey/SKILL.md +5 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-jira-journey/scripts/parse-plan.py +36 -2
- package/plugins/lisa/.codex-plugin/skills/lisa-jira-sync/SKILL.md +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-access/SKILL.md +8 -12
- package/plugins/lisa/.codex-plugin/skills/lisa-linear-sync/SKILL.md +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-nightly-lower-code-complexity/SKILL.md +7 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-notion-access/SKILL.md +7 -10
- package/plugins/lisa/.codex-plugin/skills/lisa-posthog-access/SKILL.md +7 -10
- package/plugins/lisa/.codex-plugin/skills/lisa-repair-intake/SKILL.md +19 -3
- package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +10 -6
- package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +95 -44
- package/plugins/lisa/.codex-plugin/skills/lisa-sentry-access/SKILL.md +7 -10
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-atlassian/SKILL.md +7 -10
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-linear/SKILL.md +9 -12
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-notion/SKILL.md +7 -10
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-aws/SKILL.md +7 -2
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-env/SKILL.md +6 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-env/assets/session-start.sh +19 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-env/assets/setup.sh +1 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +25 -4
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-workstation/scripts/bounded-child.mjs +9 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-workstation/scripts/workstation.mjs +29 -21
- package/plugins/lisa/.codex-plugin/skills/lisa-sonarcloud-access/SKILL.md +7 -10
- package/plugins/lisa/.codex-plugin/skills/lisa-tracker-sync/SKILL.md +1 -1
- package/plugins/lisa/hooks/parity-safety-net.sh +36 -6
- package/plugins/lisa/hooks/threshold-ratchet-families.mjs +31 -7
- package/plugins/lisa/rules/reference/base-rules.md +1 -1
- package/plugins/lisa/rules/reference/config-resolution.md +5 -14
- package/plugins/lisa/scripts/install-remote-agent-aws.mjs +5 -1
- package/plugins/lisa/scripts/rollup-blocker-classification.mjs +18 -3
- package/plugins/lisa/skills/lisa-atlassian-access/SKILL.md +10 -13
- package/plugins/lisa/skills/lisa-doctor/SKILL.md +4 -2
- package/plugins/lisa/skills/lisa-drive-pr-to-merge/SKILL.md +29 -4
- package/plugins/lisa/skills/lisa-github-sync/SKILL.md +8 -3
- package/plugins/lisa/skills/lisa-jam-access/SKILL.md +7 -10
- package/plugins/lisa/skills/lisa-jira-journey/SKILL.md +5 -0
- package/plugins/lisa/skills/lisa-jira-journey/scripts/parse-plan.py +36 -2
- package/plugins/lisa/skills/lisa-jira-sync/SKILL.md +1 -1
- package/plugins/lisa/skills/lisa-linear-access/SKILL.md +8 -12
- package/plugins/lisa/skills/lisa-linear-sync/SKILL.md +1 -1
- package/plugins/lisa/skills/lisa-nightly-lower-code-complexity/SKILL.md +7 -1
- package/plugins/lisa/skills/lisa-notion-access/SKILL.md +7 -10
- package/plugins/lisa/skills/lisa-posthog-access/SKILL.md +7 -10
- package/plugins/lisa/skills/lisa-repair-intake/SKILL.md +19 -3
- package/plugins/lisa/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +10 -6
- package/plugins/lisa/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +95 -44
- package/plugins/lisa/skills/lisa-sentry-access/SKILL.md +7 -10
- package/plugins/lisa/skills/lisa-setup-atlassian/SKILL.md +7 -10
- package/plugins/lisa/skills/lisa-setup-linear/SKILL.md +9 -12
- package/plugins/lisa/skills/lisa-setup-notion/SKILL.md +7 -10
- package/plugins/lisa/skills/lisa-setup-remote-aws/SKILL.md +7 -2
- package/plugins/lisa/skills/lisa-setup-remote-env/SKILL.md +6 -1
- package/plugins/lisa/skills/lisa-setup-remote-env/assets/session-start.sh +19 -0
- package/plugins/lisa/skills/lisa-setup-remote-env/assets/setup.sh +1 -0
- package/plugins/lisa/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +25 -4
- package/plugins/lisa/skills/lisa-setup-workstation/scripts/bounded-child.mjs +9 -0
- package/plugins/lisa/skills/lisa-setup-workstation/scripts/workstation.mjs +29 -21
- package/plugins/lisa/skills/lisa-sonarcloud-access/SKILL.md +7 -10
- package/plugins/lisa/skills/lisa-tracker-sync/SKILL.md +1 -1
- package/plugins/lisa-agy/hooks/parity-safety-net.sh +36 -6
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/scripts/install-remote-agent-aws.mjs +5 -1
- package/plugins/lisa-agy/scripts/rollup-blocker-classification.mjs +18 -3
- package/plugins/lisa-agy/skills/lisa-atlassian-access/SKILL.md +10 -13
- package/plugins/lisa-agy/skills/lisa-doctor/SKILL.md +4 -2
- package/plugins/lisa-agy/skills/lisa-drive-pr-to-merge/SKILL.md +29 -4
- package/plugins/lisa-agy/skills/lisa-github-sync/SKILL.md +8 -3
- package/plugins/lisa-agy/skills/lisa-jam-access/SKILL.md +7 -10
- package/plugins/lisa-agy/skills/lisa-jira-journey/SKILL.md +5 -0
- package/plugins/lisa-agy/skills/lisa-jira-journey/scripts/parse-plan.py +36 -2
- package/plugins/lisa-agy/skills/lisa-jira-sync/SKILL.md +1 -1
- package/plugins/lisa-agy/skills/lisa-linear-access/SKILL.md +8 -12
- package/plugins/lisa-agy/skills/lisa-linear-sync/SKILL.md +1 -1
- package/plugins/lisa-agy/skills/lisa-nightly-lower-code-complexity/SKILL.md +7 -1
- package/plugins/lisa-agy/skills/lisa-notion-access/SKILL.md +7 -10
- package/plugins/lisa-agy/skills/lisa-posthog-access/SKILL.md +7 -10
- package/plugins/lisa-agy/skills/lisa-repair-intake/SKILL.md +19 -3
- package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +10 -6
- package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +95 -44
- package/plugins/lisa-agy/skills/lisa-sentry-access/SKILL.md +7 -10
- package/plugins/lisa-agy/skills/lisa-setup-atlassian/SKILL.md +7 -10
- package/plugins/lisa-agy/skills/lisa-setup-linear/SKILL.md +9 -12
- package/plugins/lisa-agy/skills/lisa-setup-notion/SKILL.md +7 -10
- package/plugins/lisa-agy/skills/lisa-setup-remote-aws/SKILL.md +7 -2
- package/plugins/lisa-agy/skills/lisa-setup-remote-env/SKILL.md +6 -1
- package/plugins/lisa-agy/skills/lisa-setup-remote-env/assets/session-start.sh +19 -0
- package/plugins/lisa-agy/skills/lisa-setup-remote-env/assets/setup.sh +1 -0
- package/plugins/lisa-agy/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +25 -4
- package/plugins/lisa-agy/skills/lisa-setup-workstation/scripts/bounded-child.mjs +9 -0
- package/plugins/lisa-agy/skills/lisa-setup-workstation/scripts/workstation.mjs +29 -21
- package/plugins/lisa-agy/skills/lisa-sonarcloud-access/SKILL.md +7 -10
- package/plugins/lisa-agy/skills/lisa-tracker-sync/SKILL.md +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-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/hooks/parity-safety-net.sh +36 -6
- package/plugins/lisa-copilot/hooks/threshold-ratchet-families.mjs +31 -7
- package/plugins/lisa-copilot/rules/reference/base-rules.md +1 -1
- package/plugins/lisa-copilot/rules/reference/config-resolution.md +5 -14
- package/plugins/lisa-copilot/scripts/install-remote-agent-aws.mjs +5 -1
- package/plugins/lisa-copilot/scripts/rollup-blocker-classification.mjs +18 -3
- package/plugins/lisa-copilot/skills/lisa-atlassian-access/SKILL.md +10 -13
- package/plugins/lisa-copilot/skills/lisa-doctor/SKILL.md +4 -2
- package/plugins/lisa-copilot/skills/lisa-drive-pr-to-merge/SKILL.md +29 -4
- package/plugins/lisa-copilot/skills/lisa-github-sync/SKILL.md +8 -3
- package/plugins/lisa-copilot/skills/lisa-jam-access/SKILL.md +7 -10
- package/plugins/lisa-copilot/skills/lisa-jira-journey/SKILL.md +5 -0
- package/plugins/lisa-copilot/skills/lisa-jira-journey/scripts/parse-plan.py +36 -2
- package/plugins/lisa-copilot/skills/lisa-jira-sync/SKILL.md +1 -1
- package/plugins/lisa-copilot/skills/lisa-linear-access/SKILL.md +8 -12
- package/plugins/lisa-copilot/skills/lisa-linear-sync/SKILL.md +1 -1
- package/plugins/lisa-copilot/skills/lisa-nightly-lower-code-complexity/SKILL.md +7 -1
- package/plugins/lisa-copilot/skills/lisa-notion-access/SKILL.md +7 -10
- package/plugins/lisa-copilot/skills/lisa-posthog-access/SKILL.md +7 -10
- package/plugins/lisa-copilot/skills/lisa-repair-intake/SKILL.md +19 -3
- package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +10 -6
- package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +95 -44
- package/plugins/lisa-copilot/skills/lisa-sentry-access/SKILL.md +7 -10
- package/plugins/lisa-copilot/skills/lisa-setup-atlassian/SKILL.md +7 -10
- package/plugins/lisa-copilot/skills/lisa-setup-linear/SKILL.md +9 -12
- package/plugins/lisa-copilot/skills/lisa-setup-notion/SKILL.md +7 -10
- package/plugins/lisa-copilot/skills/lisa-setup-remote-aws/SKILL.md +7 -2
- package/plugins/lisa-copilot/skills/lisa-setup-remote-env/SKILL.md +6 -1
- package/plugins/lisa-copilot/skills/lisa-setup-remote-env/assets/session-start.sh +19 -0
- package/plugins/lisa-copilot/skills/lisa-setup-remote-env/assets/setup.sh +1 -0
- package/plugins/lisa-copilot/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +25 -4
- package/plugins/lisa-copilot/skills/lisa-setup-workstation/scripts/bounded-child.mjs +9 -0
- package/plugins/lisa-copilot/skills/lisa-setup-workstation/scripts/workstation.mjs +29 -21
- package/plugins/lisa-copilot/skills/lisa-sonarcloud-access/SKILL.md +7 -10
- package/plugins/lisa-copilot/skills/lisa-tracker-sync/SKILL.md +1 -1
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/hooks/parity-safety-net.sh +36 -6
- package/plugins/lisa-cursor/hooks/threshold-ratchet-families.mjs +31 -7
- package/plugins/lisa-cursor/rules/base-rules-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/config-resolution-reference.mdc +5 -14
- package/plugins/lisa-cursor/scripts/install-remote-agent-aws.mjs +5 -1
- package/plugins/lisa-cursor/scripts/rollup-blocker-classification.mjs +18 -3
- package/plugins/lisa-cursor/skills/lisa-atlassian-access/SKILL.md +10 -13
- package/plugins/lisa-cursor/skills/lisa-doctor/SKILL.md +4 -2
- package/plugins/lisa-cursor/skills/lisa-drive-pr-to-merge/SKILL.md +29 -4
- package/plugins/lisa-cursor/skills/lisa-github-sync/SKILL.md +8 -3
- package/plugins/lisa-cursor/skills/lisa-jam-access/SKILL.md +7 -10
- package/plugins/lisa-cursor/skills/lisa-jira-journey/SKILL.md +5 -0
- package/plugins/lisa-cursor/skills/lisa-jira-journey/scripts/parse-plan.py +36 -2
- package/plugins/lisa-cursor/skills/lisa-jira-sync/SKILL.md +1 -1
- package/plugins/lisa-cursor/skills/lisa-linear-access/SKILL.md +8 -12
- package/plugins/lisa-cursor/skills/lisa-linear-sync/SKILL.md +1 -1
- package/plugins/lisa-cursor/skills/lisa-nightly-lower-code-complexity/SKILL.md +7 -1
- package/plugins/lisa-cursor/skills/lisa-notion-access/SKILL.md +7 -10
- package/plugins/lisa-cursor/skills/lisa-posthog-access/SKILL.md +7 -10
- package/plugins/lisa-cursor/skills/lisa-repair-intake/SKILL.md +19 -3
- package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +10 -6
- package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +95 -44
- package/plugins/lisa-cursor/skills/lisa-sentry-access/SKILL.md +7 -10
- package/plugins/lisa-cursor/skills/lisa-setup-atlassian/SKILL.md +7 -10
- package/plugins/lisa-cursor/skills/lisa-setup-linear/SKILL.md +9 -12
- package/plugins/lisa-cursor/skills/lisa-setup-notion/SKILL.md +7 -10
- package/plugins/lisa-cursor/skills/lisa-setup-remote-aws/SKILL.md +7 -2
- package/plugins/lisa-cursor/skills/lisa-setup-remote-env/SKILL.md +6 -1
- package/plugins/lisa-cursor/skills/lisa-setup-remote-env/assets/session-start.sh +19 -0
- package/plugins/lisa-cursor/skills/lisa-setup-remote-env/assets/setup.sh +1 -0
- package/plugins/lisa-cursor/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +25 -4
- package/plugins/lisa-cursor/skills/lisa-setup-workstation/scripts/bounded-child.mjs +9 -0
- package/plugins/lisa-cursor/skills/lisa-setup-workstation/scripts/workstation.mjs +29 -21
- package/plugins/lisa-cursor/skills/lisa-sonarcloud-access/SKILL.md +7 -10
- package/plugins/lisa-cursor/skills/lisa-tracker-sync/SKILL.md +1 -1
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/src/base/hooks/parity-safety-net.sh +36 -6
- package/plugins/src/base/hooks/threshold-ratchet-families.mjs +31 -7
- package/plugins/src/base/rules/reference/base-rules.md +1 -1
- package/plugins/src/base/rules/reference/config-resolution.md +5 -14
- package/plugins/src/base/scripts/install-remote-agent-aws.mjs +5 -1
- package/plugins/src/base/scripts/rollup-blocker-classification.mjs +18 -3
- package/plugins/src/base/skills/lisa-atlassian-access/SKILL.md +10 -13
- package/plugins/src/base/skills/lisa-doctor/SKILL.md +4 -2
- package/plugins/src/base/skills/lisa-drive-pr-to-merge/SKILL.md +29 -4
- package/plugins/src/base/skills/lisa-github-sync/SKILL.md +8 -3
- package/plugins/src/base/skills/lisa-jam-access/SKILL.md +7 -10
- package/plugins/src/base/skills/lisa-jira-journey/SKILL.md +5 -0
- package/plugins/src/base/skills/lisa-jira-journey/scripts/parse-plan.py +36 -2
- package/plugins/src/base/skills/lisa-jira-sync/SKILL.md +1 -1
- package/plugins/src/base/skills/lisa-linear-access/SKILL.md +8 -12
- package/plugins/src/base/skills/lisa-linear-sync/SKILL.md +1 -1
- package/plugins/src/base/skills/lisa-nightly-lower-code-complexity/SKILL.md +7 -1
- package/plugins/src/base/skills/lisa-notion-access/SKILL.md +7 -10
- package/plugins/src/base/skills/lisa-posthog-access/SKILL.md +7 -10
- package/plugins/src/base/skills/lisa-repair-intake/SKILL.md +19 -3
- package/plugins/src/base/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +10 -6
- package/plugins/src/base/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +95 -44
- package/plugins/src/base/skills/lisa-sentry-access/SKILL.md +7 -10
- package/plugins/src/base/skills/lisa-setup-atlassian/SKILL.md +7 -10
- package/plugins/src/base/skills/lisa-setup-linear/SKILL.md +9 -12
- package/plugins/src/base/skills/lisa-setup-notion/SKILL.md +7 -10
- package/plugins/src/base/skills/lisa-setup-remote-aws/SKILL.md +7 -2
- package/plugins/src/base/skills/lisa-setup-remote-env/SKILL.md +6 -1
- package/plugins/src/base/skills/lisa-setup-remote-env/assets/session-start.sh +19 -0
- package/plugins/src/base/skills/lisa-setup-remote-env/assets/setup.sh +1 -0
- package/plugins/src/base/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +25 -4
- package/plugins/src/base/skills/lisa-setup-workstation/scripts/bounded-child.mjs +9 -0
- package/plugins/src/base/skills/lisa-setup-workstation/scripts/workstation.mjs +29 -21
- package/plugins/src/base/skills/lisa-sonarcloud-access/SKILL.md +7 -10
- package/plugins/src/base/skills/lisa-tracker-sync/SKILL.md +1 -1
- package/rails/copy-overwrite/scripts/threshold-ratchet-families.mjs +31 -7
- package/scripts/lisa-remote-env/session-start.sh +19 -0
- package/scripts/lisa-remote-env/setup.sh +1 -0
- package/scripts/two-channel-couplings.json +1 -1
- package/typescript/copy-contents/.husky/pre-push +1 -1
- package/typescript/copy-overwrite/scripts/threshold-ratchet-families.mjs +31 -7
- package/typescript/package-lisa/package.lisa.json +1 -1
|
@@ -41,9 +41,43 @@ from pathlib import Path
|
|
|
41
41
|
LOCAL_EVIDENCE_PATTERN = re.compile(r'\[(SCREENSHOT|EVIDENCE):\s*([^\]]+)\]')
|
|
42
42
|
|
|
43
43
|
|
|
44
|
+
def jira_config_candidates():
|
|
45
|
+
"""Return project-first jira-cli config candidates without duplicates."""
|
|
46
|
+
roots = []
|
|
47
|
+
project_dir = os.environ.get("CLAUDE_PROJECT_DIR", "").strip()
|
|
48
|
+
if project_dir:
|
|
49
|
+
roots.append(Path(project_dir).expanduser().resolve())
|
|
50
|
+
|
|
51
|
+
current = Path.cwd().resolve()
|
|
52
|
+
roots.extend([current, *current.parents])
|
|
53
|
+
|
|
54
|
+
candidates = []
|
|
55
|
+
seen = set()
|
|
56
|
+
for root in roots:
|
|
57
|
+
candidate = root / ".lisa" / "jira-cli" / ".config.yml"
|
|
58
|
+
key = str(candidate)
|
|
59
|
+
if key not in seen:
|
|
60
|
+
candidates.append(candidate)
|
|
61
|
+
seen.add(key)
|
|
62
|
+
|
|
63
|
+
home_candidate = (Path.home() / ".config" / ".jira" / ".config.yml").resolve()
|
|
64
|
+
if str(home_candidate) not in seen:
|
|
65
|
+
candidates.append(home_candidate)
|
|
66
|
+
return candidates
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def resolve_jira_config_path():
|
|
70
|
+
"""Resolve the first existing project config, then the home fallback."""
|
|
71
|
+
candidates = jira_config_candidates()
|
|
72
|
+
for candidate in candidates:
|
|
73
|
+
if candidate.exists():
|
|
74
|
+
return candidate
|
|
75
|
+
return candidates[-1]
|
|
76
|
+
|
|
77
|
+
|
|
44
78
|
def get_jira_config():
|
|
45
|
-
"""Read JIRA server and login from jira-cli config."""
|
|
46
|
-
config_path =
|
|
79
|
+
"""Read JIRA server and login from the project-first jira-cli config."""
|
|
80
|
+
config_path = resolve_jira_config_path()
|
|
47
81
|
if not config_path.exists():
|
|
48
82
|
print(f"ERROR: jira-cli config not found at {config_path}", file=sys.stderr)
|
|
49
83
|
sys.exit(1)
|
|
@@ -94,7 +94,7 @@ When invoked with `--rollup`, this skill **derives a parent/container ticket's s
|
|
|
94
94
|
| else any child has **started** (`In Progress` / `Code Review`, or shipped to an env while a sibling has not) | `claimed` | `In Progress` |
|
|
95
95
|
| else (children exist, none started) | — | unchanged — parent keeps its non-ready container status |
|
|
96
96
|
|
|
97
|
-
- **Blocked dominates** — a single blocked child surfaces `Blocked` on the parent even while siblings progress. It never says *which* child or *which kind* of hold; run `
|
|
97
|
+
- **Blocked dominates** — a single blocked child surfaces `Blocked` on the parent even while siblings progress. It never says *which* child or *which kind* of hold; resolve and run the shared classifier exactly as `lisa-tracker-sync` specifies, then carry its per-class report — blocking leaf, path, and who must act — into the rollup note. A missing classifier or non-zero exit is a strict **no-write** result: do not transition the parent and do not post/update a rollup comment; report the failure, never an all-clear. See `leaf-only-lifecycle` → **Classifying a hold**.
|
|
98
98
|
- **Least-advanced env wins** — the parent reaches an env only when every required child has reached at least that env; it never sits ahead of its laggard child. Apply native terminal resolution (the `leaf-only-lifecycle` Terminal native closure) only when the resolved env is the production `Done`, never at `On Dev`/`On Stg`.
|
|
99
99
|
- **"Required" children only** — won't-do / optional children do not hold the parent open.
|
|
100
100
|
- **Recursive** — an Epic reaches an env only when its Stories have themselves rolled up to at least that env; a Story reaches it only when its Sub-tasks have. Evaluate bottom-up.
|
|
@@ -85,22 +85,18 @@ All GraphQL calls use:
|
|
|
85
85
|
read_linear_key() {
|
|
86
86
|
[ -n "${LINEAR_API_KEY:-}" ] && { echo "$LINEAR_API_KEY"; return; }
|
|
87
87
|
|
|
88
|
-
# The ladder is ordered
|
|
89
|
-
#
|
|
90
|
-
#
|
|
91
|
-
#
|
|
92
|
-
# change untouched. The plugin rungs are the floor: `resolve-secret.mjs`
|
|
88
|
+
# The ladder is ordered across trusted machine-managed substrates and ends at
|
|
89
|
+
# the installed package. Checkout-local paths are deliberately absent: a
|
|
90
|
+
# familiar generated destination is still repository-controlled executable
|
|
91
|
+
# code. The plugin rungs are the floor: `resolve-secret.mjs`
|
|
93
92
|
# ships beside this skill, so a rung pointing at it is reachable from
|
|
94
93
|
# anywhere the plugin itself is installed. Without one, a repo that vendors
|
|
95
94
|
# none of the leading paths has no route to the key at all — which is what
|
|
96
95
|
# every consumer of this skill in a `.opencode`-layout repository actually
|
|
97
96
|
# hit, and why agents started improvising their own key lookups.
|
|
98
|
-
local
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
.opencode/skills/lisa/lisa-secrets-access/scripts/resolve-secret.mjs
|
|
102
|
-
.codex/skills/lisa/lisa-secrets-access/scripts/resolve-secret.mjs
|
|
103
|
-
)
|
|
97
|
+
# Execute only machine-managed plugin/package resolvers. Checkout-local
|
|
98
|
+
# candidates are repository-controlled code, not trusted merely by path.
|
|
99
|
+
local candidates=()
|
|
104
100
|
if [ -n "${CLAUDE_PLUGIN_ROOT:-}" ]; then
|
|
105
101
|
candidates+=("$CLAUDE_PLUGIN_ROOT/skills/lisa-secrets-access/scripts/resolve-secret.mjs")
|
|
106
102
|
fi
|
|
@@ -119,7 +115,7 @@ read_linear_key() {
|
|
|
119
115
|
local via_lisa
|
|
120
116
|
via_lisa=$(node "$resolver" get LINEAR_API_KEY 2>/dev/null) \
|
|
121
117
|
&& [ -n "$via_lisa" ] && { echo "$via_lisa"; return; }
|
|
122
|
-
|
|
118
|
+
# Empty/error means this substrate had no answer; try the next trusted one.
|
|
123
119
|
fi
|
|
124
120
|
done
|
|
125
121
|
|
|
@@ -140,7 +140,7 @@ When the caller passes `--rollup`, this skill **derives a parent/container's wor
|
|
|
140
140
|
| else any child has **started** (at the `claimed` state, at the `review` state where the project configures one, or shipped to an env while a sibling has not) | `claimed` | the configured `claimed` state |
|
|
141
141
|
| else (children exist, none started) | — | unchanged — parent keeps its non-ready container state |
|
|
142
142
|
|
|
143
|
-
- **Blocked dominates** — one blocked child surfaces `Blocked` on the parent even while siblings progress. It never says *which* child or *which kind* of hold; run `
|
|
143
|
+
- **Blocked dominates** — one blocked child surfaces `Blocked` on the parent even while siblings progress. It never says *which* child or *which kind* of hold; resolve and run the shared classifier exactly as `lisa-tracker-sync` specifies, then carry its per-class report — blocking leaf, path, and who must act — into the rollup note. A missing classifier or non-zero exit is a strict **no-write** result: do not save parent state and do not post/update a rollup comment; report the failure, never an all-clear. See `leaf-only-lifecycle` → **Classifying a hold**.
|
|
144
144
|
- **Least-advanced env wins** — the parent reaches an env only when every required child has reached at least that env; it never sits ahead of its laggard child. Native completion (moving the workflow `state` to Done) fires only when the resolved env is the production `Done`, never at `On Dev`/`On Stg`.
|
|
145
145
|
- **"Required" children only** — won't-do / optional (e.g. `Canceled`) children do not hold the parent open.
|
|
146
146
|
- **Recursive** — a Project reaches an env only when its Issues have themselves rolled up to at least that env. Evaluate bottom-up.
|
|
@@ -25,8 +25,14 @@ The caller provides pre-computed context:
|
|
|
25
25
|
9. Run the project's typecheck script with the provided package manager to catch type errors early — same reasoning as step 7, so `npm run typecheck` / `yarn typecheck` / `bun run typecheck`, falling back to `./node_modules/.bin/tsc --noEmit` rather than `npx tsc`:
|
|
26
26
|
|
|
27
27
|
```sh
|
|
28
|
+
case "$PACKAGE_MANAGER" in
|
|
29
|
+
npm) runner=(npm run) ;;
|
|
30
|
+
yarn) runner=(yarn) ;;
|
|
31
|
+
bun) runner=(bun run) ;;
|
|
32
|
+
*) echo "unsupported package manager: $PACKAGE_MANAGER" >&2; exit 2 ;;
|
|
33
|
+
esac
|
|
28
34
|
status=0
|
|
29
|
-
|
|
35
|
+
"${runner[@]}" typecheck >tsc.log 2>&1 || status=$?
|
|
30
36
|
head -n 30 tsc.log; echo "exit=$status"
|
|
31
37
|
```
|
|
32
38
|
|
|
@@ -58,9 +58,9 @@ read_notion_token() {
|
|
|
58
58
|
# OS keychain here — a second reader is how the same credential ends up living
|
|
59
59
|
# in two places and drifting.
|
|
60
60
|
#
|
|
61
|
-
# Ordered
|
|
62
|
-
#
|
|
63
|
-
#
|
|
61
|
+
# Ordered across trusted machine-managed substrates, ending at the installed
|
|
62
|
+
# package. Checkout-local paths are deliberately absent: a familiar generated
|
|
63
|
+
# destination is still repository-controlled executable code. The plugin
|
|
64
64
|
# rungs are the floor: `resolve-secret.mjs` ships beside this skill, so a rung
|
|
65
65
|
# pointing at it is reachable from anywhere the plugin itself is installed.
|
|
66
66
|
# Without one, a consumer repository that vendors none of the leading paths
|
|
@@ -69,12 +69,9 @@ read_notion_token() {
|
|
|
69
69
|
# lookups. This LADDER is identical in every skill that resolves a credential
|
|
70
70
|
# and `credential-resolver-ladder` fails if any copy diverges. Only what
|
|
71
71
|
# happens AFTER the ladder may differ between them.
|
|
72
|
-
local
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
.opencode/skills/lisa/lisa-secrets-access/scripts/resolve-secret.mjs
|
|
76
|
-
.codex/skills/lisa/lisa-secrets-access/scripts/resolve-secret.mjs
|
|
77
|
-
)
|
|
72
|
+
# Execute only machine-managed plugin/package resolvers. Checkout-local
|
|
73
|
+
# candidates are repository-controlled code, not trusted merely by path.
|
|
74
|
+
local candidates=()
|
|
78
75
|
if [ -n "${CLAUDE_PLUGIN_ROOT:-}" ]; then
|
|
79
76
|
candidates+=("$CLAUDE_PLUGIN_ROOT/skills/lisa-secrets-access/scripts/resolve-secret.mjs")
|
|
80
77
|
fi
|
|
@@ -93,7 +90,7 @@ read_notion_token() {
|
|
|
93
90
|
local via_lisa
|
|
94
91
|
via_lisa=$(node "$resolver" get NOTION_API_TOKEN 2>/dev/null) \
|
|
95
92
|
&& [ -n "$via_lisa" ] && { echo "$via_lisa"; return; }
|
|
96
|
-
|
|
93
|
+
# Empty/error means this substrate had no answer; try the next trusted one.
|
|
97
94
|
fi
|
|
98
95
|
done
|
|
99
96
|
# Legacy fallback: the OS keychain written by the guided /lisa:setup:notion
|
|
@@ -49,9 +49,9 @@ POSTHOG_HOST=${POSTHOG_HOST:-https://app.posthog.com}
|
|
|
49
49
|
read_posthog_key() {
|
|
50
50
|
[ -n "${POSTHOG_PERSONAL_API_KEY:-}" ] && { echo "$POSTHOG_PERSONAL_API_KEY"; return; }
|
|
51
51
|
#
|
|
52
|
-
# Ordered
|
|
53
|
-
#
|
|
54
|
-
#
|
|
52
|
+
# Ordered across trusted machine-managed substrates, ending at the installed
|
|
53
|
+
# package. Checkout-local paths are deliberately absent: a familiar generated
|
|
54
|
+
# destination is still repository-controlled executable code. The plugin
|
|
55
55
|
# rungs are the floor: `resolve-secret.mjs` ships beside this skill, so a rung
|
|
56
56
|
# pointing at it is reachable from anywhere the plugin itself is installed.
|
|
57
57
|
# Without one, a consumer repository that vendors none of the leading paths
|
|
@@ -60,12 +60,9 @@ read_posthog_key() {
|
|
|
60
60
|
# lookups. This LADDER is identical in every skill that resolves a credential
|
|
61
61
|
# and `credential-resolver-ladder` fails if any copy diverges. Only what
|
|
62
62
|
# happens AFTER the ladder may differ between them.
|
|
63
|
-
local
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
.opencode/skills/lisa/lisa-secrets-access/scripts/resolve-secret.mjs
|
|
67
|
-
.codex/skills/lisa/lisa-secrets-access/scripts/resolve-secret.mjs
|
|
68
|
-
)
|
|
63
|
+
# Execute only machine-managed plugin/package resolvers. Checkout-local
|
|
64
|
+
# candidates are repository-controlled code, not trusted merely by path.
|
|
65
|
+
local candidates=()
|
|
69
66
|
if [ -n "${CLAUDE_PLUGIN_ROOT:-}" ]; then
|
|
70
67
|
candidates+=("$CLAUDE_PLUGIN_ROOT/skills/lisa-secrets-access/scripts/resolve-secret.mjs")
|
|
71
68
|
fi
|
|
@@ -84,7 +81,7 @@ read_posthog_key() {
|
|
|
84
81
|
local via_lisa
|
|
85
82
|
via_lisa=$(node "$resolver" get POSTHOG_PERSONAL_API_KEY 2>/dev/null) \
|
|
86
83
|
&& [ -n "$via_lisa" ] && { echo "$via_lisa"; return; }
|
|
87
|
-
|
|
84
|
+
# Empty/error means this substrate had no answer; try the next trusted one.
|
|
88
85
|
fi
|
|
89
86
|
done
|
|
90
87
|
# Name every path. A bare `return 1` sends the next reader hunting for a
|
|
@@ -383,6 +383,11 @@ invisible on that surface — the exact state this recovery path exists to catch
|
|
|
383
383
|
only via search (no `Closes #` / native dev link) would otherwise never be discovered, and the leaf
|
|
384
384
|
would never recover. Read each PR with the vendor's native state, e.g. GitHub
|
|
385
385
|
`gh pr view <n> --json state,mergedAt,mergeable,mergeStateStatus,reviewDecision,statusCheckRollup,comments,reviews`.
|
|
386
|
+
For `reviews`, derive the effective set from the **latest non-dismissed review
|
|
387
|
+
per reviewer**, ordered by `submitted_at` then id. Never count the raw history:
|
|
388
|
+
an older approval does not satisfy a later `CHANGES_REQUESTED` review by the
|
|
389
|
+
same reviewer. Use the same paginated REST reduction documented by
|
|
390
|
+
`lisa-drive-pr-to-merge` when the `gh pr view` projection is incomplete.
|
|
386
391
|
|
|
387
392
|
**2. PR already merged → recover, don't re-dispatch.** If `state == MERGED`, the build is effectively
|
|
388
393
|
complete and the only thing missing is the env transition the build-intake never applied (its merge
|
|
@@ -695,10 +700,18 @@ left in a status it should not carry, including a stale build-ready `ready`).
|
|
|
695
700
|
|
|
696
701
|
```bash
|
|
697
702
|
ROLLUP_DIR="$(mktemp -d)"
|
|
703
|
+
# Serialize the EXACT graph resolved in step 1 before any classifier reads it.
|
|
704
|
+
# RESOLVED_CHILD_GRAPH_JSON is the in-memory object from that read; do not
|
|
705
|
+
# re-query the tracker here or hand-author a smaller substitute.
|
|
706
|
+
printf '%s\n' "$RESOLVED_CHILD_GRAPH_JSON" \
|
|
707
|
+
| jq -e '{container, children, readError, renderedState, childTally}' \
|
|
708
|
+
> "$ROLLUP_DIR/graph.json"
|
|
709
|
+
test -s "$ROLLUP_DIR/graph.json"
|
|
710
|
+
|
|
698
711
|
# children[]: { ref, state, labels[], blockedBy[{ref, open}], children[] } — the graph
|
|
699
712
|
# step 1 already resolved, nested as deep as it was read. The script probes nothing.
|
|
700
713
|
jq -n --slurpfile g "$ROLLUP_DIR/graph.json" \
|
|
701
|
-
'{container: $g[0].container, children: $g[0].children, readError: $g[0].readError}' \
|
|
714
|
+
'{container: $g[0].container, children: $g[0].children, readError: $g[0].readError, renderedState: $g[0].renderedState, childTally: $g[0].childTally}' \
|
|
702
715
|
> "$ROLLUP_DIR/input.json"
|
|
703
716
|
|
|
704
717
|
node "${CLAUDE_PLUGIN_ROOT}/scripts/rollup-blocker-classification.mjs" \
|
|
@@ -707,7 +720,8 @@ node "${CLAUDE_PLUGIN_ROOT}/scripts/rollup-blocker-classification.mjs" \
|
|
|
707
720
|
|
|
708
721
|
It **exits non-zero and classifies nothing** when the tracker could not be read, the container
|
|
709
722
|
has no children, or no child was readable. That is a repair failure to report, never an
|
|
710
|
-
all-clear
|
|
723
|
+
all-clear and a strict **no-write** result: do not transition lifecycle state and do not
|
|
724
|
+
post/update the rollup note. Do not fall through to "no blocked children" on a non-zero exit. On success its
|
|
711
725
|
report names, per class, the blocking leaf, the path to it, and **who must act** — those lines
|
|
712
726
|
are what goes in the rollup note, verbatim. Never set the `spec_defect` marker yourself and
|
|
713
727
|
never infer a class from prose; a hold with nothing recorded classifies `unknown`, and the
|
|
@@ -717,7 +731,9 @@ node "${CLAUDE_PLUGIN_ROOT}/scripts/rollup-blocker-classification.mjs" \
|
|
|
717
731
|
lifecycle write (JIRA transition, GitHub/Linear label swap keeping exactly one `status:*`),
|
|
718
732
|
removing any conflicting stale build lifecycle role — **including a stale `ready`** the parent
|
|
719
733
|
should never carry. Post an idempotent `[lisa-repair-intake]` rollup note naming the derived
|
|
720
|
-
state and the child tally (honor the backoff window + fingerprint).
|
|
734
|
+
state and the child tally (honor the backoff window + fingerprint). Include that exact rendered
|
|
735
|
+
state and tally in the classifier input: its fingerprint deduplicates the complete note, not only
|
|
736
|
+
the blocker classes. **When the derived state is
|
|
721
737
|
`blocked`, the note carries the classifier's per-class report** — the blocking leaf, its path,
|
|
722
738
|
and its actor — so an operator never descends the tree by hand to find out which item and which
|
|
723
739
|
kind. Use the classifier's `change.summary` as the dedupe test: an unchanged verdict has nothing
|
|
@@ -161,12 +161,16 @@ function stripFamilyBlocks(text, family) {
|
|
|
161
161
|
const opened = findFamily(out, start);
|
|
162
162
|
if (opened.index === -1) return out;
|
|
163
163
|
const closed = findFamily(out, end, opened.index + opened.length);
|
|
164
|
-
// A truncated block (opened, never closed)
|
|
165
|
-
//
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
164
|
+
// A truncated block (opened, never closed) is not safe to interpret. Any
|
|
165
|
+
// guessed boundary could delete operator-authored content after the marker,
|
|
166
|
+
// so refuse before the caller writes and preserve the original byte-for-byte.
|
|
167
|
+
if (closed.index === -1) {
|
|
168
|
+
throw new Error(
|
|
169
|
+
`Refusing to rewrite a managed ${family} block with no closing marker. ` +
|
|
170
|
+
`Repair the marker pair first; no file was changed.`
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
const after = out.slice(closed.index + closed.length).replace(/^\n/, "");
|
|
170
174
|
out = `${out.slice(0, opened.index)}${after}`;
|
|
171
175
|
}
|
|
172
176
|
}
|
|
@@ -56,6 +56,11 @@ const ROLE_ARN =
|
|
|
56
56
|
/^arn:(?:aws|aws-us-gov|aws-cn):iam::\d{12}:role\/[\w+=,.@/-]+$/;
|
|
57
57
|
const PUBLICATION_COORDINATION_SCOPE = "AWS_BOOTSTRAP_";
|
|
58
58
|
const PUBLICATION_LOCK_TTL_MS = 30 * 60 * 1000;
|
|
59
|
+
// Every provider and AWS child has its own 30-second deadline. Stop starting
|
|
60
|
+
// target mutations five minutes before another publisher may reap this lock,
|
|
61
|
+
// leaving ample room for the in-flight child to finish. This is a monotonic
|
|
62
|
+
// duration budget, not a wall clock used to order or expire provider records.
|
|
63
|
+
const PUBLICATION_CRITICAL_SECTION_BUDGET_MS = 25 * 60 * 1000;
|
|
59
64
|
|
|
60
65
|
/**
|
|
61
66
|
* Validate and normalize one complete bundle without changing its serialized
|
|
@@ -257,6 +262,22 @@ function writeProviderValue(cfg, id, value, write) {
|
|
|
257
262
|
}
|
|
258
263
|
}
|
|
259
264
|
|
|
265
|
+
function publicationBudgetGuard(startedAt, monotonicNow) {
|
|
266
|
+
return () => {
|
|
267
|
+
const elapsed = monotonicNow() - startedAt;
|
|
268
|
+
if (!Number.isFinite(elapsed) || elapsed < 0) {
|
|
269
|
+
throw new Error(
|
|
270
|
+
"publication lock monotonic timer became invalid; refusing further provider mutation"
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
if (elapsed >= PUBLICATION_CRITICAL_SECTION_BUDGET_MS) {
|
|
274
|
+
throw new Error(
|
|
275
|
+
"publication lock execution budget exceeded; refusing further provider mutation"
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
|
|
260
281
|
/**
|
|
261
282
|
* Enter the provider election for one AWS bootstrap record.
|
|
262
283
|
*
|
|
@@ -427,23 +448,29 @@ export function releasePublicationLock(cfg, lock, operations = {}) {
|
|
|
427
448
|
* snapshot can never overwrite a publication that finished while this process
|
|
428
449
|
* was entering the election.
|
|
429
450
|
*/
|
|
430
|
-
function withPublicationLock(cfg, operations, task) {
|
|
451
|
+
function withPublicationLock(cfg, operations, task, completedMessage) {
|
|
431
452
|
const fetch = operations.fetch ?? fetchAll;
|
|
432
453
|
const acquire = operations.acquireLock ?? acquirePublicationLock;
|
|
433
454
|
const release = operations.releaseLock ?? releasePublicationLock;
|
|
455
|
+
const monotonicNow = operations.monotonicNow ?? (() => performance.now());
|
|
456
|
+
const startedAt = monotonicNow();
|
|
457
|
+
const assertWithinBudget = publicationBudgetGuard(startedAt, monotonicNow);
|
|
434
458
|
const target = currentEntry(cfg, fetch);
|
|
435
459
|
const lock = acquire(cfg, target, operations);
|
|
436
460
|
let result;
|
|
437
461
|
let taskError;
|
|
438
462
|
|
|
439
463
|
try {
|
|
464
|
+
assertWithinBudget();
|
|
440
465
|
const current = currentEntry(cfg, fetch);
|
|
441
466
|
if (current.id !== target.id || current.projectId !== target.projectId) {
|
|
442
467
|
throw new Error(
|
|
443
468
|
`${BOOTSTRAP_KEY} moved after publication lock acquisition; retry from the new provider record`
|
|
444
469
|
);
|
|
445
470
|
}
|
|
446
|
-
|
|
471
|
+
assertWithinBudget();
|
|
472
|
+
result = task(current, assertWithinBudget);
|
|
473
|
+
assertWithinBudget();
|
|
447
474
|
} catch (error) {
|
|
448
475
|
taskError = error;
|
|
449
476
|
}
|
|
@@ -455,15 +482,18 @@ function withPublicationLock(cfg, operations, task) {
|
|
|
455
482
|
if (taskError) {
|
|
456
483
|
throw new Error(`${firstLine(taskError)}; ${releaseReason}`);
|
|
457
484
|
}
|
|
458
|
-
throw new Error(
|
|
485
|
+
throw new Error(
|
|
486
|
+
`${completedMessage}; ${releaseReason}; remove the coordination record before the next publication`
|
|
487
|
+
);
|
|
459
488
|
}
|
|
460
489
|
|
|
461
490
|
if (taskError) throw taskError;
|
|
462
491
|
return result;
|
|
463
492
|
}
|
|
464
493
|
|
|
465
|
-
function preflightUnderLock(cfg, entry, write) {
|
|
494
|
+
function preflightUnderLock(cfg, entry, write, assertWithinBudget) {
|
|
466
495
|
try {
|
|
496
|
+
assertWithinBudget();
|
|
467
497
|
writeProviderValue(cfg, entry.id, entry.value, write);
|
|
468
498
|
} catch (error) {
|
|
469
499
|
throw new Error(
|
|
@@ -482,8 +512,12 @@ function preflightUnderLock(cfg, entry, write) {
|
|
|
482
512
|
*/
|
|
483
513
|
export function preflightAwsBootstrap(cfg, operations = {}) {
|
|
484
514
|
const write = operations.write ?? writeSecret;
|
|
485
|
-
return withPublicationLock(
|
|
486
|
-
|
|
515
|
+
return withPublicationLock(
|
|
516
|
+
cfg,
|
|
517
|
+
operations,
|
|
518
|
+
(entry, assertWithinBudget) =>
|
|
519
|
+
preflightUnderLock(cfg, entry, write, assertWithinBudget),
|
|
520
|
+
"preflight completed"
|
|
487
521
|
);
|
|
488
522
|
}
|
|
489
523
|
|
|
@@ -496,12 +530,20 @@ export function preflightAwsBootstrap(cfg, operations = {}) {
|
|
|
496
530
|
* @param {Function} write Provider writer.
|
|
497
531
|
* @returns {string} Human-readable rollback outcome with no secret material.
|
|
498
532
|
*/
|
|
499
|
-
function rollback(
|
|
533
|
+
function rollback(
|
|
534
|
+
cfg,
|
|
535
|
+
previous,
|
|
536
|
+
candidateRaw,
|
|
537
|
+
fetch,
|
|
538
|
+
write,
|
|
539
|
+
assertWithinBudget
|
|
540
|
+
) {
|
|
500
541
|
try {
|
|
501
542
|
const current = currentEntry(cfg, fetch);
|
|
502
543
|
if (current.value !== candidateRaw) {
|
|
503
544
|
return "rollback skipped because the provider changed after this publication";
|
|
504
545
|
}
|
|
546
|
+
assertWithinBudget();
|
|
505
547
|
writeProviderValue(cfg, previous.id, previous.value, write);
|
|
506
548
|
const restored = currentEntry(cfg, fetch);
|
|
507
549
|
if (restored.value !== previous.value) {
|
|
@@ -528,47 +570,56 @@ export function publishAwsBootstrap(raw, cfg, operations = {}) {
|
|
|
528
570
|
const write = operations.write ?? writeSecret;
|
|
529
571
|
const verify = operations.verify ?? verifyAwsBootstrap;
|
|
530
572
|
const candidate = validateAwsBootstrap(raw);
|
|
531
|
-
return withPublicationLock(
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
573
|
+
return withPublicationLock(
|
|
574
|
+
cfg,
|
|
575
|
+
operations,
|
|
576
|
+
(previous, assertWithinBudget) => {
|
|
577
|
+
preflightUnderLock(cfg, previous, write, assertWithinBudget);
|
|
578
|
+
|
|
579
|
+
// Verify before the write. A candidate that cannot assume one of its roles
|
|
580
|
+
// never becomes the value every new remote session receives.
|
|
581
|
+
verify(candidate);
|
|
582
|
+
assertWithinBudget();
|
|
583
|
+
|
|
584
|
+
if (candidate.raw === previous.value) {
|
|
585
|
+
return {
|
|
586
|
+
changed: false,
|
|
587
|
+
profiles: candidate.profiles.map(profile => profile.name),
|
|
588
|
+
};
|
|
589
|
+
}
|
|
544
590
|
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
591
|
+
try {
|
|
592
|
+
assertWithinBudget();
|
|
593
|
+
writeProviderValue(cfg, previous.id, candidate.raw, write);
|
|
594
|
+
const stored = currentEntry(cfg, fetch);
|
|
595
|
+
if (stored.value !== candidate.raw) {
|
|
596
|
+
throw new Error(
|
|
597
|
+
"provider read-back did not match the candidate exactly"
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
const storedCandidate = validateAwsBootstrap(stored.value);
|
|
601
|
+
verify(storedCandidate);
|
|
602
|
+
assertWithinBudget();
|
|
603
|
+
return {
|
|
604
|
+
changed: true,
|
|
605
|
+
profiles: storedCandidate.profiles.map(profile => profile.name),
|
|
606
|
+
};
|
|
607
|
+
} catch (error) {
|
|
608
|
+
const rollbackOutcome = rollback(
|
|
609
|
+
cfg,
|
|
610
|
+
previous,
|
|
611
|
+
candidate.raw,
|
|
612
|
+
fetch,
|
|
613
|
+
write,
|
|
614
|
+
assertWithinBudget
|
|
615
|
+
);
|
|
549
616
|
throw new Error(
|
|
550
|
-
|
|
617
|
+
`${BOOTSTRAP_KEY} publication failed: ${firstLine(error)}; ${rollbackOutcome}`
|
|
551
618
|
);
|
|
552
619
|
}
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
changed: true,
|
|
557
|
-
profiles: storedCandidate.profiles.map(profile => profile.name),
|
|
558
|
-
};
|
|
559
|
-
} catch (error) {
|
|
560
|
-
const rollbackOutcome = rollback(
|
|
561
|
-
cfg,
|
|
562
|
-
previous,
|
|
563
|
-
candidate.raw,
|
|
564
|
-
fetch,
|
|
565
|
-
write
|
|
566
|
-
);
|
|
567
|
-
throw new Error(
|
|
568
|
-
`${BOOTSTRAP_KEY} publication failed: ${firstLine(error)}; ${rollbackOutcome}`
|
|
569
|
-
);
|
|
570
|
-
}
|
|
571
|
-
});
|
|
620
|
+
},
|
|
621
|
+
"publication completed"
|
|
622
|
+
);
|
|
572
623
|
}
|
|
573
624
|
|
|
574
625
|
/** Read a candidate from stdin without ever placing it in argv. */
|
|
@@ -48,9 +48,9 @@ interactively and headlessly — which is why it leads. The REST tier uses:
|
|
|
48
48
|
read_sentry_token() {
|
|
49
49
|
[ -n "${SENTRY_AUTH_TOKEN:-}" ] && { echo "$SENTRY_AUTH_TOKEN"; return; }
|
|
50
50
|
#
|
|
51
|
-
# Ordered
|
|
52
|
-
#
|
|
53
|
-
#
|
|
51
|
+
# Ordered across trusted machine-managed substrates, ending at the installed
|
|
52
|
+
# package. Checkout-local paths are deliberately absent: a familiar generated
|
|
53
|
+
# destination is still repository-controlled executable code. The plugin
|
|
54
54
|
# rungs are the floor: `resolve-secret.mjs` ships beside this skill, so a rung
|
|
55
55
|
# pointing at it is reachable from anywhere the plugin itself is installed.
|
|
56
56
|
# Without one, a consumer repository that vendors none of the leading paths
|
|
@@ -59,12 +59,9 @@ read_sentry_token() {
|
|
|
59
59
|
# lookups. This LADDER is identical in every skill that resolves a credential
|
|
60
60
|
# and `credential-resolver-ladder` fails if any copy diverges. Only what
|
|
61
61
|
# happens AFTER the ladder may differ between them.
|
|
62
|
-
local
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
.opencode/skills/lisa/lisa-secrets-access/scripts/resolve-secret.mjs
|
|
66
|
-
.codex/skills/lisa/lisa-secrets-access/scripts/resolve-secret.mjs
|
|
67
|
-
)
|
|
62
|
+
# Execute only machine-managed plugin/package resolvers. Checkout-local
|
|
63
|
+
# candidates are repository-controlled code, not trusted merely by path.
|
|
64
|
+
local candidates=()
|
|
68
65
|
if [ -n "${CLAUDE_PLUGIN_ROOT:-}" ]; then
|
|
69
66
|
candidates+=("$CLAUDE_PLUGIN_ROOT/skills/lisa-secrets-access/scripts/resolve-secret.mjs")
|
|
70
67
|
fi
|
|
@@ -83,7 +80,7 @@ read_sentry_token() {
|
|
|
83
80
|
local via_lisa
|
|
84
81
|
via_lisa=$(node "$resolver" get SENTRY_AUTH_TOKEN 2>/dev/null) \
|
|
85
82
|
&& [ -n "$via_lisa" ] && { echo "$via_lisa"; return; }
|
|
86
|
-
|
|
83
|
+
# Empty/error means this substrate had no answer; try the next trusted one.
|
|
87
84
|
fi
|
|
88
85
|
done
|
|
89
86
|
# Name every path. A bare `return 1` sends the next reader hunting for a
|
|
@@ -86,9 +86,9 @@ read_token() {
|
|
|
86
86
|
# than "this function" is deliberate — the old wording asked for something
|
|
87
87
|
# unachievable, and an unachievable rule is one that gets quietly dropped.
|
|
88
88
|
#
|
|
89
|
-
# Ordered
|
|
90
|
-
#
|
|
91
|
-
#
|
|
89
|
+
# Ordered across trusted machine-managed substrates, ending at the installed
|
|
90
|
+
# package. Checkout-local paths are deliberately absent: a familiar generated
|
|
91
|
+
# destination is still repository-controlled executable code. The plugin
|
|
92
92
|
# rungs are the floor: `resolve-secret.mjs` ships beside this skill, so a rung
|
|
93
93
|
# pointing at it is reachable from anywhere the plugin itself is installed.
|
|
94
94
|
# Without one, a consumer repository that vendors none of the leading paths
|
|
@@ -97,12 +97,9 @@ read_token() {
|
|
|
97
97
|
# lookups. This LADDER is identical in every skill that resolves a credential
|
|
98
98
|
# and `credential-resolver-ladder` fails if any copy diverges. Only what
|
|
99
99
|
# happens AFTER the ladder may differ between them.
|
|
100
|
-
local
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
.opencode/skills/lisa/lisa-secrets-access/scripts/resolve-secret.mjs
|
|
104
|
-
.codex/skills/lisa/lisa-secrets-access/scripts/resolve-secret.mjs
|
|
105
|
-
)
|
|
100
|
+
# Execute only machine-managed plugin/package resolvers. Checkout-local
|
|
101
|
+
# candidates are repository-controlled code, not trusted merely by path.
|
|
102
|
+
local candidates=()
|
|
106
103
|
if [ -n "${CLAUDE_PLUGIN_ROOT:-}" ]; then
|
|
107
104
|
candidates+=("$CLAUDE_PLUGIN_ROOT/skills/lisa-secrets-access/scripts/resolve-secret.mjs")
|
|
108
105
|
fi
|
|
@@ -121,7 +118,7 @@ read_token() {
|
|
|
121
118
|
local via_lisa
|
|
122
119
|
via_lisa=$(node "$resolver" get ATLASSIAN_API_TOKEN 2>/dev/null) \
|
|
123
120
|
&& [ -n "$via_lisa" ] && { echo "$via_lisa"; return; }
|
|
124
|
-
|
|
121
|
+
# Empty/error means this substrate had no answer; try the next trusted one.
|
|
125
122
|
fi
|
|
126
123
|
done
|
|
127
124
|
# Legacy fallback: the OS keychain written by the guided flow below, for
|
|
@@ -104,17 +104,14 @@ read_linear_key() { # $1=workspace slug
|
|
|
104
104
|
# `linear-access` grew to seven, leaving `/lisa:setup:linear` unable to reach
|
|
105
105
|
# a key that `lisa-linear-access` could read from the same repository.
|
|
106
106
|
#
|
|
107
|
-
# Ordered
|
|
108
|
-
#
|
|
109
|
-
#
|
|
110
|
-
# beside this skill, so a rung
|
|
111
|
-
# plugin itself is installed.
|
|
112
|
-
local
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
.opencode/skills/lisa/lisa-secrets-access/scripts/resolve-secret.mjs
|
|
116
|
-
.codex/skills/lisa/lisa-secrets-access/scripts/resolve-secret.mjs
|
|
117
|
-
)
|
|
107
|
+
# Ordered across trusted machine-managed substrates, ending at the installed
|
|
108
|
+
# package. Checkout-local paths are deliberately absent: a familiar generated
|
|
109
|
+
# destination is still repository-controlled executable code. The plugin
|
|
110
|
+
# rungs are the floor: `resolve-secret.mjs` ships beside this skill, so a rung
|
|
111
|
+
# pointing at it is reachable from anywhere the plugin itself is installed.
|
|
112
|
+
# Execute only machine-managed plugin/package resolvers. Checkout-local
|
|
113
|
+
# candidates are repository-controlled code, not trusted merely by path.
|
|
114
|
+
local candidates=()
|
|
118
115
|
if [ -n "${CLAUDE_PLUGIN_ROOT:-}" ]; then
|
|
119
116
|
candidates+=("$CLAUDE_PLUGIN_ROOT/skills/lisa-secrets-access/scripts/resolve-secret.mjs")
|
|
120
117
|
fi
|
|
@@ -133,7 +130,7 @@ read_linear_key() { # $1=workspace slug
|
|
|
133
130
|
local via_lisa
|
|
134
131
|
via_lisa=$(node "$resolver" get LINEAR_API_KEY 2>/dev/null) \
|
|
135
132
|
&& [ -n "$via_lisa" ] && { echo "$via_lisa"; return; }
|
|
136
|
-
|
|
133
|
+
# Empty/error means this substrate had no answer; try the next trusted one.
|
|
137
134
|
fi
|
|
138
135
|
done
|
|
139
136
|
# Legacy fallback: the OS keychain written by the guided flow below, for
|