@codyswann/lisa 3.4.1 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -0
- package/all/copy-contents/gitignore +7 -0
- package/all/copy-overwrite/scripts/lisa-command-envelope.mjs +44 -4
- package/all/copy-overwrite/scripts/lisa-schema-validate.mjs +125 -47
- package/cdk/merge/.oxlintrc.json +1 -1
- package/dist/cli/apply.d.ts.map +1 -1
- package/dist/cli/apply.js +48 -13
- package/dist/cli/apply.js.map +1 -1
- package/dist/cli/doctor-apply-freshness.d.ts +29 -0
- package/dist/cli/doctor-apply-freshness.d.ts.map +1 -0
- package/dist/cli/doctor-apply-freshness.js +194 -0
- package/dist/cli/doctor-apply-freshness.js.map +1 -0
- package/dist/cli/doctor-learnings-merge-driver.d.ts +23 -0
- package/dist/cli/doctor-learnings-merge-driver.d.ts.map +1 -0
- package/dist/cli/doctor-learnings-merge-driver.js +73 -0
- package/dist/cli/doctor-learnings-merge-driver.js.map +1 -0
- package/dist/cli/doctor-readiness-workflows.js +2 -2
- package/dist/cli/doctor-readiness-workflows.js.map +1 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +13 -0
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/ui-ci-quality-jobs-parse.js +2 -2
- package/dist/cli/ui-ci-quality-jobs-parse.js.map +1 -1
- package/dist/cli/ui-deploy-pipeline-model.d.ts +4 -0
- package/dist/cli/ui-deploy-pipeline-model.d.ts.map +1 -1
- package/dist/cli/ui-deploy-pipeline-model.js +2 -2
- package/dist/cli/ui-deploy-pipeline-model.js.map +1 -1
- package/dist/codex/agent-transformer.js +2 -2
- package/dist/codex/agent-transformer.js.map +1 -1
- package/dist/codex/command-skill-transformer.js +3 -3
- package/dist/codex/command-skill-transformer.js.map +1 -1
- package/dist/core/apply-receipt.d.ts +68 -0
- package/dist/core/apply-receipt.d.ts.map +1 -0
- package/dist/core/apply-receipt.js +107 -0
- package/dist/core/apply-receipt.js.map +1 -0
- package/dist/core/learnings-merge-driver-install.d.ts +34 -0
- package/dist/core/learnings-merge-driver-install.d.ts.map +1 -1
- package/dist/core/learnings-merge-driver-install.js +36 -0
- package/dist/core/learnings-merge-driver-install.js.map +1 -1
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +53 -31
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/dist/migrations/ensure-lisa-postinstall.d.ts +33 -0
- package/dist/migrations/ensure-lisa-postinstall.d.ts.map +1 -1
- package/dist/migrations/ensure-lisa-postinstall.js +47 -5
- package/dist/migrations/ensure-lisa-postinstall.js.map +1 -1
- package/dist/migrations/ensure-oxlint-base-configs.d.ts +42 -0
- package/dist/migrations/ensure-oxlint-base-configs.d.ts.map +1 -0
- package/dist/migrations/ensure-oxlint-base-configs.js +212 -0
- package/dist/migrations/ensure-oxlint-base-configs.js.map +1 -0
- package/dist/migrations/index.d.ts +1 -0
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/migrations/index.js +3 -0
- package/dist/migrations/index.js.map +1 -1
- package/dist/opencode/command-transformer.js +3 -3
- package/dist/opencode/command-transformer.js.map +1 -1
- package/dist/utils/yaml.d.ts +54 -0
- package/dist/utils/yaml.d.ts.map +1 -0
- package/dist/utils/yaml.js +124 -0
- package/dist/utils/yaml.js.map +1 -0
- package/expo/copy-overwrite/scripts/bdd/baseline.mjs +104 -19
- package/expo/copy-overwrite/scripts/bdd/contract.mjs +20 -1
- package/expo/copy-overwrite/scripts/bdd/discover.mjs +53 -10
- package/expo/copy-overwrite/scripts/bdd/parse.mjs +25 -3
- package/expo/copy-overwrite/scripts/bdd/render.mjs +2 -1
- package/expo/copy-overwrite/scripts/bdd/report.mjs +26 -12
- package/expo/copy-overwrite/scripts/bdd/validate.mjs +2 -2
- package/expo/copy-overwrite/scripts/bdd/waivers.mjs +19 -4
- package/expo/copy-overwrite/scripts/bdd-matrix.mjs +2 -2
- package/expo/copy-overwrite/scripts/check-bdd-coverage.mjs +58 -16
- package/expo/create-only/.github/required-checks.json +10 -4
- package/expo/merge/.oxlintrc.json +1 -1
- package/harper-fabric/merge/.oxlintrc.json +1 -1
- package/nestjs/create-only/.github/required-checks.json +57 -0
- package/nestjs/merge/.oxlintrc.json +1 -1
- package/package.json +1 -1
- package/phaser/merge/.oxlintrc.json +1 -1
- 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 +7 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-jam-access/SKILL.md +37 -2
- package/plugins/lisa/.codex-plugin/skills/lisa-notion-access/SKILL.md +7 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-posthog-access/SKILL.md +40 -3
- package/plugins/lisa/.codex-plugin/skills/lisa-sentry-access/SKILL.md +44 -3
- package/plugins/lisa/.codex-plugin/skills/lisa-sonarcloud-access/SKILL.md +56 -0
- package/plugins/lisa/rules/eager/credential-substrate-precedence.md +3 -1
- package/plugins/lisa/rules/reference/credential-substrate-precedence.md +20 -0
- package/plugins/lisa/skills/lisa-atlassian-access/SKILL.md +7 -0
- package/plugins/lisa/skills/lisa-jam-access/SKILL.md +37 -2
- package/plugins/lisa/skills/lisa-notion-access/SKILL.md +7 -0
- package/plugins/lisa/skills/lisa-posthog-access/SKILL.md +40 -3
- package/plugins/lisa/skills/lisa-sentry-access/SKILL.md +44 -3
- package/plugins/lisa/skills/lisa-sonarcloud-access/SKILL.md +56 -0
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/skills/lisa-atlassian-access/SKILL.md +7 -0
- package/plugins/lisa-agy/skills/lisa-jam-access/SKILL.md +37 -2
- package/plugins/lisa-agy/skills/lisa-notion-access/SKILL.md +7 -0
- package/plugins/lisa-agy/skills/lisa-posthog-access/SKILL.md +40 -3
- package/plugins/lisa-agy/skills/lisa-sentry-access/SKILL.md +44 -3
- package/plugins/lisa-agy/skills/lisa-sonarcloud-access/SKILL.md +56 -0
- 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/rules/eager/credential-substrate-precedence.md +3 -1
- package/plugins/lisa-copilot/rules/reference/credential-substrate-precedence.md +20 -0
- package/plugins/lisa-copilot/skills/lisa-atlassian-access/SKILL.md +7 -0
- package/plugins/lisa-copilot/skills/lisa-jam-access/SKILL.md +37 -2
- package/plugins/lisa-copilot/skills/lisa-notion-access/SKILL.md +7 -0
- package/plugins/lisa-copilot/skills/lisa-posthog-access/SKILL.md +40 -3
- package/plugins/lisa-copilot/skills/lisa-sentry-access/SKILL.md +44 -3
- package/plugins/lisa-copilot/skills/lisa-sonarcloud-access/SKILL.md +56 -0
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/rules/credential-substrate-precedence-reference.mdc +20 -0
- package/plugins/lisa-cursor/rules/credential-substrate-precedence.mdc +3 -1
- package/plugins/lisa-cursor/skills/lisa-atlassian-access/SKILL.md +7 -0
- package/plugins/lisa-cursor/skills/lisa-jam-access/SKILL.md +37 -2
- package/plugins/lisa-cursor/skills/lisa-notion-access/SKILL.md +7 -0
- package/plugins/lisa-cursor/skills/lisa-posthog-access/SKILL.md +40 -3
- package/plugins/lisa-cursor/skills/lisa-sentry-access/SKILL.md +44 -3
- package/plugins/lisa-cursor/skills/lisa-sonarcloud-access/SKILL.md +56 -0
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-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/rules/eager/credential-substrate-precedence.md +3 -1
- package/plugins/src/base/rules/reference/credential-substrate-precedence.md +20 -0
- package/plugins/src/base/skills/lisa-atlassian-access/SKILL.md +7 -0
- package/plugins/src/base/skills/lisa-jam-access/SKILL.md +37 -2
- package/plugins/src/base/skills/lisa-notion-access/SKILL.md +7 -0
- package/plugins/src/base/skills/lisa-posthog-access/SKILL.md +40 -3
- package/plugins/src/base/skills/lisa-sentry-access/SKILL.md +44 -3
- package/plugins/src/base/skills/lisa-sonarcloud-access/SKILL.md +56 -0
- package/scripts/install-claude-plugins.sh +5 -1
- package/typescript/copy-overwrite/scripts/check-skipped-required-checks.mjs +298 -26
- package/typescript/create-only/.github/required-checks.json +11 -6
- package/typescript/create-only/.github/workflows/required-checks-drift.yml +84 -0
- package/typescript/merge/.oxlintrc.json +1 -1
|
@@ -20,7 +20,9 @@ scope for that skill's work.
|
|
|
20
20
|
`lisa-secrets-access`, chosen whenever its bootstrap credential is available **and**
|
|
21
21
|
the resolved substrate identity-matches the configured tenant/workspace/site.
|
|
22
22
|
`lisa-secrets-access` is the single chokepoint — never read an OS keychain a second
|
|
23
|
-
time.
|
|
23
|
+
time. The two legacy OS-keychain rungs that remain (`lisa-atlassian-access`,
|
|
24
|
+
`lisa-notion-access`) are a dated migration ramp with a **removal date of
|
|
25
|
+
2026-11-01**, not a standing exemption; no new access skill may add one.
|
|
24
26
|
2. **Tier 2 — interactive MCP**, used only when tier 1 is *genuinely* unavailable:
|
|
25
27
|
no bootstrap, no adapter for the operation (per-operation, not per-session), or a
|
|
26
28
|
provider outage. "The MCP happens to be authenticated" and "tier 1 is slower" are
|
|
@@ -139,6 +139,26 @@ operation, the fallback is guarded — never the normal path:
|
|
|
139
139
|
A successful pre-flight switch is not sufficient for tenant safety — another process can
|
|
140
140
|
mutate global state between the check and the write.
|
|
141
141
|
|
|
142
|
+
## Legacy OS-keychain fallback — removal date 2026-11-01
|
|
143
|
+
|
|
144
|
+
Two access skills (`lisa-atlassian-access`, `lisa-notion-access`) still read an
|
|
145
|
+
OS keychain as a last rung below the chokepoint, because the guided
|
|
146
|
+
`/lisa:setup:atlassian` and `/lisa:setup:notion` flows wrote credentials there
|
|
147
|
+
before `lisa-secrets-access` existed. That rung is a **migration ramp with a
|
|
148
|
+
removal date, not a standing exemption**: it is a second reader of the same
|
|
149
|
+
credential, which is exactly how one credential ends up living in two places and
|
|
150
|
+
drifting, and a keychain entry is machine-local ambient state that no headless
|
|
151
|
+
surface can reach — so a project resting on it has no working tier 1 in cron, CI,
|
|
152
|
+
or a cloud session.
|
|
153
|
+
|
|
154
|
+
**Both rungs are deleted on 2026-11-01.** Before then, projects still on the
|
|
155
|
+
keychain path move the credential into their configured provider — re-running
|
|
156
|
+
`/lisa:setup:<vendor>` stores it through the chokepoint. After removal, a
|
|
157
|
+
keychain-only project fails loudly with the exact variable named (tier 3), which
|
|
158
|
+
is the intended outcome: it can never silently resolve through a substrate
|
|
159
|
+
authenticated elsewhere. No new access skill may add a keychain rung; a credential
|
|
160
|
+
the chokepoint cannot answer for is a setup gap to fix, not a store to add.
|
|
161
|
+
|
|
142
162
|
## Consequences to expect
|
|
143
163
|
|
|
144
164
|
- **A stale or wrong token now fails identity-match instead of silently succeeding
|
|
@@ -69,6 +69,13 @@ read_atlassian_token() {
|
|
|
69
69
|
# Legacy fallback: the OS keychain written by the guided /lisa:setup:atlassian
|
|
70
70
|
# flow, for projects that have not adopted a credentials provider. Reached only
|
|
71
71
|
# when the chokepoint is absent or has no entry.
|
|
72
|
+
#
|
|
73
|
+
# This rung is REMOVED ON 2026-11-01 — a dated migration ramp, not a standing
|
|
74
|
+
# exemption (see credential-substrate-precedence, "Legacy OS-keychain fallback
|
|
75
|
+
# — removal date"). A keychain entry is machine-local ambient state no headless
|
|
76
|
+
# surface can reach, so a project resting on it has no working tier 1 in cron,
|
|
77
|
+
# CI, or a cloud session. Re-run /lisa:setup:atlassian before that date to
|
|
78
|
+
# store ATLASSIAN_API_TOKEN through the chokepoint instead.
|
|
72
79
|
case "$(uname -s)" in
|
|
73
80
|
Darwin) security find-generic-password -s lisa-atlassian -a "$email" -w 2>/dev/null ;;
|
|
74
81
|
Linux) command -v secret-tool >/dev/null && secret-tool lookup service lisa-atlassian account "$email" 2>/dev/null ;;
|
|
@@ -39,20 +39,55 @@ headlessly — which is why it leads. The CLI tier uses:
|
|
|
39
39
|
```bash
|
|
40
40
|
curl -fsSL https://native.jam.dev/install | bash
|
|
41
41
|
export PATH="$HOME/.local/bin:$PATH"
|
|
42
|
-
|
|
42
|
+
|
|
43
|
+
# Resolve the PAT through the chokepoint before giving up on the environment.
|
|
44
|
+
# `$JAM_PAT` is the documented fallback, not the only rung: without this, a
|
|
45
|
+
# project that keeps its credentials in Bitwarden, Doppler, or AWS has no tier 1
|
|
46
|
+
# path at all and silently resolves through the interactive MCP — the exact
|
|
47
|
+
# divergence `credential-substrate-precedence` exists to remove.
|
|
48
|
+
read_jam_pat() {
|
|
49
|
+
[ -n "${JAM_PAT:-}" ] && { echo "$JAM_PAT"; return; }
|
|
50
|
+
local resolver
|
|
51
|
+
for resolver in .claude/skills/lisa-secrets-access/scripts/resolve-secret.mjs \
|
|
52
|
+
.agents/skills/lisa-secrets-access/scripts/resolve-secret.mjs; do
|
|
53
|
+
if [ -f "$resolver" ]; then
|
|
54
|
+
local via_lisa
|
|
55
|
+
via_lisa=$(node "$resolver" get JAM_PAT 2>/dev/null) \
|
|
56
|
+
&& [ -n "$via_lisa" ] && { echo "$via_lisa"; return; }
|
|
57
|
+
break
|
|
58
|
+
fi
|
|
59
|
+
done
|
|
60
|
+
return 1
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
# Piped, never written to disk and never passed as an argv token: a PAT on a
|
|
64
|
+
# command line is readable from the process table by every user on the host.
|
|
65
|
+
read_jam_pat | jam auth login --token
|
|
43
66
|
jam skills install
|
|
44
67
|
```
|
|
45
68
|
|
|
46
69
|
If neither tier works, fail with:
|
|
47
70
|
|
|
48
71
|
```text
|
|
49
|
-
Error: no Jam access substrate available. Authenticate the Jam MCP or
|
|
72
|
+
Error: no Jam access substrate available. Authenticate the Jam MCP, set JAM_PAT, or store JAM_PAT in this project's secrets provider.
|
|
50
73
|
```
|
|
51
74
|
|
|
75
|
+
## Mutation boundary
|
|
76
|
+
|
|
77
|
+
Every operation in the Invocation Contract is **read-only** — fetching a trace,
|
|
78
|
+
a recording, or a bug report. So the `credential-substrate-precedence` guarded
|
|
79
|
+
fallback for mutating operations (write, read back, assert the tenant from the
|
|
80
|
+
response, roll back on mismatch) is not engaged here, and a failed tier is
|
|
81
|
+
simply skipped. A future operation that mutates Jam state — commenting on or
|
|
82
|
+
deleting a Jam — is a write and MUST reconcile by read-back before any retry.
|
|
83
|
+
|
|
52
84
|
## Invariants
|
|
53
85
|
|
|
54
86
|
- Tier order is `credential-substrate-precedence`: `JAM_PAT` CLI first, Jam MCP as
|
|
55
87
|
a preserved first-class fallback. Do not retry a failed tier blindly.
|
|
88
|
+
- The PAT is resolved through `lisa-secrets-access`, with the bare `JAM_PAT`
|
|
89
|
+
environment variable as the documented fallback. Never read a second
|
|
90
|
+
credential store directly.
|
|
56
91
|
- Never commit a Jam PAT into `.mcp.json` or any generated setup artifact.
|
|
57
92
|
- Headless Jam access requires `native.jam.dev` for the installer and
|
|
58
93
|
`api.jam.dev` for CLI/API calls in any custom remote network allowlist.
|
|
@@ -70,6 +70,13 @@ read_notion_token() {
|
|
|
70
70
|
# Legacy fallback: the OS keychain written by the guided /lisa:setup:notion
|
|
71
71
|
# flow, for projects that have not adopted a credentials provider. Reached only
|
|
72
72
|
# when the chokepoint is absent or has no entry.
|
|
73
|
+
#
|
|
74
|
+
# This rung is REMOVED ON 2026-11-01 — a dated migration ramp, not a standing
|
|
75
|
+
# exemption (see credential-substrate-precedence, "Legacy OS-keychain fallback
|
|
76
|
+
# — removal date"). A keychain entry is machine-local ambient state no headless
|
|
77
|
+
# surface can reach, so a project resting on it has no working tier 1 in cron,
|
|
78
|
+
# CI, or a cloud session. Re-run /lisa:setup:notion before that date to store
|
|
79
|
+
# NOTION_API_TOKEN through the chokepoint instead.
|
|
73
80
|
case "$(uname -s)" in
|
|
74
81
|
Darwin) security find-generic-password -s lisa-notion -a "$workspace" -w 2>/dev/null ;;
|
|
75
82
|
Linux) command -v secret-tool >/dev/null && \
|
|
@@ -40,15 +40,38 @@ works interactively and headlessly — which is why it leads. The REST tier uses
|
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
42
|
POSTHOG_HOST=${POSTHOG_HOST:-https://app.posthog.com}
|
|
43
|
+
|
|
44
|
+
# Resolve the key through the chokepoint before giving up on the environment.
|
|
45
|
+
# `$POSTHOG_PERSONAL_API_KEY` is the documented fallback, not the only rung:
|
|
46
|
+
# without this, a project that keeps its credentials in Bitwarden, Doppler, or
|
|
47
|
+
# AWS has no tier 1 path at all and silently resolves through the interactive
|
|
48
|
+
# MCP — the exact divergence `credential-substrate-precedence` exists to remove.
|
|
49
|
+
read_posthog_key() {
|
|
50
|
+
[ -n "${POSTHOG_PERSONAL_API_KEY:-}" ] && { echo "$POSTHOG_PERSONAL_API_KEY"; return; }
|
|
51
|
+
local resolver
|
|
52
|
+
for resolver in .claude/skills/lisa-secrets-access/scripts/resolve-secret.mjs \
|
|
53
|
+
.agents/skills/lisa-secrets-access/scripts/resolve-secret.mjs; do
|
|
54
|
+
if [ -f "$resolver" ]; then
|
|
55
|
+
local via_lisa
|
|
56
|
+
via_lisa=$(node "$resolver" get POSTHOG_PERSONAL_API_KEY 2>/dev/null) \
|
|
57
|
+
&& [ -n "$via_lisa" ] && { echo "$via_lisa"; return; }
|
|
58
|
+
break
|
|
59
|
+
fi
|
|
60
|
+
done
|
|
61
|
+
return 1
|
|
62
|
+
}
|
|
63
|
+
|
|
43
64
|
posthog_api() {
|
|
44
65
|
local path="$1"
|
|
45
66
|
local method="${2:-GET}"
|
|
46
67
|
local body="${3:-}"
|
|
47
|
-
|
|
48
|
-
|
|
68
|
+
local key
|
|
69
|
+
key=$(read_posthog_key) || {
|
|
70
|
+
echo "Error: no PostHog key. Set POSTHOG_PERSONAL_API_KEY, or store it as" >&2
|
|
71
|
+
echo "POSTHOG_PERSONAL_API_KEY in this project's secrets provider." >&2
|
|
49
72
|
return 1
|
|
50
73
|
}
|
|
51
|
-
local args=(-sS -X "$method" -H "Authorization: Bearer $
|
|
74
|
+
local args=(-sS -X "$method" -H "Authorization: Bearer $key")
|
|
52
75
|
[ -n "$body" ] && args+=(-H "Content-Type: application/json" --data-binary "$body")
|
|
53
76
|
curl "${args[@]}" "${POSTHOG_HOST%/}/api${path}"
|
|
54
77
|
}
|
|
@@ -60,11 +83,25 @@ If neither tier works, fail with:
|
|
|
60
83
|
Error: no PostHog access substrate available. Authenticate the PostHog MCP or set POSTHOG_PERSONAL_API_KEY.
|
|
61
84
|
```
|
|
62
85
|
|
|
86
|
+
## Mutation boundary
|
|
87
|
+
|
|
88
|
+
Every operation in the Invocation Contract is **read-only** — analytics
|
|
89
|
+
retrieval. `query` is an HTTP POST, but it reads: it submits a query body and
|
|
90
|
+
changes no PostHog state. So the `credential-substrate-precedence` guarded
|
|
91
|
+
fallback for mutating operations (write, read back, assert the tenant from the
|
|
92
|
+
response, roll back on mismatch) is not engaged here, and a failed tier is
|
|
93
|
+
simply skipped. Adding a genuinely mutating operation — creating an insight,
|
|
94
|
+
editing a feature flag — pulls that protocol in: a write of unknown outcome MUST
|
|
95
|
+
reconcile by read-back before any retry.
|
|
96
|
+
|
|
63
97
|
## Invariants
|
|
64
98
|
|
|
65
99
|
- Tier order is `credential-substrate-precedence`: `POSTHOG_PERSONAL_API_KEY`
|
|
66
100
|
first, the PostHog MCP as a preserved first-class fallback. Identity-match
|
|
67
101
|
against the configured project is mandatory on every tier.
|
|
102
|
+
- The key is resolved through `lisa-secrets-access`, with the bare
|
|
103
|
+
`POSTHOG_PERSONAL_API_KEY` environment variable as the documented fallback.
|
|
104
|
+
Never read a second credential store directly.
|
|
68
105
|
- `POSTHOG_HOST` defaults to PostHog Cloud but can point at a self-hosted
|
|
69
106
|
deployment.
|
|
70
107
|
- Consumer skills do not embed PostHog REST paths.
|
|
@@ -39,28 +39,69 @@ Sentry documents API auth tokens for REST API calls, and the same token works
|
|
|
39
39
|
interactively and headlessly — which is why it leads. The REST tier uses:
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
|
+
# Resolve the token through the chokepoint before giving up on the environment.
|
|
43
|
+
# `$SENTRY_AUTH_TOKEN` is the documented fallback, not the only rung: without
|
|
44
|
+
# this, a project that keeps its credentials in Bitwarden, Doppler, or AWS has
|
|
45
|
+
# no tier 1 path at all and silently resolves through the interactive MCP —
|
|
46
|
+
# the exact divergence `credential-substrate-precedence` exists to remove.
|
|
47
|
+
# Mirrors `linear-access`, `atlassian-access`, and `notion-access`.
|
|
48
|
+
read_sentry_token() {
|
|
49
|
+
[ -n "${SENTRY_AUTH_TOKEN:-}" ] && { echo "$SENTRY_AUTH_TOKEN"; return; }
|
|
50
|
+
local resolver
|
|
51
|
+
for resolver in .claude/skills/lisa-secrets-access/scripts/resolve-secret.mjs \
|
|
52
|
+
.agents/skills/lisa-secrets-access/scripts/resolve-secret.mjs; do
|
|
53
|
+
if [ -f "$resolver" ]; then
|
|
54
|
+
local via_lisa
|
|
55
|
+
via_lisa=$(node "$resolver" get SENTRY_AUTH_TOKEN 2>/dev/null) \
|
|
56
|
+
&& [ -n "$via_lisa" ] && { echo "$via_lisa"; return; }
|
|
57
|
+
break
|
|
58
|
+
fi
|
|
59
|
+
done
|
|
60
|
+
return 1
|
|
61
|
+
}
|
|
62
|
+
|
|
42
63
|
sentry_api() {
|
|
43
64
|
local path="$1"
|
|
44
|
-
|
|
45
|
-
|
|
65
|
+
local token
|
|
66
|
+
token=$(read_sentry_token) || {
|
|
67
|
+
echo "Error: no Sentry auth token. Set SENTRY_AUTH_TOKEN, or store it as" >&2
|
|
68
|
+
echo "SENTRY_AUTH_TOKEN in this project's secrets provider." >&2
|
|
46
69
|
return 1
|
|
47
70
|
}
|
|
48
71
|
curl -sS "https://sentry.io/api/0${path}" \
|
|
49
|
-
-H "Authorization: Bearer $
|
|
72
|
+
-H "Authorization: Bearer $token"
|
|
50
73
|
}
|
|
51
74
|
```
|
|
52
75
|
|
|
76
|
+
Tier 1a authenticates `sentry-cli` from the **same resolved token**
|
|
77
|
+
(`SENTRY_AUTH_TOKEN=$(read_sentry_token) sentry-cli …`) — never from a second
|
|
78
|
+
credential store, and never from an interactive `sentry-cli login` keychain.
|
|
79
|
+
|
|
53
80
|
If neither tier works, fail with:
|
|
54
81
|
|
|
55
82
|
```text
|
|
56
83
|
Error: no Sentry access substrate available. Authenticate Sentry MCP/CLI or set SENTRY_AUTH_TOKEN.
|
|
57
84
|
```
|
|
58
85
|
|
|
86
|
+
## Mutation boundary
|
|
87
|
+
|
|
88
|
+
Every operation in the Invocation Contract is **read-only** — issue, event, and
|
|
89
|
+
release retrieval. So the `credential-substrate-precedence` guarded fallback for
|
|
90
|
+
mutating operations (write, read back, assert the tenant from the response, roll
|
|
91
|
+
back on mismatch) is not engaged here, and a failed tier is simply skipped. Any
|
|
92
|
+
future operation that mutates Sentry state — resolving an issue, editing a
|
|
93
|
+
release — is a write and MUST reconcile by read-back under that protocol before
|
|
94
|
+
any retry; do not add one to the contract without it.
|
|
95
|
+
|
|
59
96
|
## Invariants
|
|
60
97
|
|
|
61
98
|
- Tier order is `credential-substrate-precedence`: `SENTRY_AUTH_TOKEN` first, the
|
|
62
99
|
Sentry MCP as a preserved first-class fallback. Identity-match against the
|
|
63
100
|
configured org/project is mandatory on every tier.
|
|
101
|
+
- The token is resolved through `lisa-secrets-access`, with the bare
|
|
102
|
+
`SENTRY_AUTH_TOKEN` environment variable as the documented fallback. Never read
|
|
103
|
+
a second credential store (OS keychain, `~/.sentryclirc` token) directly — the
|
|
104
|
+
one-store rule lives at the chokepoint.
|
|
64
105
|
- Org/project come from `.sentryclirc`, `.lisa.config.json`, or explicit
|
|
65
106
|
operation args; never infer by searching all accessible orgs.
|
|
66
107
|
- Consumer skills do not embed Sentry REST paths.
|
|
@@ -34,6 +34,49 @@ SonarQube Cloud org. Do **not** substitute the raw MCP-image names
|
|
|
34
34
|
running the Docker image directly, and the `sonar` CLI ignores them (auth exits
|
|
35
35
|
non-zero). The CI scan gate's `SONAR_TOKEN` is a third, separate name.
|
|
36
36
|
|
|
37
|
+
### Where those variables come from
|
|
38
|
+
|
|
39
|
+
The `sonar` CLI reads them **from the environment only** — it has no provider
|
|
40
|
+
integration of its own — so on a surface that deliberately materializes nothing
|
|
41
|
+
to disk the credential can be provisioned and unreachable at the same time.
|
|
42
|
+
Resolve it through `lisa-secrets-access` and export it into the launching
|
|
43
|
+
process, exactly as the shared `sonar-secrets.sh` hook already does. The bare
|
|
44
|
+
`$SONARQUBE_CLI_TOKEN` in the environment is the documented **fallback** rung,
|
|
45
|
+
not the only one:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Preferred: the one sanctioned reader. Without this rung a project keeping its
|
|
49
|
+
# credentials in Bitwarden, Doppler, or AWS cannot authenticate the MCP at all,
|
|
50
|
+
# and Sonar access degrades to "run `sonar auth login` in a browser" — dead in
|
|
51
|
+
# cron, CI, and cloud sessions. See `credential-substrate-precedence`.
|
|
52
|
+
read_sonar_secret() {
|
|
53
|
+
local name="$1"
|
|
54
|
+
[ -n "${!name:-}" ] && { echo "${!name}"; return; }
|
|
55
|
+
local resolver
|
|
56
|
+
for resolver in .claude/skills/lisa-secrets-access/scripts/resolve-secret.mjs \
|
|
57
|
+
.agents/skills/lisa-secrets-access/scripts/resolve-secret.mjs; do
|
|
58
|
+
if [ -f "$resolver" ]; then
|
|
59
|
+
local via_lisa
|
|
60
|
+
via_lisa=$(node "$resolver" get "$name" 2>/dev/null) \
|
|
61
|
+
&& [ -n "$via_lisa" ] && { echo "$via_lisa"; return; }
|
|
62
|
+
break
|
|
63
|
+
fi
|
|
64
|
+
done
|
|
65
|
+
return 1
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
# Exported into this process only. Writing it anywhere durable would create a
|
|
69
|
+
# second live copy of a credential whose single store is the provider.
|
|
70
|
+
SONARQUBE_CLI_TOKEN=$(read_sonar_secret SONARQUBE_CLI_TOKEN) && export SONARQUBE_CLI_TOKEN
|
|
71
|
+
SONARQUBE_CLI_ORG=$(read_sonar_secret SONARQUBE_CLI_ORG) && export SONARQUBE_CLI_ORG
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`sonar-secrets.sh` runs the same resolution with a longer search path (it also
|
|
75
|
+
probes `.codex/skills/…` and `node_modules/@codyswann/lisa/plugins/lisa/…`,
|
|
76
|
+
because a hook fires in checkouts that never installed an agent plugin) and with
|
|
77
|
+
a timeout, because it sits in front of every prompt. Use its search order
|
|
78
|
+
verbatim when this skill runs inside a hook.
|
|
79
|
+
|
|
37
80
|
Wiring is performed once by `/lisa:setup:sonar` (which drives `sonar integrate
|
|
38
81
|
<agent>`); this access layer assumes the MCP is already wired. This is distinct
|
|
39
82
|
from the CI `SONAR_TOKEN` secret that authenticates the SonarCloud scan job in
|
|
@@ -79,9 +122,22 @@ Pass the project key through the tool's `projectKey` argument (or rely on a
|
|
|
79
122
|
server-configured `SONARQUBE_PROJECT_KEY`); pass `branch` / `pullRequest` where the
|
|
80
123
|
tool accepts them.
|
|
81
124
|
|
|
125
|
+
## Mutation boundary
|
|
126
|
+
|
|
127
|
+
Every operation in the map above is **read-only** — quality, coverage, and
|
|
128
|
+
security data. So the `credential-substrate-precedence` guarded fallback for
|
|
129
|
+
mutating operations (write, read back, assert the tenant from the response, roll
|
|
130
|
+
back on mismatch) is not engaged here; with one substrate there is nothing to
|
|
131
|
+
fall back to in any case. A future operation that mutates Sonar state — marking
|
|
132
|
+
a hotspot safe, changing an issue's status — is a write and MUST reconcile by
|
|
133
|
+
read-back before any retry.
|
|
134
|
+
|
|
82
135
|
## Invariants
|
|
83
136
|
|
|
84
137
|
- The official SonarQube MCP is the only substrate; there is no REST fallback.
|
|
138
|
+
- `SONARQUBE_CLI_*` values are resolved through `lisa-secrets-access` and
|
|
139
|
+
exported in-process, with the bare environment variables as the documented
|
|
140
|
+
fallback. Never write them to a dotfile or a `.env` on a local surface.
|
|
85
141
|
- Auth is env-var only (`SONARQUBE_CLI_TOKEN` [+ `SONARQUBE_CLI_ORG` | `SONARQUBE_CLI_SERVER`]);
|
|
86
142
|
never the interactive `sonar auth login` keychain flow inside a factory.
|
|
87
143
|
- Sonar host access requires the host (`sonarcloud.io`, `sonarqube.us`, or the
|
|
@@ -177,7 +177,11 @@ if [ "$IS_LISA_SELF" != "true" ] && [ -z "${CI:-}" ]; then
|
|
|
177
177
|
if [ "$HOST_HAS_LISA_POSTINSTALL" = "true" ]; then
|
|
178
178
|
echo "Lisa apply deferred to the host project's own postinstall script."
|
|
179
179
|
elif ! LISA_BOOTSTRAP=1 node "$LISA_DIR/dist/index.js" --yes --skip-git-check "$PROJECT_ROOT"; then
|
|
180
|
-
|
|
180
|
+
# Loud but non-fatal, for the same reason as the host-side bootstrap: a
|
|
181
|
+
# postinstall that exits non-zero aborts the whole install. The durable
|
|
182
|
+
# signal is the apply receipt this failed run did NOT write, which
|
|
183
|
+
# `lisa doctor` reports (CodySwannGT/lisa#2467).
|
|
184
|
+
echo "⚠️ lisa: TEMPLATE APPLY FAILED (error above) - this project is NOT receiving Lisa template or guardrail updates. Diagnose with: node $LISA_DIR/dist/index.js doctor" >&2
|
|
181
185
|
fi
|
|
182
186
|
fi
|
|
183
187
|
|