@codyswann/lisa 2.296.1 → 2.297.1

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.
Files changed (114) hide show
  1. package/dist/cli/doctor-sonar.d.ts +15 -0
  2. package/dist/cli/doctor-sonar.d.ts.map +1 -0
  3. package/dist/cli/doctor-sonar.js +28 -0
  4. package/dist/cli/doctor-sonar.js.map +1 -0
  5. package/dist/cli/doctor.d.ts +2 -0
  6. package/dist/cli/doctor.d.ts.map +1 -1
  7. package/dist/cli/doctor.js +4 -0
  8. package/dist/cli/doctor.js.map +1 -1
  9. package/dist/core/lisa.d.ts +13 -0
  10. package/dist/core/lisa.d.ts.map +1 -1
  11. package/dist/core/lisa.js +44 -0
  12. package/dist/core/lisa.js.map +1 -1
  13. package/dist/core/project-config-kane.d.ts +9 -0
  14. package/dist/core/project-config-kane.d.ts.map +1 -1
  15. package/dist/core/project-config-kane.js +35 -3
  16. package/dist/core/project-config-kane.js.map +1 -1
  17. package/dist/core/sonar-integration.d.ts +30 -0
  18. package/dist/core/sonar-integration.d.ts.map +1 -0
  19. package/dist/core/sonar-integration.js +55 -0
  20. package/dist/core/sonar-integration.js.map +1 -0
  21. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  22. package/dist/core/upstream-evidence-manifest.js +25 -4
  23. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  24. package/dist/sonar/sonar-installer.d.ts +19 -0
  25. package/dist/sonar/sonar-installer.d.ts.map +1 -0
  26. package/dist/sonar/sonar-installer.js +69 -0
  27. package/dist/sonar/sonar-installer.js.map +1 -0
  28. package/package.json +1 -1
  29. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  30. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  31. package/plugins/lisa/.codex-plugin/skills/lisa-analyze-claude-remote/SKILL.md +6 -6
  32. package/plugins/lisa/.codex-plugin/skills/lisa-generate-claude-remote-build-script/SKILL.md +14 -6
  33. package/plugins/lisa/.codex-plugin/skills/lisa-setup-sonar/SKILL.md +108 -0
  34. package/plugins/lisa/.codex-plugin/skills/lisa-setup-sonar/agents/openai.yaml +4 -0
  35. package/plugins/lisa/.codex-plugin/skills/lisa-sonarcloud-access/SKILL.md +58 -46
  36. package/plugins/lisa/commands/setup/sonar.md +7 -0
  37. package/plugins/lisa/rules/reference/integration-access-layer.md +10 -2
  38. package/plugins/lisa/skills/lisa-analyze-claude-remote/SKILL.md +6 -6
  39. package/plugins/lisa/skills/lisa-generate-claude-remote-build-script/SKILL.md +14 -6
  40. package/plugins/lisa/skills/lisa-setup-sonar/SKILL.md +108 -0
  41. package/plugins/lisa/skills/lisa-setup-sonar/agents/openai.yaml +4 -0
  42. package/plugins/lisa/skills/lisa-sonarcloud-access/SKILL.md +59 -47
  43. package/plugins/lisa/skills/lisa-sonarcloud-access/agents/openai.yaml +2 -2
  44. package/plugins/lisa-agy/commands/lisa/setup/sonar.md +7 -0
  45. package/plugins/lisa-agy/plugin.json +1 -1
  46. package/plugins/lisa-agy/skills/lisa-analyze-claude-remote/SKILL.md +6 -6
  47. package/plugins/lisa-agy/skills/lisa-generate-claude-remote-build-script/SKILL.md +14 -6
  48. package/plugins/lisa-agy/skills/lisa-setup-sonar/SKILL.md +108 -0
  49. package/plugins/lisa-agy/skills/lisa-sonarcloud-access/SKILL.md +59 -47
  50. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  52. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  53. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-copilot/commands/lisa/setup/sonar.md +7 -0
  57. package/plugins/lisa-copilot/rules/reference/integration-access-layer.md +10 -2
  58. package/plugins/lisa-copilot/skills/lisa-analyze-claude-remote/SKILL.md +6 -6
  59. package/plugins/lisa-copilot/skills/lisa-generate-claude-remote-build-script/SKILL.md +14 -6
  60. package/plugins/lisa-copilot/skills/lisa-setup-sonar/SKILL.md +108 -0
  61. package/plugins/lisa-copilot/skills/lisa-sonarcloud-access/SKILL.md +59 -47
  62. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-cursor/commands/lisa/setup/sonar.md +7 -0
  64. package/plugins/lisa-cursor/rules/integration-access-layer-reference.mdc +10 -2
  65. package/plugins/lisa-cursor/skills/lisa-analyze-claude-remote/SKILL.md +6 -6
  66. package/plugins/lisa-cursor/skills/lisa-generate-claude-remote-build-script/SKILL.md +14 -6
  67. package/plugins/lisa-cursor/skills/lisa-setup-sonar/SKILL.md +108 -0
  68. package/plugins/lisa-cursor/skills/lisa-sonarcloud-access/SKILL.md +59 -47
  69. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  70. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  71. package/plugins/lisa-expo-agy/plugin.json +1 -1
  72. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  73. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  74. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  75. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  76. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  77. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  78. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  79. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  80. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  81. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  82. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  83. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  84. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  85. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  86. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  87. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  88. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  89. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  90. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  91. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  92. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  93. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  94. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  95. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  96. package/plugins/lisa-rails-agy/plugin.json +1 -1
  97. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  98. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  99. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  100. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  101. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  102. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  103. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  104. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  105. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  106. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  107. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  108. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  109. package/plugins/src/base/commands/setup/sonar.md +7 -0
  110. package/plugins/src/base/rules/reference/integration-access-layer.md +10 -2
  111. package/plugins/src/base/skills/lisa-analyze-claude-remote/SKILL.md +6 -6
  112. package/plugins/src/base/skills/lisa-generate-claude-remote-build-script/SKILL.md +14 -6
  113. package/plugins/src/base/skills/lisa-setup-sonar/SKILL.md +108 -0
  114. package/plugins/src/base/skills/lisa-sonarcloud-access/SKILL.md +59 -47
