@codyswann/lisa 4.22.9 → 4.22.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/all/copy-overwrite/scripts/check-release-package-identity.mjs +51 -41
- 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 +26 -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 -52
- 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-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-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-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-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-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-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/check-release-package-identity.mjs +51 -41
- 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
|
@@ -90,6 +90,33 @@ function tarMember(tarballPath, member) {
|
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
/** Create the one npm archive whose bytes will be published. */
|
|
94
|
+
function createCandidateArchive(root, packDestination) {
|
|
95
|
+
mkdirSync(packDestination, { recursive: true });
|
|
96
|
+
if (readdirSync(packDestination).length !== 0) {
|
|
97
|
+
mismatch(`pack destination must be empty (${packDestination})`);
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
return String(
|
|
101
|
+
boundedExecFileSync(
|
|
102
|
+
"npm",
|
|
103
|
+
[
|
|
104
|
+
"pack",
|
|
105
|
+
"--ignore-scripts",
|
|
106
|
+
"--silent",
|
|
107
|
+
"--pack-destination",
|
|
108
|
+
packDestination,
|
|
109
|
+
],
|
|
110
|
+
{ cwd: root, encoding: "utf8", timeout: 120_000 }
|
|
111
|
+
)
|
|
112
|
+
);
|
|
113
|
+
} catch (error) {
|
|
114
|
+
mismatch(
|
|
115
|
+
`npm pack failed before publication (${error instanceof Error ? error.message : String(error)})`
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
93
120
|
/** Extract the one workspace package version certified by generated bytes. */
|
|
94
121
|
function certificateVersion(bytes, label) {
|
|
95
122
|
const match = String(bytes).match(
|
|
@@ -115,18 +142,24 @@ export function assertReleaseCommit(releaseCommit) {
|
|
|
115
142
|
* @returns {{headCommit: string, tagCommit: string, releaseCommit: string}}
|
|
116
143
|
*/
|
|
117
144
|
export function assertCheckoutIdentity({ root, releaseCommit, tag }) {
|
|
118
|
-
assertReleaseCommit(releaseCommit);
|
|
145
|
+
const validatedReleaseCommit = assertReleaseCommit(releaseCommit);
|
|
119
146
|
const headCommit = gitCommit(root, "HEAD");
|
|
120
|
-
if (headCommit !==
|
|
147
|
+
if (headCommit !== validatedReleaseCommit) {
|
|
121
148
|
mismatch(
|
|
122
|
-
`HEAD ${headCommit} does not match release commit ${
|
|
149
|
+
`HEAD ${headCommit} does not match release commit ${validatedReleaseCommit}`
|
|
123
150
|
);
|
|
124
151
|
}
|
|
125
152
|
const tagCommit = gitCommit(root, tag);
|
|
126
|
-
if (tagCommit !==
|
|
127
|
-
mismatch(
|
|
153
|
+
if (tagCommit !== validatedReleaseCommit) {
|
|
154
|
+
mismatch(
|
|
155
|
+
`tag ${tag} resolves ${tagCommit}, expected ${validatedReleaseCommit}`
|
|
156
|
+
);
|
|
128
157
|
}
|
|
129
|
-
return Object.freeze({
|
|
158
|
+
return Object.freeze({
|
|
159
|
+
headCommit,
|
|
160
|
+
tagCommit,
|
|
161
|
+
releaseCommit: validatedReleaseCommit,
|
|
162
|
+
});
|
|
130
163
|
}
|
|
131
164
|
|
|
132
165
|
/**
|
|
@@ -140,21 +173,21 @@ export function packAndValidateReleaseCandidate({
|
|
|
140
173
|
releaseCommit,
|
|
141
174
|
packDestination,
|
|
142
175
|
}) {
|
|
143
|
-
assertReleaseCommit(releaseCommit);
|
|
176
|
+
const validatedReleaseCommit = assertReleaseCommit(releaseCommit);
|
|
144
177
|
const packageJson = readJson(path.join(root, "package.json"), "package.json");
|
|
145
178
|
if (packageJson.version !== version) {
|
|
146
179
|
mismatch(
|
|
147
180
|
`package.json version ${JSON.stringify(packageJson.version)} expected ${version}`
|
|
148
181
|
);
|
|
149
182
|
}
|
|
150
|
-
if (packageJson.lisaReleaseCommit !==
|
|
183
|
+
if (packageJson.lisaReleaseCommit !== validatedReleaseCommit) {
|
|
151
184
|
mismatch(
|
|
152
|
-
`package.json lisaReleaseCommit ${JSON.stringify(packageJson.lisaReleaseCommit)} expected ${
|
|
185
|
+
`package.json lisaReleaseCommit ${JSON.stringify(packageJson.lisaReleaseCommit)} expected ${validatedReleaseCommit}`
|
|
153
186
|
);
|
|
154
187
|
}
|
|
155
|
-
if (packageJson.gitHead !==
|
|
188
|
+
if (packageJson.gitHead !== validatedReleaseCommit) {
|
|
156
189
|
mismatch(
|
|
157
|
-
`package.json gitHead ${JSON.stringify(packageJson.gitHead)} expected ${
|
|
190
|
+
`package.json gitHead ${JSON.stringify(packageJson.gitHead)} expected ${validatedReleaseCommit}`
|
|
158
191
|
);
|
|
159
192
|
}
|
|
160
193
|
|
|
@@ -172,30 +205,7 @@ export function packAndValidateReleaseCandidate({
|
|
|
172
205
|
}
|
|
173
206
|
}
|
|
174
207
|
|
|
175
|
-
|
|
176
|
-
if (readdirSync(packDestination).length !== 0) {
|
|
177
|
-
mismatch(`pack destination must be empty (${packDestination})`);
|
|
178
|
-
}
|
|
179
|
-
let packOutput;
|
|
180
|
-
try {
|
|
181
|
-
packOutput = String(
|
|
182
|
-
boundedExecFileSync(
|
|
183
|
-
"npm",
|
|
184
|
-
[
|
|
185
|
-
"pack",
|
|
186
|
-
"--ignore-scripts",
|
|
187
|
-
"--silent",
|
|
188
|
-
"--pack-destination",
|
|
189
|
-
packDestination,
|
|
190
|
-
],
|
|
191
|
-
{ cwd: root, encoding: "utf8", timeout: 120_000 }
|
|
192
|
-
)
|
|
193
|
-
);
|
|
194
|
-
} catch (error) {
|
|
195
|
-
mismatch(
|
|
196
|
-
`npm pack failed before publication (${error instanceof Error ? error.message : String(error)})`
|
|
197
|
-
);
|
|
198
|
-
}
|
|
208
|
+
const packOutput = createCandidateArchive(root, packDestination);
|
|
199
209
|
const candidates = readdirSync(packDestination).filter(file =>
|
|
200
210
|
file.endsWith(".tgz")
|
|
201
211
|
);
|
|
@@ -223,14 +233,14 @@ export function packAndValidateReleaseCandidate({
|
|
|
223
233
|
`packed package version ${JSON.stringify(packedPackage.version)} expected ${version}`
|
|
224
234
|
);
|
|
225
235
|
}
|
|
226
|
-
if (packedPackage.lisaReleaseCommit !==
|
|
236
|
+
if (packedPackage.lisaReleaseCommit !== validatedReleaseCommit) {
|
|
227
237
|
mismatch(
|
|
228
|
-
`packed lisaReleaseCommit ${JSON.stringify(packedPackage.lisaReleaseCommit)} expected ${
|
|
238
|
+
`packed lisaReleaseCommit ${JSON.stringify(packedPackage.lisaReleaseCommit)} expected ${validatedReleaseCommit}`
|
|
229
239
|
);
|
|
230
240
|
}
|
|
231
|
-
if (packedPackage.gitHead !==
|
|
241
|
+
if (packedPackage.gitHead !== validatedReleaseCommit) {
|
|
232
242
|
mismatch(
|
|
233
|
-
`packed gitHead ${JSON.stringify(packedPackage.gitHead)} expected ${
|
|
243
|
+
`packed gitHead ${JSON.stringify(packedPackage.gitHead)} expected ${validatedReleaseCommit}`
|
|
234
244
|
);
|
|
235
245
|
}
|
|
236
246
|
|
|
@@ -241,7 +251,7 @@ export function packAndValidateReleaseCandidate({
|
|
|
241
251
|
packedCertificateVersion = certificateVersion(member, "packed certificate");
|
|
242
252
|
if (packedCertificateVersion !== version) {
|
|
243
253
|
mismatch(
|
|
244
|
-
`packed certificate names ${packedCertificateVersion}, expected ${version} at release commit ${
|
|
254
|
+
`packed certificate names ${packedCertificateVersion}, expected ${version} at release commit ${validatedReleaseCommit} (${PACKED_CERTIFICATE})`
|
|
245
255
|
);
|
|
246
256
|
}
|
|
247
257
|
certificateMemberSha256 = sha256(member);
|
|
@@ -249,7 +259,7 @@ export function packAndValidateReleaseCandidate({
|
|
|
249
259
|
|
|
250
260
|
return Object.freeze({
|
|
251
261
|
version,
|
|
252
|
-
releaseCommit,
|
|
262
|
+
releaseCommit: validatedReleaseCommit,
|
|
253
263
|
certificateVersion: packedCertificateVersion,
|
|
254
264
|
tarballPath,
|
|
255
265
|
tarballSha256: sha256(tarballBytes),
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// This file is managed by Lisa and IS replaced on each `lisa` run.
|
|
3
|
+
// Do not edit directly — durable changes belong upstream in Lisa.
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Run one shell command in its own process group and reap the whole group.
|
|
7
|
+
*
|
|
8
|
+
* Node's synchronous timeout signals only the direct child. A gate command is
|
|
9
|
+
* a tree (shell, package manager, test workers), so killing only the shell
|
|
10
|
+
* leaves descendants running against scratch state the caller then removes.
|
|
11
|
+
* This small asynchronous supervisor is invoked through a synchronous parent:
|
|
12
|
+
* it owns the process-group id, applies the deadline, terminates the group, and
|
|
13
|
+
* only then lets the parent continue.
|
|
14
|
+
* @module scripts/lib/process-tree-runner
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
18
|
+
|
|
19
|
+
import { invokedAsScript } from "./invoked-as-script.mjs";
|
|
20
|
+
|
|
21
|
+
const KILL_GRACE_MS = 750;
|
|
22
|
+
|
|
23
|
+
function parseArguments(argv) {
|
|
24
|
+
const timeoutArg = argv.find(value => value.startsWith("--timeout-ms="));
|
|
25
|
+
const separator = argv.indexOf("--");
|
|
26
|
+
const timeoutMs = Number(timeoutArg?.slice("--timeout-ms=".length));
|
|
27
|
+
const command = separator >= 0 ? argv.slice(separator + 1).join(" ") : "";
|
|
28
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0 || !command) {
|
|
29
|
+
throw new Error(
|
|
30
|
+
"usage: process-tree-runner.mjs --timeout-ms=<positive-ms> -- <command>"
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
return { command, timeoutMs };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function killTree(pid, signal) {
|
|
37
|
+
if (process.platform === "win32") {
|
|
38
|
+
// Windows has no negative-pid process groups. taskkill /T is the native
|
|
39
|
+
// tree primitive; /F is used only for the escalation.
|
|
40
|
+
const args = ["/pid", String(pid), "/T"];
|
|
41
|
+
if (signal === "SIGKILL") args.push("/F");
|
|
42
|
+
spawnSync("taskkill", args, { stdio: "ignore", timeout: KILL_GRACE_MS });
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
process.kill(-pid, signal);
|
|
47
|
+
} catch {
|
|
48
|
+
// ESRCH means the whole group already exited.
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function supervise(command, timeoutMs) {
|
|
53
|
+
return new Promise((resolve, reject) => {
|
|
54
|
+
const shell =
|
|
55
|
+
process.platform === "win32"
|
|
56
|
+
? process.env.ComSpec || "cmd.exe"
|
|
57
|
+
: "/bin/sh";
|
|
58
|
+
const shellArgs =
|
|
59
|
+
process.platform === "win32"
|
|
60
|
+
? ["/d", "/s", "/c", command]
|
|
61
|
+
: ["-c", command];
|
|
62
|
+
const child = spawn(shell, shellArgs, {
|
|
63
|
+
detached: true,
|
|
64
|
+
env: process.env,
|
|
65
|
+
stdio: "inherit",
|
|
66
|
+
});
|
|
67
|
+
const pid = child.pid;
|
|
68
|
+
if (pid === undefined) {
|
|
69
|
+
reject(new Error("gate process tree did not start"));
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
let timedOut = false;
|
|
74
|
+
let settled = false;
|
|
75
|
+
const finish = (code, signal) => {
|
|
76
|
+
if (settled) return;
|
|
77
|
+
settled = true;
|
|
78
|
+
clearTimeout(deadline);
|
|
79
|
+
// A command may leave a background descendant after its direct shell
|
|
80
|
+
// exits. Reap that residue before returning a verdict too.
|
|
81
|
+
killTree(pid, "SIGTERM");
|
|
82
|
+
resolve({ code, signal });
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const deadline = setTimeout(() => {
|
|
86
|
+
timedOut = true;
|
|
87
|
+
killTree(pid, "SIGTERM");
|
|
88
|
+
setTimeout(() => {
|
|
89
|
+
killTree(pid, "SIGKILL");
|
|
90
|
+
// A signal-shaped result is the existing gate runner vocabulary for
|
|
91
|
+
// "no verdict". It also prevents an ordinary exit code such as 124
|
|
92
|
+
// from being confused with a user command that returned that code.
|
|
93
|
+
if (process.platform === "win32") {
|
|
94
|
+
process.exit(124);
|
|
95
|
+
} else {
|
|
96
|
+
process.kill(process.pid, "SIGKILL");
|
|
97
|
+
}
|
|
98
|
+
}, KILL_GRACE_MS);
|
|
99
|
+
}, timeoutMs);
|
|
100
|
+
|
|
101
|
+
child.once("error", error => {
|
|
102
|
+
clearTimeout(deadline);
|
|
103
|
+
killTree(pid, "SIGKILL");
|
|
104
|
+
reject(error);
|
|
105
|
+
});
|
|
106
|
+
child.once("close", (code, signal) => {
|
|
107
|
+
// On timeout, wait for the forced group reap above before this supervisor
|
|
108
|
+
// ends. Exiting on the direct shell's close is the race that used to leave
|
|
109
|
+
// its descendants alive.
|
|
110
|
+
if (!timedOut) finish(code, signal);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function main() {
|
|
116
|
+
const { command, timeoutMs } = parseArguments(process.argv.slice(2));
|
|
117
|
+
const result = await supervise(command, timeoutMs);
|
|
118
|
+
if (result.signal) {
|
|
119
|
+
process.exitCode = 128;
|
|
120
|
+
} else {
|
|
121
|
+
process.exitCode = result.code ?? 1;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (invokedAsScript(import.meta.url)) {
|
|
126
|
+
await main();
|
|
127
|
+
}
|
|
@@ -85,11 +85,45 @@ const DEPENDENCY_SECTIONS = [
|
|
|
85
85
|
* means: `^8` is `>=8.0.0 <9.0.0` and `1.x` is `>=1.0.0 <2.0.0`. Only the lower
|
|
86
86
|
* bound is read here, so the upper half costs nothing to ignore.
|
|
87
87
|
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
88
|
+
* This parser deliberately uses no version-shaped regular expression. The
|
|
89
|
+
* collision gate consumes dependency text supplied by a repository, so even a
|
|
90
|
+
* bounded-looking optional-group expression becomes an avoidable ReDoS review
|
|
91
|
+
* burden. A tiny left-to-right scanner is both clearer and constant-work per
|
|
92
|
+
* input character.
|
|
91
93
|
*/
|
|
92
|
-
|
|
94
|
+
function parseBranchVersion(branch) {
|
|
95
|
+
let cursor = branch.trimStart();
|
|
96
|
+
while (cursor.startsWith("v")) cursor = cursor.slice(1);
|
|
97
|
+
|
|
98
|
+
const operator = [">=", ">", "=", "^", "~"].find(candidate =>
|
|
99
|
+
cursor.startsWith(candidate)
|
|
100
|
+
);
|
|
101
|
+
if (operator) cursor = cursor.slice(operator.length);
|
|
102
|
+
cursor = cursor.trimStart();
|
|
103
|
+
|
|
104
|
+
let end = 0;
|
|
105
|
+
while (end < cursor.length) {
|
|
106
|
+
const character = cursor[end];
|
|
107
|
+
const digit = character >= "0" && character <= "9";
|
|
108
|
+
const next = cursor[end + 1];
|
|
109
|
+
const componentSeparator = character === "." && next >= "0" && next <= "9";
|
|
110
|
+
if (!digit && !componentSeparator) break;
|
|
111
|
+
end += 1;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const parts = cursor.slice(0, end).split(".");
|
|
115
|
+
if (
|
|
116
|
+
parts.length > 3 ||
|
|
117
|
+
parts.some(
|
|
118
|
+
part =>
|
|
119
|
+
part === "" ||
|
|
120
|
+
[...part].some(character => character < "0" || character > "9")
|
|
121
|
+
)
|
|
122
|
+
) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
return { operator, parts };
|
|
126
|
+
}
|
|
93
127
|
|
|
94
128
|
/**
|
|
95
129
|
* Lowest version a single disjunction branch permits.
|
|
@@ -104,13 +138,34 @@ const BRANCH_VERSION = /^[\sv=><~^]*(\d+)(?:\.(\d+))?(?:\.(\d+))?/;
|
|
|
104
138
|
function branchLowerBound(branch) {
|
|
105
139
|
const trimmed = branch.trim();
|
|
106
140
|
if (trimmed === "") return null;
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
141
|
+
const upperOperand = trimmed
|
|
142
|
+
.slice(trimmed.startsWith("<=") ? 2 : 1)
|
|
143
|
+
.trimStart();
|
|
144
|
+
if (
|
|
145
|
+
trimmed.startsWith("<") &&
|
|
146
|
+
upperOperand[0] >= "0" &&
|
|
147
|
+
upperOperand[0] <= "9"
|
|
148
|
+
) {
|
|
149
|
+
return [0, 0, 0];
|
|
150
|
+
}
|
|
151
|
+
const parsed = parseBranchVersion(trimmed);
|
|
152
|
+
if (!parsed) return null;
|
|
110
153
|
// An absent minor or patch is zero, not missing: `^8` is `>=8.0.0`. Number()
|
|
111
154
|
// of undefined is NaN, which would compare as neither higher nor lower than
|
|
112
155
|
// anything and quietly disable the comparison it feeds.
|
|
113
|
-
|
|
156
|
+
const lower = [...parsed.parts, "0", "0"].slice(0, 3).map(Number);
|
|
157
|
+
if (parsed.operator !== ">") return lower;
|
|
158
|
+
|
|
159
|
+
// npm expands a STRICT comparator on a partial version before comparing:
|
|
160
|
+
// `>1` is `>=2.0.0` and `>1.2` is `>=1.3.0`. Reading either as merely
|
|
161
|
+
// 1.0.0/1.2.0 invents versions the range does not permit and can report an
|
|
162
|
+
// adequate dependency line as weaker than its override.
|
|
163
|
+
const lastSpecified = parsed.parts.length - 1;
|
|
164
|
+
lower[lastSpecified] += 1;
|
|
165
|
+
for (let index = lastSpecified + 1; index < lower.length; index += 1) {
|
|
166
|
+
lower[index] = 0;
|
|
167
|
+
}
|
|
168
|
+
return lower;
|
|
114
169
|
}
|
|
115
170
|
|
|
116
171
|
/**
|
|
@@ -1067,8 +1067,38 @@ readonly AGENT_CREDENTIAL='(\.(claude|codex|cursor|copilot|gemini|antigravity)/[
|
|
|
1067
1067
|
# 15d. Dotenv files. `.env.example`, `.sample`, `.template`, `.dist` and
|
|
1068
1068
|
# `.schema` are checked-in documentation of which keys exist, never the values,
|
|
1069
1069
|
# so they are excluded — that collision is the one this rule most had to avoid.
|
|
1070
|
-
|
|
1071
|
-
|
|
1070
|
+
# Decide dotenv privacy per PATH, never by subtracting one command-wide match
|
|
1071
|
+
# from another. A command that names `.env.example` and `.env` contains both a
|
|
1072
|
+
# public path and a private one; seeing the former cannot authorize the latter.
|
|
1073
|
+
#
|
|
1074
|
+
# The one write-only shape this guard has always allowed remains explicit:
|
|
1075
|
+
# seeding a private dotenv destination from one public template. This is safe
|
|
1076
|
+
# because the private path is the destination, not a value being read back.
|
|
1077
|
+
has_private_dotenv_path() {
|
|
1078
|
+
dotenv_scan_status=0
|
|
1079
|
+
dotenv_candidates="$(printf '%s' "$normalized_command_str" \
|
|
1080
|
+
| grep -Eio -- '(^|[[:space:]='"$qc"'./])\.env(\.[[:alnum:]_-]+)?')" \
|
|
1081
|
+
|| dotenv_scan_status=$?
|
|
1082
|
+
if [ "$dotenv_scan_status" -gt 1 ]; then
|
|
1083
|
+
block "dotenv path classification failed; denying the credential-store read fail-closed."
|
|
1084
|
+
fi
|
|
1085
|
+
|
|
1086
|
+
while IFS= read -r candidate; do
|
|
1087
|
+
[ -n "$candidate" ] || continue
|
|
1088
|
+
candidate="$(printf '%s' "$candidate" \
|
|
1089
|
+
| tr '[:upper:]' '[:lower:]' \
|
|
1090
|
+
| grep -Eo -- '\.env(\.[[:alnum:]_-]+)?')"
|
|
1091
|
+
case "$candidate" in
|
|
1092
|
+
.env.example | .env.sample | .env.template | .env.dist | .env.schema | .env.defaults) ;;
|
|
1093
|
+
*) return 0 ;;
|
|
1094
|
+
esac
|
|
1095
|
+
done <<EOF
|
|
1096
|
+
$dotenv_candidates
|
|
1097
|
+
EOF
|
|
1098
|
+
return 1
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
readonly SAFE_DOTENV_SEED='^[[:space:]]*(cp|mv)[[:space:]]+\.env\.(example|sample|template|dist|schema|defaults)[[:space:]]+\.env(\.[[:alnum:]_-]+)?[[:space:]]*$'
|
|
1072
1102
|
|
|
1073
1103
|
if matches "$SECRET_READ_VERB"; then
|
|
1074
1104
|
if matches "$SSH_PRIVATE_KEY"; then
|
|
@@ -1080,10 +1110,10 @@ if matches "$SECRET_READ_VERB"; then
|
|
|
1080
1110
|
if matches "$AGENT_CREDENTIAL"; then
|
|
1081
1111
|
block "reading, copying or transmitting a coding-agent or package-registry credential store. These tokens impersonate the operator to every service the agent can reach."
|
|
1082
1112
|
fi
|
|
1083
|
-
#
|
|
1084
|
-
#
|
|
1085
|
-
#
|
|
1086
|
-
if
|
|
1113
|
+
# A public path elsewhere in the command never exempts a private path. The
|
|
1114
|
+
# narrow public-template -> private-destination seed is write-only and remains
|
|
1115
|
+
# allowed; every other command containing a private dotenv path is refused.
|
|
1116
|
+
if has_private_dotenv_path && ! matches "$SAFE_DOTENV_SEED"; then
|
|
1087
1117
|
block "reading, copying or transmitting a dotenv file holding real values. \`.env.example\`, \`.env.sample\`, \`.env.template\` and \`.env.dist\` are readable, and WRITING a .env is unaffected — only reading one back is refused."
|
|
1088
1118
|
fi
|
|
1089
1119
|
# Fail-closed, narrowly. A read whose DIRECTORY is a known credential store
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
48
48
|
import { dirname, join } from "node:path";
|
|
49
49
|
|
|
50
|
-
import { boundedSpawnSync } from "./lib/bounded-spawn.mjs";
|
|
50
|
+
import { boundedSpawnSync, isChildTimeout } from "./lib/bounded-spawn.mjs";
|
|
51
51
|
import { invokedAsScript } from "./lib/invoked-as-script.mjs";
|
|
52
52
|
|
|
53
53
|
/**
|
|
@@ -148,18 +148,40 @@ export function runPostinstall(cwd = process.cwd(), env = process.env) {
|
|
|
148
148
|
return;
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
151
|
+
let child;
|
|
152
|
+
try {
|
|
153
|
+
child = boundedSpawnSync(
|
|
154
|
+
process.execPath,
|
|
155
|
+
[LISA_ENTRY, "--yes", "--skip-git-check", "."],
|
|
156
|
+
{
|
|
157
|
+
cwd,
|
|
158
|
+
env: { ...env, LISA_BOOTSTRAP: "1" },
|
|
159
|
+
encoding: "utf8",
|
|
160
|
+
// Inherited, NOT captured-and-discarded. The whole point.
|
|
161
|
+
stdio: ["ignore", "inherit", "pipe"],
|
|
162
|
+
timeout: APPLY_BUDGET_MS,
|
|
163
|
+
}
|
|
164
|
+
);
|
|
165
|
+
} catch (error) {
|
|
166
|
+
// A timeout is a failed APPLY, not a failed INSTALL. The bounded child
|
|
167
|
+
// deliberately throws so ordinary callers fail closed; this caller has a
|
|
168
|
+
// stronger, documented contract to leave a durable marker and let the
|
|
169
|
+
// package manager finish. Unknown throws still escape because converting a
|
|
170
|
+
// broken postinstall module into an apparent apply failure would hide the
|
|
171
|
+
// defect that needs fixing.
|
|
172
|
+
if (!isChildTimeout(error)) throw error;
|
|
173
|
+
child = {
|
|
174
|
+
error: Object.assign(
|
|
175
|
+
new Error(
|
|
176
|
+
"Lisa template apply exceeded its ten-minute deadline and was killed."
|
|
177
|
+
),
|
|
178
|
+
{ code: "ETIMEDOUT" }
|
|
179
|
+
),
|
|
180
|
+
status: null,
|
|
181
|
+
stderr:
|
|
182
|
+
"Lisa template apply exceeded its ten-minute deadline and was killed.\n",
|
|
183
|
+
};
|
|
184
|
+
}
|
|
163
185
|
|
|
164
186
|
const stderr = child.stderr ?? "";
|
|
165
187
|
if (stderr) process.stderr.write(stderr);
|
|
@@ -718,9 +718,17 @@ export function reconcileContexts({
|
|
|
718
718
|
if (record.ruleset !== undefined && entry.ruleset !== record.ruleset) {
|
|
719
719
|
return false;
|
|
720
720
|
}
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
721
|
+
// Configured ruleset policy defaults to GitHub Actions when it carries no
|
|
722
|
+
// explicit pin. That is the same default the writer applies, so comparison
|
|
723
|
+
// and repair converge. A gate-derived record names no ruleset and remains
|
|
724
|
+
// name-only: it never declared which app may satisfy it.
|
|
725
|
+
if (record.ruleset !== undefined) {
|
|
726
|
+
const expected = record.integration_id ?? ACTIONS_INTEGRATION_ID;
|
|
727
|
+
return entry.integration_id === expected;
|
|
728
|
+
}
|
|
729
|
+
return (
|
|
730
|
+
record.integration_id === undefined ||
|
|
731
|
+
entry.integration_id === record.integration_id
|
|
724
732
|
);
|
|
725
733
|
};
|
|
726
734
|
const unsatisfied = declarations.filter(
|
|
@@ -358,10 +358,9 @@ function normaliseExec(raw) {
|
|
|
358
358
|
* ## Two kinds that look eligible and are not
|
|
359
359
|
*
|
|
360
360
|
* `uncaptured` is NOT here, and the attempt to include it is what proves the
|
|
361
|
-
* distinction. Capture is
|
|
362
|
-
* so `uncaptured` is
|
|
363
|
-
*
|
|
364
|
-
* `lint` gate exiting 1. A gate that exited nonzero did measure something; the
|
|
361
|
+
* distinction. Capture is on by default (`LISA_GATES_CAPTURE=0` turns it off),
|
|
362
|
+
* so `uncaptured` is an explicit loss of diagnostic evidence rather than the
|
|
363
|
+
* ordinary outcome. A gate that exited nonzero did measure something; the
|
|
365
364
|
* runner merely did not keep the transcript. Missing evidence about a real
|
|
366
365
|
* failure is not the same claim as a captured transcript that describes no
|
|
367
366
|
* failure at all, which is what `undiagnosed` means.
|
|
@@ -888,6 +887,33 @@ const CAPTURE_TAIL_BYTES = 512 * 1024;
|
|
|
888
887
|
*/
|
|
889
888
|
const GATE_COMMAND_BUDGET_MS = 2 * 60 * 60 * 1000;
|
|
890
889
|
|
|
890
|
+
/** Extra ceiling for the supervisor to reap descendants after its deadline. */
|
|
891
|
+
const PROCESS_TREE_REAP_BUDGET_MS = 10_000;
|
|
892
|
+
|
|
893
|
+
/** The asynchronous supervisor used behind this synchronous gate API. */
|
|
894
|
+
const PROCESS_TREE_RUNNER = fileURLToPath(
|
|
895
|
+
new URL("./lib/process-tree-runner.mjs", import.meta.url)
|
|
896
|
+
);
|
|
897
|
+
|
|
898
|
+
/**
|
|
899
|
+
* Run a shell command under a process-tree deadline.
|
|
900
|
+
* @param {string} command Shell source.
|
|
901
|
+
* @param {object} options Child options passed to the supervisor.
|
|
902
|
+
* @returns {import("node:child_process").SpawnSyncReturns<string>} Result.
|
|
903
|
+
*/
|
|
904
|
+
function runProcessTree(command, options = {}) {
|
|
905
|
+
const timeout = options.timeout ?? GATE_COMMAND_BUDGET_MS;
|
|
906
|
+
const { shell: _shell, ...childOptions } = options;
|
|
907
|
+
return boundedSpawnSync(
|
|
908
|
+
process.execPath,
|
|
909
|
+
[PROCESS_TREE_RUNNER, `--timeout-ms=${timeout}`, "--", command],
|
|
910
|
+
{
|
|
911
|
+
...childOptions,
|
|
912
|
+
timeout: timeout + PROCESS_TREE_REAP_BUDGET_MS,
|
|
913
|
+
}
|
|
914
|
+
);
|
|
915
|
+
}
|
|
916
|
+
|
|
891
917
|
/**
|
|
892
918
|
* Convert a killed child into this file's no-verdict answer, or re-raise.
|
|
893
919
|
*
|
|
@@ -916,8 +942,7 @@ function killedOrRethrow(error) {
|
|
|
916
942
|
*/
|
|
917
943
|
function plainExec(command) {
|
|
918
944
|
try {
|
|
919
|
-
const child =
|
|
920
|
-
shell: true,
|
|
945
|
+
const child = runProcessTree(command, {
|
|
921
946
|
stdio: "inherit",
|
|
922
947
|
timeout: GATE_COMMAND_BUDGET_MS,
|
|
923
948
|
});
|
|
@@ -1015,9 +1040,17 @@ export function spawnExec(command) {
|
|
|
1015
1040
|
const statusPath = join(dir, "status");
|
|
1016
1041
|
// Newline-separated inside a group, so a command ending in a trailing
|
|
1017
1042
|
// comment or redirection still has `echo` run as its own statement.
|
|
1018
|
-
|
|
1043
|
+
// Paths travel as data, never as shell source. A TMPDIR containing a quote,
|
|
1044
|
+
// newline, dollar sign, or command substitution must not be able to break
|
|
1045
|
+
// this wrapper or execute content merely because mkdtemp inherited it.
|
|
1046
|
+
const script = `{\n${command}\necho $? > "$LISA_GATE_STATUS_PATH"\n} 2>&1 | tee "$LISA_GATE_LOG_PATH"\n`;
|
|
1019
1047
|
try {
|
|
1020
|
-
const child =
|
|
1048
|
+
const child = runProcessTree(script, {
|
|
1049
|
+
env: {
|
|
1050
|
+
...process.env,
|
|
1051
|
+
LISA_GATE_LOG_PATH: logPath,
|
|
1052
|
+
LISA_GATE_STATUS_PATH: statusPath,
|
|
1053
|
+
},
|
|
1021
1054
|
stdio: "inherit",
|
|
1022
1055
|
timeout: GATE_COMMAND_BUDGET_MS,
|
|
1023
1056
|
});
|
|
@@ -150,9 +150,9 @@ function resolveRef(ref, root) {
|
|
|
150
150
|
const defs = isSchemaObject(root.$defs) ? root.$defs : {};
|
|
151
151
|
const target =
|
|
152
152
|
match && Object.hasOwn(defs, match[1]) ? defs[match[1]] : undefined;
|
|
153
|
-
if (!target) {
|
|
153
|
+
if (!isSchemaObject(target)) {
|
|
154
154
|
throw new Error(
|
|
155
|
-
`unsupported or unresolvable $ref "${ref}" (only #/$defs/<name> is supported)`
|
|
155
|
+
`unsupported or unresolvable $ref "${ref}" (only #/$defs/<name> resolving to a subschema object is supported)`
|
|
156
156
|
);
|
|
157
157
|
}
|
|
158
158
|
return target;
|
|
@@ -536,7 +536,8 @@ function verifyLevel(config) {
|
|
|
536
536
|
throw new TrackingError(
|
|
537
537
|
`Unknown workItem.verify '${raw}'. Expected "trailer" (the default: ` +
|
|
538
538
|
`prove the Work-Item reference, contact no tracker) or "full" (also ` +
|
|
539
|
-
`prove the tracker item
|
|
539
|
+
`prove the tracker item exists and is open, has repo scope, is a leaf, ` +
|
|
540
|
+
`and carries the PR backlink)`
|
|
540
541
|
);
|
|
541
542
|
}
|
|
542
543
|
return value;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"prepare": "husky install || true",
|
|
9
9
|
"test": "vitest run",
|
|
10
10
|
"test:unit": "vitest run --exclude='**/integration/**'",
|
|
11
|
-
"test:integration:lisa": "vitest run '.integration.' 'integration/'
|
|
11
|
+
"test:integration:lisa": "vitest run '.integration.' 'integration/'",
|
|
12
12
|
"test:cov": "vitest run --coverage",
|
|
13
13
|
"test:mutation": "node scripts/lisa-mutation.mjs",
|
|
14
14
|
"test:watch": "vitest",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lisa-owned-hash-ledger.d.ts","sourceRoot":"","sources":["../../src/core/lisa-owned-hash-ledger.ts"],"names":[],"mappings":"AACA,6EAA6E;AAE7E;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAC3C,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"lisa-owned-hash-ledger.d.ts","sourceRoot":"","sources":["../../src/core/lisa-owned-hash-ledger.ts"],"names":[],"mappings":"AACA,6EAA6E;AAE7E;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAC3C,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CA8tBjC,CAAC;AAEH;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,+BAA+B,EAAE,QAAQ,CACpD,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAioBjC,CAAC"}
|