@@ -0,0 +1,19 @@
1
+ /** Result of the apply-time Sonar integrate pass. */
2
+ export interface SonarIntegrateResult {
3
+ /** True when the project opted in via `verification.sonar.enabled`. */
4
+ readonly enabled: boolean;
5
+ /** True when opted in AND the `sonar` CLI was on PATH (integrate attempted). */
6
+ readonly attempted: boolean;
7
+ /** Vendor agent names whose `sonar integrate` exited zero. */
8
+ readonly integrated: readonly string[];
9
+ /** Vendor agent names whose `sonar integrate` failed. */
10
+ readonly failed: readonly string[];
11
+ }
12
+ /**
13
+ * Wire the official SonarQube MCP into each supported agent via `sonar integrate`.
14
+ * @param projectRoot - Downstream project root (holds `.lisa.config.json`)
15
+ * @param vendorAgents - Vendor agent names to integrate, derived from the harness
16
+ * @returns Integrate result describing opt-in, attempt, and per-agent outcomes
17
+ */
18
+ export declare function installSonarIntegrations(projectRoot: string, vendorAgents: readonly string[]): Promise<SonarIntegrateResult>;
19
+ //# sourceMappingURL=sonar-installer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sonar-installer.d.ts","sourceRoot":"","sources":["../../src/sonar/sonar-installer.ts"],"names":[],"mappings":"AAkBA,qDAAqD;AACrD,MAAM,WAAW,oBAAoB;IACnC,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,gFAAgF;IAChF,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,8DAA8D;IAC9D,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,yDAAyD;IACzD,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AA8BD;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC5C,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,SAAS,MAAM,EAAE,GAC9B,OAAO,CAAC,oBAAoB,CAAC,CAyB/B"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Detect the `sonar` CLI and run the vendor's per-agent integrate at apply time.
3
+ *
4
+ * This delegates to SonarSource's official `sonar integrate <agent>` — Lisa does
5
+ * not reimplement the vendor's wiring. It is hard-gated so it never surprises a
6
+ * project: it is a no-op unless the project has explicitly opted in
7
+ * (`verification.sonar.enabled`) AND the `sonar` CLI is on `$PATH`. Per-agent
8
+ * failures are swallowed so a partial or unauthenticated environment never breaks
9
+ * `lisa apply`; `lisa doctor` surfaces the readiness gap instead.
10
+ * @module sonar/sonar-installer
11
+ */
12
+ import { exec, execFile } from "node:child_process";
13
+ import { promisify } from "node:util";
14
+ import { readProjectConfig } from "../core/project-config.js";
15
+ const execAsync = promisify(exec);
16
+ const execFileAsync = promisify(execFile);
17
+ /**
18
+ * Detect whether `sonar` is on PATH.
19
+ * @returns True when sonar is callable.
20
+ */
21
+ async function detectSonar() {
22
+ try {
23
+ await execAsync("command -v sonar");
24
+ return true;
25
+ }
26
+ catch {
27
+ return false;
28
+ }
29
+ }
30
+ /**
31
+ * Run the vendor's non-interactive integrate for one agent.
32
+ * @param agent - Vendor agent name (claude | codex | cursor | copilot | antigravity)
33
+ * @returns True when integrate exited zero.
34
+ */
35
+ async function integrateAgent(agent) {
36
+ try {
37
+ // execFile (no shell) so an agent token can never be interpreted.
38
+ await execFileAsync("sonar", ["integrate", agent, "--non-interactive"]);
39
+ return true;
40
+ }
41
+ catch {
42
+ return false;
43
+ }
44
+ }
45
+ /**
46
+ * Wire the official SonarQube MCP into each supported agent via `sonar integrate`.
47
+ * @param projectRoot - Downstream project root (holds `.lisa.config.json`)
48
+ * @param vendorAgents - Vendor agent names to integrate, derived from the harness
49
+ * @returns Integrate result describing opt-in, attempt, and per-agent outcomes
50
+ */
51
+ export async function installSonarIntegrations(projectRoot, vendorAgents) {
52
+ const config = (await readProjectConfig(projectRoot)).verification?.sonar;
53
+ if (config?.enabled !== true) {
54
+ return { enabled: false, attempted: false, integrated: [], failed: [] };
55
+ }
56
+ if (!(await detectSonar())) {
57
+ return { enabled: true, attempted: false, integrated: [], failed: [] };
58
+ }
59
+ // Integrate agents one at a time (the vendor CLI mutates config), threading an
60
+ // immutable accumulator so no array is mutated in place.
61
+ const outcome = await vendorAgents.reduce(async (accP, agent) => {
62
+ const acc = await accP;
63
+ return (await integrateAgent(agent))
64
+ ? { integrated: [...acc.integrated, agent], failed: acc.failed }
65
+ : { integrated: acc.integrated, failed: [...acc.failed, agent] };
66
+ }, Promise.resolve({ integrated: [], failed: [] }));
67
+ return { enabled: true, attempted: true, ...outcome };
68
+ }
69
+ //# sourceMappingURL=sonar-installer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sonar-installer.js","sourceRoot":"","sources":["../../src/sonar/sonar-installer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;AAClC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAc1C;;;GAGG;AACH,KAAK,UAAU,WAAW;IACxB,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,kBAAkB,CAAC,CAAC;QACpC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,cAAc,CAAC,KAAa;IACzC,IAAI,CAAC;QACH,kEAAkE;QAClE,MAAM,aAAa,CAAC,OAAO,EAAE,CAAC,WAAW,EAAE,KAAK,EAAE,mBAAmB,CAAC,CAAC,CAAC;QACxE,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,WAAmB,EACnB,YAA+B;IAE/B,MAAM,MAAM,GAAG,CAAC,MAAM,iBAAiB,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,EAAE,KAAK,CAAC;IAC1E,IAAI,MAAM,EAAE,OAAO,KAAK,IAAI,EAAE,CAAC;QAC7B,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IAC1E,CAAC;IACD,IAAI,CAAC,CAAC,MAAM,WAAW,EAAE,CAAC,EAAE,CAAC;QAC3B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACzE,CAAC;IACD,+EAA+E;IAC/E,yDAAyD;IACzD,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,MAAM,CAMvC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE;QACpB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC;QACvB,OAAO,CAAC,MAAM,cAAc,CAAC,KAAK,CAAC,CAAC;YAClC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,GAAG,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE;YAChE,CAAC,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC;IACrE,CAAC,EACD,OAAO,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAChD,CAAC;IACF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,OAAO,EAAE,CAAC;AACxD,CAAC"}
package/package.json CHANGED
@@ -113,7 +113,7 @@
113
113
  "brace-expansion": ">=5.0.6"
114
114
  },
115
115
  "name": "@codyswann/lisa",
116
- "version": "2.296.1",
116
+ "version": "2.297.1",
117
117
  "description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
118
118
  "main": "dist/index.js",
119
119
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.296.1",
3
+ "version": "2.297.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.296.1",
3
+ "version": "2.297.1",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -195,7 +195,7 @@ Group the findings as:
195
195
  | Match | Substrate | Env | Setup / wiring | Domains |
196
196
  |---|---|---|---|---|
197
197
  | `mcp.jam.dev`, `jam`, or Jam MCP entries | Jam CLI (`jam`) authenticated by PAT | `JAM_PAT` | install with `curl -fsSL https://native.jam.dev/install | bash`; export `~/.local/bin`; run `printf '%s' "$JAM_PAT" | jam auth login --token`; optionally `jam skills install` | `native.jam.dev`, `api.jam.dev` |
198
- | `mcp/sonarqube`, `sonarqube`, or SonarCloud/SonarQube MCP entries | SonarCloud Web API | `SONAR_TOKEN` | use REST calls against `https://sonarcloud.io/api/`; if a host needs legacy token-as-basic-auth, put that in the access adapter | `sonarcloud.io` |
198
+ | `mcp/sonarqube`, `sonarqube`, or SonarQube/SonarCloud MCP entries | Official SonarQube MCP (`sonar run mcp`), token-authed — runs headless as-is, no REST substitute | `SONARQUBE_CLI_TOKEN` (+ `SONARQUBE_CLI_ORG` for Cloud / `SONARQUBE_CLI_SERVER` for Server) | install the SonarQube CLI (`curl -o- https://raw.githubusercontent.com/SonarSource/sonarqube-cli/refs/heads/master/user-scripts/install.sh \| bash`) and `sonar integrate <agent>`; pre-pull the MCP container image in the setup script so it fits the cache budget; the MCP authenticates from the env token — never `sonar auth login` | `sonarcloud.io`, `sonarqube.us` (or the Server URL) |
199
199
 
200
200
  For PAT-bearer MCP substrates that really use the same MCP transport, include `mcpHeaders` in
201
201
  the inventory with a snippet such as `headers: { "Authorization": "Bearer ${VAR}" }` so the
@@ -353,17 +353,17 @@ so the generator can render acquisition comments into its template:
353
353
  "setupSnippet": "curl -fsSL https://native.jam.dev/install | bash; export PATH=\"$HOME/.local/bin:$PATH\"; printf '%s' \"$JAM_PAT\" | jam auth login --token; jam skills install"
354
354
  },
355
355
  {
356
- "name": "SONAR_TOKEN", "required": false, "secret": true, "integration": "sonarcloud",
357
- "reason": "optional non-tracker MCP recovery; SonarQube MCP wraps the token-authenticated SonarCloud Web API",
358
- "headlessSubstrate": "SonarCloud Web API (token)",
356
+ "name": "SONARQUBE_CLI_TOKEN", "required": false, "secret": true, "integration": "sonarcloud",
357
+ "reason": "authenticates the official SonarQube MCP headlessly; the MCP runs as-is in a cloud routine (Docker is preinstalled), so no REST substitute is needed",
358
+ "headlessSubstrate": "Official SonarQube MCP (token-authed)",
359
359
  "acquireUrl": "https://docs.sonarsource.com/sonarqube-cloud/managing-your-account/managing-tokens",
360
- "accessScope": "token must be able to read the target SonarCloud organization/project quality gate, issues, hotspots, rules, and source snippets"
360
+ "accessScope": "token must be able to read the target Sonar organization/project quality gate, issues, hotspots, rules, coverage, duplications, and dependency risks; add SONARQUBE_CLI_ORG (Cloud) or SONARQUBE_CLI_SERVER (Server)"
361
361
  }
362
362
  ],
363
363
  "mcp": [
364
364
  { "name": "linear-server", "transport": "http", "auth": "oauth", "headlessUsable": false, "replacedBy": "LINEAR_API_KEY + Linear GraphQL", "dormant": true },
365
365
  { "name": "jam", "transport": "http", "auth": "oauth", "headlessUsable": true, "replacedBy": "jam CLI + JAM_PAT", "dormant": true },
366
- { "name": "sonarqube", "transport": "stdio", "auth": "local-wrapper", "headlessUsable": true, "replacedBy": "SONAR_TOKEN + SonarCloud Web API", "dormant": true }
366
+ { "name": "sonarqube", "transport": "stdio", "auth": "env-token", "headlessUsable": true, "replacedBy": null, "dormant": true }
367
367
  ],
368
368
  "awsProfiles": [
369
369
  {
@@ -69,9 +69,9 @@ tracker/source, plus the host project's own package manager and tooling — not
69
69
  sibling repos reachable through the routine's GitHub proxy.
70
70
  For OPTIONAL non-tracker MCP recovery entries discovered by
71
71
  `/lisa:analyze-claude-remote`, preserve the same names-only behavior:
72
- include `JAM_PAT`, `SONAR_TOKEN`, or similar documented substrate env vars
73
- only as optional secrets, with their acquire/scope comments when the analysis
74
- supplied them. Never invent values or promote dormant substrates to required.
72
+ include `JAM_PAT`, `SONARQUBE_CLI_TOKEN` (+ `SONARQUBE_CLI_ORG`/`SONARQUBE_CLI_SERVER`), or
73
+ similar documented substrate env vars only as optional secrets, with their
74
+ acquire/scope comments when the analysis supplied them. Never invent values or promote dormant substrates to required.
75
75
  When AWS entries are present, list only `LISA_AWS_BOOTSTRAP_JSON` as the
76
76
  required secret and `LISA_REMOTE_AGENT=claude` as plain configuration. Never
77
77
  emit standard `AWS_ACCESS_KEY_ID` variables and never recommend `aws sso login`.
@@ -84,9 +84,17 @@ tracker/source, plus the host project's own package manager and tooling — not
84
84
  `export PATH="$HOME/.local/bin:$PATH"`, `printf '%s' "$JAM_PAT" | jam auth login --token`,
85
85
  and `jam skills install`, all inside `[ -n "${JAM_PAT:-}" ] && ...` guards so missing
86
86
  optional secrets do not fail the environment build.
87
- - REST substitute substrates: do not install an MCP. Emit comments naming the
88
- REST host and env var (for example `SONAR_TOKEN` with `https://sonarcloud.io/api/`) and
89
- rely on the access skill or generated consumer to call the API.
87
+ - Container-backed MCP substrates (e.g. the official SonarQube MCP): the MCP
88
+ runs headless as-is in a cloud routine Docker is preinstalled — so wire the
89
+ real MCP rather than substituting REST. Emit, guarded on the optional env
90
+ token, the vendor CLI install (`curl -o- https://raw.githubusercontent.com/SonarSource/sonarqube-cli/refs/heads/master/user-scripts/install.sh | bash`),
91
+ `sonar integrate <agent>`, and a `sonar run mcp`-image pre-pull so the first
92
+ run fits the ~5-min cache budget. Provide `SONARQUBE_CLI_TOKEN`
93
+ (+ `SONARQUBE_CLI_ORG`/`SONARQUBE_CLI_SERVER`); never emit `sonar auth login` (keychain
94
+ does not exist headless).
95
+ - REST-only substitute substrates: for a vendor whose MCP genuinely cannot run
96
+ headless, do not install an MCP — emit comments naming the REST host and env
97
+ var, and rely on the access skill or generated consumer to call the API.
90
98
  - PAT-bearer MCP substrates: print a commented `.mcp.json` `headers` snippet from the
91
99
  inventory's `mcpHeaders`. Use this only when the analysis explicitly says the same MCP
92
100
  transport supports static-token auth. Do not print a Jam `.mcp.json` header snippet because
@@ -0,0 +1,108 @@
1
+ ---
2
+ name: lisa-setup-sonar
3
+ description: "Configure the official…"
4
+ allowed-tools: ["Bash", "Read", "Write", "Edit", "AskUserQuestion", "Skill"]
5
+ ---
6
+
7
+ # Set up SonarQube (official plugin + MCP)
8
+
9
+ This is an explicit exterior setup gate. Run it **outside** any active Build, QA,
10
+ Monitor, or Verify factory — authentication and MCP wiring must be complete before
11
+ unattended factories run. It replaces Lisa's former hand-rolled SonarCloud REST
12
+ access with the vendor's official token-authed MCP, which is Lisa's single Sonar
13
+ substrate on both developer machines and headless cloud routines.
14
+
15
+ This does **not** touch the CI SonarCloud SAST job in `quality.yml` or its
16
+ `SONAR_TOKEN` secret — that enforcement gate is separate and stays as-is.
17
+
18
+ ## Supported agents
19
+
20
+ Wire only Lisa's supported agents: **Claude Code, Codex, Cursor, GitHub Copilot,
21
+ Antigravity (agy)** via `sonar integrate <agent>`, and **OpenCode** via its MCP
22
+ config. **Never** wire Kiro or Gemini CLI even though the vendor supports them —
23
+ they are not Lisa-supported agents.
24
+
25
+ ## 1. Install or update the SonarQube CLI
26
+
27
+ Check `sonar` on PATH (`command -v sonar`). If present, update it (`sonar
28
+ self-update`, or the package manager that owns it); if absent, install it and ask
29
+ for confirmation before running the install:
30
+
31
+ ```bash
32
+ # macOS/Linux (script) — default, works everywhere
33
+ curl -o- https://raw.githubusercontent.com/SonarSource/sonarqube-cli/refs/heads/master/user-scripts/install.sh | bash
34
+ # or Homebrew: brew install --cask sonarqube-cli
35
+ # or mise: mise use -g aqua:SonarSource/sonarqube-cli
36
+ ```
37
+
38
+ A container runtime (Docker/Podman/Nerdctl) must be installed and running — the
39
+ MCP runs as a container via `sonar run mcp`. Probe with `docker ps` (falling back
40
+ to `podman ps` / `nerdctl ps`). If none succeed, tell the operator to start it and
41
+ note the agent session must restart afterward for the MCP tools to load.
42
+
43
+ ## 2. Authenticate — token for factories, login for dev machines
44
+
45
+ The MCP authenticates from environment variables — this is the headless path and
46
+ the one factories use. **Never** write credentials to `.lisa.config.json` or
47
+ `.lisa.config.local.json`; provide them as environment variables / CI secrets:
48
+
49
+ - `SONARQUBE_CLI_TOKEN` — required.
50
+ - `SONARQUBE_CLI_ORG` — for SonarQube Cloud.
51
+ - `SONARQUBE_CLI_SERVER` — for a self-hosted SonarQube Server.
52
+
53
+ On an interactive developer machine you may instead run `sonar auth login`
54
+ (browser flow; token stored in the OS keychain). Do **not** use the keychain flow
55
+ for headless/cloud-routine environments — provision the env token there instead
56
+ (see `/lisa:generate-claude-remote-build-script`, which now installs the CLI,
57
+ pre-pulls the MCP image, and sets `SONARQUBE_CLI_TOKEN`). Verify with `sonar auth
58
+ status`; record the identity label only, never token material.
59
+
60
+ ## 3. Select the Test Manager target
61
+
62
+ Use `sonar config project` (and optional `sonar config folder`), then `sonar
63
+ config show`. Capture the non-secret project/organization identifiers.
64
+
65
+ ## 4. Integrate per supported agent
66
+
67
+ Confirm the target scope (single-choice: current project / global), then for each
68
+ supported agent detected on PATH run its non-interactive integrate:
69
+
70
+ ```bash
71
+ sonar integrate claude --non-interactive
72
+ sonar integrate codex --non-interactive
73
+ sonar integrate cursor --non-interactive
74
+ sonar integrate copilot --non-interactive
75
+ sonar integrate antigravity --non-interactive
76
+ ```
77
+
78
+ For **OpenCode** (no vendor integrate path), wire the MCP through OpenCode's own
79
+ MCP config so it launches `sonar run mcp`, authenticated from the same env token.
80
+
81
+ Skip any agent whose CLI is not installed; never wire Kiro or Gemini.
82
+
83
+ ## 5. Write non-secret policy config
84
+
85
+ Merge only non-secret identifiers into committed `.lisa.config.json`, preserving
86
+ every unrelated key (never credentials):
87
+
88
+ ```json
89
+ {
90
+ "verification": {
91
+ "sonar": {
92
+ "enabled": true,
93
+ "edition": "cloud",
94
+ "organization": "<org-key>",
95
+ "projectKey": "<project-key>"
96
+ }
97
+ }
98
+ }
99
+ ```
100
+
101
+ Use `"edition": "server"` with a `"serverUrl"` for a self-hosted Server.
102
+
103
+ ## 6. Prove readiness
104
+
105
+ Run the `lisa-sonarcloud-access` probe (an `mcp__sonarqube__*` project search) and
106
+ confirm a `mcp__sonarqube__*` tool answers. Then run `lisa doctor` and confirm the
107
+ Sonar provider check is green. If the MCP tools do not appear, verify the container
108
+ runtime is running and restart the agent session.
@@ -0,0 +1,4 @@
1
+ display_name: "Setup Sonar"
2
+ short_description: "Configure the official…"
3
+ default_prompt:
4
+ - "Use $lisa-setup-sonar: Configure the official…."
@@ -6,66 +6,78 @@ allowed-tools: ["Bash", "Read", "Skill"]
6
6
 
7
7
  # SonarCloud Access: $ARGUMENTS
8
8
 
9
- Single chokepoint for SonarCloud operations. Caller skills MUST NOT call
10
- `mcp__sonarqube__*` tools directly or curl `https://sonarcloud.io/api/`
11
- themselves.
9
+ Single chokepoint for Sonar quality and security data. Caller skills MUST NOT
10
+ invoke `mcp__sonarqube__*` tools directly; they ask for data by operation name and
11
+ this skill owns the tool selection.
12
12
 
13
- ## Invocation Contract
13
+ ## Substrate
14
14
 
15
- ```text
16
- operation: gate-status project_key:<KEY> [branch:<BRANCH>] [pull_request:<N>]
17
- operation: issues project_key:<KEY> [branch:<BRANCH>] [pull_request:<N>] [types:<csv>] [severities:<csv>]
18
- operation: hotspots project_key:<KEY> [branch:<BRANCH>] [pull_request:<N>]
19
- operation: rule-detail key:<RULE_KEY>
20
- operation: source-snippet component:<COMPONENT_KEY> from:<N> to:<N>
21
- ```
15
+ There is exactly one substrate: the **official SonarQube MCP server**, provided by
16
+ the `sonarqube` plugin and launched by the `sonar` CLI (`sonar run mcp`). It
17
+ authenticates headlessly from environment variables no browser, no OS keychain —
18
+ so it is the same substrate on a developer machine and in a headless cloud routine:
22
19
 
23
- Return parsed JSON in a `<result>` block.
20
+ - `SONARQUBE_CLI_TOKEN` required (Sonar user/analysis token).
21
+ - `SONARQUBE_CLI_ORG` — required for SonarQube Cloud.
22
+ - `SONARQUBE_CLI_SERVER` — required for a self-hosted SonarQube Server.
24
23
 
25
- ## Substrate Selection
24
+ These are the **SonarQube CLI** variable names (`SONARQUBE_CLI_*`), which the
25
+ `sonar run mcp` wrapper forwards into the MCP container — verified against a live
26
+ SonarQube Cloud org. Do **not** substitute the raw MCP-image names
27
+ (`SONARQUBE_TOKEN`/`SONARQUBE_ORG`/`SONARQUBE_URL`): those are read only when
28
+ running the Docker image directly, and the `sonar` CLI ignores them (auth exits
29
+ non-zero). The CI scan gate's `SONAR_TOKEN` is a third, separate name.
26
30
 
27
- Probe in order:
31
+ Wiring is performed once by `/lisa:setup:sonar` (which drives `sonar integrate
32
+ <agent>`); this access layer assumes the MCP is already wired. This is distinct
33
+ from the CI `SONAR_TOKEN` secret that authenticates the SonarCloud scan job in
34
+ `quality.yml` — that gate is separate and unchanged.
28
35
 
29
- 1. Sonar MCP, if available and authenticated.
30
- 2. `SONAR_TOKEN` against the SonarCloud Web API.
36
+ ## Probe (tool-access-gate)
31
37
 
32
- SonarCloud documents bearer-token authentication for the Web API. Use:
33
-
34
- ```bash
35
- sonar_api() {
36
- local path="$1"
37
- [ -n "$SONAR_TOKEN" ] || {
38
- echo "Error: SONAR_TOKEN is not set." >&2
39
- return 1
40
- }
41
- curl -sS "https://sonarcloud.io/api${path}" \
42
- -H "Authorization: Bearer $SONAR_TOKEN"
43
- }
44
- ```
38
+ Prove access with a cheap read-only MCP call before relying on it — the `sonar` CLI
39
+ being on PATH is not access. Probe by searching projects (the `projects` toolset is
40
+ always enabled):
45
41
 
46
- If a host still requires the legacy token-as-basic-auth form, make that an
47
- explicit adapter branch in this skill; consumers do not choose auth style.
48
-
49
- If neither tier works, fail with:
42
+ - If a `mcp__sonarqube__*` project-search tool returns, access is proven.
43
+ - If no `mcp__sonarqube__*` tool is present, or the call fails authentication, fail
44
+ loudly and do not improvise a substitute:
50
45
 
51
46
  ```text
52
- Error: no SonarCloud access substrate available. Authenticate the Sonar MCP or set SONAR_TOKEN.
47
+ Error: no SonarQube access. Run /lisa:setup:sonar (or `sonar integrate <agent>`), and set SONARQUBE_CLI_TOKEN (+ SONARQUBE_CLI_ORG for Cloud / SONARQUBE_CLI_SERVER for Server).
53
48
  ```
54
49
 
55
- ## REST Dispatch
50
+ There is no hand-rolled REST fallback: the official MCP is headless-capable via the
51
+ token env vars, so it is the only sanctioned substrate. A missing MCP is a
52
+ tool-access-gate failure to surface, not a reason to curl the Web API.
53
+
54
+ ## Operation → toolset map
55
+
56
+ Consumers pass a coarse, vendor-native operation; resolve it with the matching
57
+ `mcp__sonarqube__*` tool from the named toolset and return parsed JSON in a
58
+ `<result>` block.
56
59
 
57
- | Operation | REST path |
60
+ | Operation | SonarQube MCP toolset |
58
61
  |---|---|
59
- | `gate-status` | `/qualitygates/project_status?projectKey=<KEY>[&branch=<BRANCH>][&pullRequest=<N>]` |
60
- | `issues` | `/issues/search?componentKeys=<KEY>[&branch=<BRANCH>][&pullRequest=<N>]...` |
61
- | `hotspots` | `/hotspots/search?projectKey=<KEY>[&branch=<BRANCH>][&pullRequest=<N>]` |
62
- | `rule-detail` | `/rules/show?key=<RULE_KEY>` |
63
- | `source-snippet` | `/sources/lines?key=<COMPONENT_KEY>&from=<N>&to=<N>` |
62
+ | `gate-status` | `quality-gates` |
63
+ | `issues` | `issues` |
64
+ | `hotspots` | `security-hotspots` |
65
+ | `rule-detail` | `rules` |
66
+ | `source-snippet` | `cag` (context augmentation) / component source |
67
+ | `coverage` | `coverage` |
68
+ | `duplication` | `duplications` |
69
+ | `dependency-risks` | `dependency-risks` |
70
+ | `projects` | `projects` |
71
+
72
+ Pass the project key through the tool's `projectKey` argument (or rely on a
73
+ server-configured `SONARQUBE_PROJECT_KEY`); pass `branch` / `pullRequest` where the
74
+ tool accepts them.
64
75
 
65
76
  ## Invariants
66
77
 
67
- - Fallback is gated on `SONAR_TOKEN`.
68
- - SonarCloud host access requires `sonarcloud.io` in any custom remote network
69
- allowlist.
70
- - Consumers ask for analysis data by operation name; this skill owns the Web API
71
- path shape.
78
+ - The official SonarQube MCP is the only substrate; there is no REST fallback.
79
+ - Auth is env-var only (`SONARQUBE_CLI_TOKEN` [+ `SONARQUBE_CLI_ORG` | `SONARQUBE_CLI_SERVER`]);
80
+ never the interactive `sonar auth login` keychain flow inside a factory.
81
+ - Sonar host access requires the host (`sonarcloud.io`, `sonarqube.us`, or the
82
+ Server URL) in any custom remote-network allowlist.
83
+ - Consumers ask for data by operation name; this skill owns tool selection.
@@ -0,0 +1,7 @@
1
+ ---
2
+ description: "Wire the official SonarQube plugin + MCP into this project across every supported coding agent. Installs/updates the SonarQube CLI, authenticates (browser login on a dev machine, or SONARQUBE_CLI_TOKEN headless), selects the Test Manager target, runs `sonar integrate <agent>` for each supported agent, and writes only non-secret policy to `.lisa.config.json`. Does not touch the separate CI SonarCloud scan gate."
3
+ allowed-tools: ["Skill"]
4
+ argument-hint: "[--org=<org-key>] [--server-url=<url>] [--global]"
5
+ ---
6
+
7
+ Use the /lisa-setup-sonar skill to wire the official SonarQube MCP for this project across every supported agent. $ARGUMENTS
@@ -15,6 +15,14 @@ Do not blind-retry a failed or absent MCP. Fall back only after checking the
15
15
  documented env var for that vendor, and never silently no-op when neither tier is
16
16
  available.
17
17
 
18
+ Some MCPs authenticate headlessly from an env token and need no separate REST
19
+ tier — the MCP **is** the headless substrate on both developer machines and cloud
20
+ routines. The official SonarQube MCP is one such case (`SONARQUBE_CLI_TOKEN`
21
+ [+ `SONARQUBE_CLI_ORG`/`SONARQUBE_CLI_SERVER`]): `lisa-sonarcloud-access` resolves it as a
22
+ single substrate with no hand-rolled REST fallback. Reserve the two-tier
23
+ MCP-then-REST shape for vendors whose MCP is browser-OAuth or keychain-bound and
24
+ therefore dead headless.
25
+
18
26
  ## Access Skills
19
27
 
20
28
  | Vendor | Access skill | Headless env var | REST/token substrate |
@@ -23,7 +31,7 @@ available.
23
31
  | Notion | `lisa-notion-access` | `NOTION_API_TOKEN` | Notion REST |
24
32
  | Linear | `lisa-linear-access` | `LINEAR_API_KEY` | Linear GraphQL |
25
33
  | Jam | `lisa-jam-access` | `JAM_PAT` | Jam CLI |
26
- | SonarCloud | `lisa-sonarcloud-access` | `SONAR_TOKEN` | SonarCloud Web API |
34
+ | SonarCloud | `lisa-sonarcloud-access` | `SONARQUBE_CLI_TOKEN` (+ `SONARQUBE_CLI_ORG`/`SONARQUBE_CLI_SERVER`) | Official SonarQube MCP (headless via token) |
27
35
  | Sentry | `lisa-sentry-access` | `SENTRY_AUTH_TOKEN` | Sentry REST API |
28
36
  | PostHog | `lisa-posthog-access` | `POSTHOG_PERSONAL_API_KEY` | PostHog REST API |
29
37
  | Google Play | `lisa-expo:play-store-access` | `GOOGLE_PLAY_SERVICE_ACCOUNT_JSON` or `GOOGLE_PLAY_SERVICE_ACCOUNT_KEY_BASE64` | Google Play Developer API |
@@ -39,7 +47,7 @@ Source audit date: 2026-06-23. Scope: `plugins/src/**/skills/**` and
39
47
  | Notion | setup-only references | `notion-access` | Done. |
40
48
  | Linear | Multiple base queue/read/write/verify skills | Raw Linear MCP | Access layer added; consumers still need migration to `linear-access`. |
41
49
  | Jam | None in `plugins/src` at audit time | No access layer | Access layer added for host rules that include Jam triage. |
42
- | SonarCloud | None in `plugins/src` at audit time | No access layer | Access layer added for host rules that include SonarCloud gate triage. |
50
+ | SonarCloud | Routed through `sonarcloud-access` | Official SonarQube MCP (single substrate) | Migrated to the official token-authed SonarQube MCP; bespoke REST dispatch removed. |
43
51
  | Sentry | No Sentry MCP references in `plugins/src`; CLI/REST mentions only | CLI/REST scattered in observability docs | Access layer added for future MCP-backed consumers. |
44
52
  | PostHog | No PostHog MCP references in `plugins/src`; observability docs mention PostHog detection | No access layer | Access layer added for future MCP-backed consumers. |
45
53
  | Google Play | No MCP surface; EAS submit docs only | `play-store-access` for Expo post-submit release visibility | Done for Expo stack. |
@@ -195,7 +195,7 @@ Group the findings as:
195
195
  | Match | Substrate | Env | Setup / wiring | Domains |
196
196
  |---|---|---|---|---|
197
197
  | `mcp.jam.dev`, `jam`, or Jam MCP entries | Jam CLI (`jam`) authenticated by PAT | `JAM_PAT` | install with `curl -fsSL https://native.jam.dev/install | bash`; export `~/.local/bin`; run `printf '%s' "$JAM_PAT" | jam auth login --token`; optionally `jam skills install` | `native.jam.dev`, `api.jam.dev` |
198
- | `mcp/sonarqube`, `sonarqube`, or SonarCloud/SonarQube MCP entries | SonarCloud Web API | `SONAR_TOKEN` | use REST calls against `https://sonarcloud.io/api/`; if a host needs legacy token-as-basic-auth, put that in the access adapter | `sonarcloud.io` |
198
+ | `mcp/sonarqube`, `sonarqube`, or SonarQube/SonarCloud MCP entries | Official SonarQube MCP (`sonar run mcp`), token-authed — runs headless as-is, no REST substitute | `SONARQUBE_CLI_TOKEN` (+ `SONARQUBE_CLI_ORG` for Cloud / `SONARQUBE_CLI_SERVER` for Server) | install the SonarQube CLI (`curl -o- https://raw.githubusercontent.com/SonarSource/sonarqube-cli/refs/heads/master/user-scripts/install.sh \| bash`) and `sonar integrate <agent>`; pre-pull the MCP container image in the setup script so it fits the cache budget; the MCP authenticates from the env token — never `sonar auth login` | `sonarcloud.io`, `sonarqube.us` (or the Server URL) |
199
199
 
200
200
  For PAT-bearer MCP substrates that really use the same MCP transport, include `mcpHeaders` in
201
201
  the inventory with a snippet such as `headers: { "Authorization": "Bearer ${VAR}" }` so the
@@ -353,17 +353,17 @@ so the generator can render acquisition comments into its template:
353
353
  "setupSnippet": "curl -fsSL https://native.jam.dev/install | bash; export PATH=\"$HOME/.local/bin:$PATH\"; printf '%s' \"$JAM_PAT\" | jam auth login --token; jam skills install"
354
354
  },
355
355
  {
356
- "name": "SONAR_TOKEN", "required": false, "secret": true, "integration": "sonarcloud",
357
- "reason": "optional non-tracker MCP recovery; SonarQube MCP wraps the token-authenticated SonarCloud Web API",
358
- "headlessSubstrate": "SonarCloud Web API (token)",
356
+ "name": "SONARQUBE_CLI_TOKEN", "required": false, "secret": true, "integration": "sonarcloud",
357
+ "reason": "authenticates the official SonarQube MCP headlessly; the MCP runs as-is in a cloud routine (Docker is preinstalled), so no REST substitute is needed",
358
+ "headlessSubstrate": "Official SonarQube MCP (token-authed)",
359
359
  "acquireUrl": "https://docs.sonarsource.com/sonarqube-cloud/managing-your-account/managing-tokens",
360
- "accessScope": "token must be able to read the target SonarCloud organization/project quality gate, issues, hotspots, rules, and source snippets"
360
+ "accessScope": "token must be able to read the target Sonar organization/project quality gate, issues, hotspots, rules, coverage, duplications, and dependency risks; add SONARQUBE_CLI_ORG (Cloud) or SONARQUBE_CLI_SERVER (Server)"
361
361
  }
362
362
  ],
363
363
  "mcp": [
364
364
  { "name": "linear-server", "transport": "http", "auth": "oauth", "headlessUsable": false, "replacedBy": "LINEAR_API_KEY + Linear GraphQL", "dormant": true },
365
365
  { "name": "jam", "transport": "http", "auth": "oauth", "headlessUsable": true, "replacedBy": "jam CLI + JAM_PAT", "dormant": true },
366
- { "name": "sonarqube", "transport": "stdio", "auth": "local-wrapper", "headlessUsable": true, "replacedBy": "SONAR_TOKEN + SonarCloud Web API", "dormant": true }
366
+ { "name": "sonarqube", "transport": "stdio", "auth": "env-token", "headlessUsable": true, "replacedBy": null, "dormant": true }
367
367
  ],
368
368
  "awsProfiles": [
369
369
  {
@@ -69,9 +69,9 @@ tracker/source, plus the host project's own package manager and tooling — not
69
69
  sibling repos reachable through the routine's GitHub proxy.
70
70
  For OPTIONAL non-tracker MCP recovery entries discovered by
71
71
  `/lisa:analyze-claude-remote`, preserve the same names-only behavior:
72
- include `JAM_PAT`, `SONAR_TOKEN`, or similar documented substrate env vars
73
- only as optional secrets, with their acquire/scope comments when the analysis
74
- supplied them. Never invent values or promote dormant substrates to required.
72
+ include `JAM_PAT`, `SONARQUBE_CLI_TOKEN` (+ `SONARQUBE_CLI_ORG`/`SONARQUBE_CLI_SERVER`), or
73
+ similar documented substrate env vars only as optional secrets, with their
74
+ acquire/scope comments when the analysis supplied them. Never invent values or promote dormant substrates to required.
75
75
  When AWS entries are present, list only `LISA_AWS_BOOTSTRAP_JSON` as the
76
76
  required secret and `LISA_REMOTE_AGENT=claude` as plain configuration. Never
77
77
  emit standard `AWS_ACCESS_KEY_ID` variables and never recommend `aws sso login`.
@@ -84,9 +84,17 @@ tracker/source, plus the host project's own package manager and tooling — not
84
84
  `export PATH="$HOME/.local/bin:$PATH"`, `printf '%s' "$JAM_PAT" | jam auth login --token`,
85
85
  and `jam skills install`, all inside `[ -n "${JAM_PAT:-}" ] && ...` guards so missing
86
86
  optional secrets do not fail the environment build.
87
- - REST substitute substrates: do not install an MCP. Emit comments naming the
88
- REST host and env var (for example `SONAR_TOKEN` with `https://sonarcloud.io/api/`) and
89
- rely on the access skill or generated consumer to call the API.
87
+ - Container-backed MCP substrates (e.g. the official SonarQube MCP): the MCP
88
+ runs headless as-is in a cloud routine Docker is preinstalled — so wire the
89
+ real MCP rather than substituting REST. Emit, guarded on the optional env
90
+ token, the vendor CLI install (`curl -o- https://raw.githubusercontent.com/SonarSource/sonarqube-cli/refs/heads/master/user-scripts/install.sh | bash`),
91
+ `sonar integrate <agent>`, and a `sonar run mcp`-image pre-pull so the first
92
+ run fits the ~5-min cache budget. Provide `SONARQUBE_CLI_TOKEN`
93
+ (+ `SONARQUBE_CLI_ORG`/`SONARQUBE_CLI_SERVER`); never emit `sonar auth login` (keychain
94
+ does not exist headless).
95
+ - REST-only substitute substrates: for a vendor whose MCP genuinely cannot run
96
+ headless, do not install an MCP — emit comments naming the REST host and env
97
+ var, and rely on the access skill or generated consumer to call the API.
90
98
  - PAT-bearer MCP substrates: print a commented `.mcp.json` `headers` snippet from the
91
99
  inventory's `mcpHeaders`. Use this only when the analysis explicitly says the same MCP
92
100
  transport supports static-token auth. Do not print a Jam `.mcp.json` header snippet because