@codyswann/lisa 2.325.0 → 2.325.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 (64) hide show
  1. package/dist/core/upstream-evidence-manifest.js +2 -2
  2. package/package.json +1 -1
  3. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  4. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  5. package/plugins/lisa/.codex-plugin/skills/lisa-detect-tooling/SKILL.md +2 -2
  6. package/plugins/lisa/.codex-plugin/skills/lisa-detect-tooling/scripts/detect-tooling.mjs +22 -0
  7. package/plugins/lisa/skills/lisa-detect-tooling/SKILL.md +2 -2
  8. package/plugins/lisa/skills/lisa-detect-tooling/scripts/detect-tooling.mjs +22 -0
  9. package/plugins/lisa-agy/plugin.json +1 -1
  10. package/plugins/lisa-agy/skills/lisa-detect-tooling/SKILL.md +2 -2
  11. package/plugins/lisa-agy/skills/lisa-detect-tooling/scripts/detect-tooling.mjs +22 -0
  12. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  13. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  14. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  15. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  16. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  17. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  18. package/plugins/lisa-copilot/skills/lisa-detect-tooling/SKILL.md +2 -2
  19. package/plugins/lisa-copilot/skills/lisa-detect-tooling/scripts/detect-tooling.mjs +22 -0
  20. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  21. package/plugins/lisa-cursor/skills/lisa-detect-tooling/SKILL.md +2 -2
  22. package/plugins/lisa-cursor/skills/lisa-detect-tooling/scripts/detect-tooling.mjs +22 -0
  23. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  24. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  25. package/plugins/lisa-expo-agy/plugin.json +1 -1
  26. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  27. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  28. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  29. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  30. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  31. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  32. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  33. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  34. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  35. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  36. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  37. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  38. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  40. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  41. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  42. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  43. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  45. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  46. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  47. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  50. package/plugins/lisa-rails-agy/plugin.json +1 -1
  51. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  52. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  55. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  56. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  60. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  61. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  62. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  63. package/plugins/src/base/skills/lisa-detect-tooling/SKILL.md +2 -2
  64. package/plugins/src/base/skills/lisa-detect-tooling/scripts/detect-tooling.mjs +22 -0
@@ -424,8 +424,8 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
424
424
  "plugins/src/base/skills/lisa-debrief-apply/SKILL.md": "90c5f01994bb0f8e71947e8a2f765ccf9a6aa3da47b8d7b8e2022150ef89c2b2",
425
425
  "plugins/src/base/skills/lisa-debrief/SKILL.md": "47e4cda36b07994ff47ab15fb04a17dd6b0c310ad804f9cae9d69637edaaa72a",
426
426
  "plugins/src/base/skills/lisa-delivery-effectiveness/SKILL.md": "21bc55fa0e86a9694bd22269fd089dbfae0c54c199262f46a4955447acea0f35",
427
- "plugins/src/base/skills/lisa-detect-tooling/SKILL.md": "e29b3b8ebc256468bb67e5d10e2ae3cb4eda9ba20dfd2e065201b00864134734",
428
- "plugins/src/base/skills/lisa-detect-tooling/scripts/detect-tooling.mjs": "043c3f59d6a7a21a3ab4fce8ae8dc88e8650c19c5a57bba40f567c5257684747",
427
+ "plugins/src/base/skills/lisa-detect-tooling/SKILL.md": "1778a009d06099b3bd2d9a33b37bec34836b295e21fad220ae926491d3557208",
428
+ "plugins/src/base/skills/lisa-detect-tooling/scripts/detect-tooling.mjs": "90086ca11dafb5250ee930fa78fd3cc7d4bd601ad57f3e3c1a49920f7d7a1493",
429
429
  "plugins/src/base/skills/lisa-doctor/SKILL.md": "fb41a1e63c5332d47a46e715aff52551f3df867033b5e4f37dfaeee30019b891",
430
430
  "plugins/src/base/skills/lisa-drive-pr-to-merge/SKILL.md": "c78ae2ba32c830d0b2cd7d24de91adf99e2b3cef4c7cab1c417580d86f41351f",
431
431
  "plugins/src/base/skills/lisa-epic-triage/SKILL.md": "d02760411249bddbd396f283191fe3e82bb7b95bf9393a19a7025dc5a57c3ab7",
package/package.json CHANGED
@@ -115,7 +115,7 @@
115
115
  "brace-expansion": ">=5.0.9"
116
116
  },
117
117
  "name": "@codyswann/lisa",
118
- "version": "2.325.0",
118
+ "version": "2.325.1",
119
119
  "description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
120
120
  "main": "dist/index.js",
121
121
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.325.0",
3
+ "version": "2.325.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.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -13,7 +13,7 @@ Lisa provisions tooling through four unrelated mechanisms, and only one of them
13
13
  | playwright, stryker | npm devDependency from a stack template | nothing — a local `node_modules` binary |
14
14
  | maestro | npm **scripts** in the Expo template | **nothing** |
15
15
  | sonar | `src/sonar/sonar-installer.ts` | nothing |
16
- | linear | MCP server | nothing, and it needs browser OAuth |
16
+ | linear | MCP server or `LINEAR_API_KEY` | `lisa-linear-access`, not a CLI |
17
17
  | bws, gh | `remoteEnv.tools` — pinned and checksummed | this, and only this |
18
18
 
19
19
  Nothing populates that last row. So a project can ship scripts that invoke `maestro`, wire an MCP server whose CLI it also shells out to, and configure Playwright thresholds, while the manifest that actually provisions binaries stays empty — and every one of those fails at the moment of use rather than at setup.
@@ -25,7 +25,7 @@ That is the same failure this repository has now paid for twice: `gh` was declar
25
25
  Reads four signals, subtracts what `remoteEnv.tools` already declares, and prints what is left with the evidence for each:
26
26
 
27
27
  - **npm scripts** that invoke a binary. The strongest signal there is — a script running `maestro test` is the project stating a dependency in executable form. Matched on the script *body*, not its name, because the name is a label.
28
- - **MCP servers with a CLI equivalent.** An MCP server is not a substitute for the binary: several authenticate by browser OAuth, which a container cannot do, so a project relying on one remotely has *no* integration rather than a degraded one.
28
+ - **MCP servers with a CLI equivalent.** An MCP server is not a substitute for the binary: several authenticate by browser OAuth, which a container cannot do, so a project relying on one remotely has *no* integration rather than a degraded one. Do not infer a CLI for access layers that already define their own headless substrate; Linear is handled by `lisa-linear-access` through `LINEAR_API_KEY` + GraphQL when MCP OAuth is unavailable.
29
29
  - **Credential usage notes.** A note explaining what a token is for usually names the program that consumes it. `lisa-secrets-access` already exposes these without touching a value, which makes them a first-class input rather than a trick.
30
30
  - **Quality configuration**, where a threshold implies the tool that produces it.
31
31
 
@@ -98,6 +98,20 @@ export function toolsFromScripts(pkg) {
98
98
  return found;
99
99
  }
100
100
 
101
+ /**
102
+ * MCP servers that are access substrates rather than evidence for a CLI.
103
+ *
104
+ * Linear is the important case: Lisa's `lisa-linear-access` skill owns the
105
+ * headless path through `LINEAR_API_KEY` + GraphQL. There is no official Linear
106
+ * CLI to pin, and the unrelated `linear` npm package is not a tracker binary.
107
+ * Treating the MCP server as CLI evidence would push operators toward an
108
+ * arbitrary third-party executable instead of the access-layer contract.
109
+ */
110
+ const MCP_ACCESS_LAYER_SUBSTRATES = Object.freeze({
111
+ "linear-server":
112
+ "lisa-linear-access uses LINEAR_API_KEY in headless sessions",
113
+ });
114
+
101
115
  /**
102
116
  * Tools implied by MCP servers that also have a CLI.
103
117
  *
@@ -114,6 +128,14 @@ export function toolsFromMcp(mcp) {
114
128
  for (const [tool, meta] of Object.entries(KNOWN_TOOLS)) {
115
129
  if (!meta.mcpFallback) continue;
116
130
  const server = servers.find(name => name.includes(meta.mcpFallback));
131
+ if (
132
+ server &&
133
+ Object.keys(MCP_ACCESS_LAYER_SUBSTRATES).some(substrate =>
134
+ server.includes(substrate)
135
+ )
136
+ ) {
137
+ continue;
138
+ }
117
139
  if (server) {
118
140
  found.set(
119
141
  tool,
@@ -13,7 +13,7 @@ Lisa provisions tooling through four unrelated mechanisms, and only one of them
13
13
  | playwright, stryker | npm devDependency from a stack template | nothing — a local `node_modules` binary |
14
14
  | maestro | npm **scripts** in the Expo template | **nothing** |
15
15
  | sonar | `src/sonar/sonar-installer.ts` | nothing |
16
- | linear | MCP server | nothing, and it needs browser OAuth |
16
+ | linear | MCP server or `LINEAR_API_KEY` | `lisa-linear-access`, not a CLI |
17
17
  | bws, gh | `remoteEnv.tools` — pinned and checksummed | this, and only this |
18
18
 
19
19
  Nothing populates that last row. So a project can ship scripts that invoke `maestro`, wire an MCP server whose CLI it also shells out to, and configure Playwright thresholds, while the manifest that actually provisions binaries stays empty — and every one of those fails at the moment of use rather than at setup.
@@ -25,7 +25,7 @@ That is the same failure this repository has now paid for twice: `gh` was declar
25
25
  Reads four signals, subtracts what `remoteEnv.tools` already declares, and prints what is left with the evidence for each:
26
26
 
27
27
  - **npm scripts** that invoke a binary. The strongest signal there is — a script running `maestro test` is the project stating a dependency in executable form. Matched on the script *body*, not its name, because the name is a label.
28
- - **MCP servers with a CLI equivalent.** An MCP server is not a substitute for the binary: several authenticate by browser OAuth, which a container cannot do, so a project relying on one remotely has *no* integration rather than a degraded one.
28
+ - **MCP servers with a CLI equivalent.** An MCP server is not a substitute for the binary: several authenticate by browser OAuth, which a container cannot do, so a project relying on one remotely has *no* integration rather than a degraded one. Do not infer a CLI for access layers that already define their own headless substrate; Linear is handled by `lisa-linear-access` through `LINEAR_API_KEY` + GraphQL when MCP OAuth is unavailable.
29
29
  - **Credential usage notes.** A note explaining what a token is for usually names the program that consumes it. `lisa-secrets-access` already exposes these without touching a value, which makes them a first-class input rather than a trick.
30
30
  - **Quality configuration**, where a threshold implies the tool that produces it.
31
31
 
@@ -98,6 +98,20 @@ export function toolsFromScripts(pkg) {
98
98
  return found;
99
99
  }
100
100
 
101
+ /**
102
+ * MCP servers that are access substrates rather than evidence for a CLI.
103
+ *
104
+ * Linear is the important case: Lisa's `lisa-linear-access` skill owns the
105
+ * headless path through `LINEAR_API_KEY` + GraphQL. There is no official Linear
106
+ * CLI to pin, and the unrelated `linear` npm package is not a tracker binary.
107
+ * Treating the MCP server as CLI evidence would push operators toward an
108
+ * arbitrary third-party executable instead of the access-layer contract.
109
+ */
110
+ const MCP_ACCESS_LAYER_SUBSTRATES = Object.freeze({
111
+ "linear-server":
112
+ "lisa-linear-access uses LINEAR_API_KEY in headless sessions",
113
+ });
114
+
101
115
  /**
102
116
  * Tools implied by MCP servers that also have a CLI.
103
117
  *
@@ -114,6 +128,14 @@ export function toolsFromMcp(mcp) {
114
128
  for (const [tool, meta] of Object.entries(KNOWN_TOOLS)) {
115
129
  if (!meta.mcpFallback) continue;
116
130
  const server = servers.find(name => name.includes(meta.mcpFallback));
131
+ if (
132
+ server &&
133
+ Object.keys(MCP_ACCESS_LAYER_SUBSTRATES).some(substrate =>
134
+ server.includes(substrate)
135
+ )
136
+ ) {
137
+ continue;
138
+ }
117
139
  if (server) {
118
140
  found.set(
119
141
  tool,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -13,7 +13,7 @@ Lisa provisions tooling through four unrelated mechanisms, and only one of them
13
13
  | playwright, stryker | npm devDependency from a stack template | nothing — a local `node_modules` binary |
14
14
  | maestro | npm **scripts** in the Expo template | **nothing** |
15
15
  | sonar | `src/sonar/sonar-installer.ts` | nothing |
16
- | linear | MCP server | nothing, and it needs browser OAuth |
16
+ | linear | MCP server or `LINEAR_API_KEY` | `lisa-linear-access`, not a CLI |
17
17
  | bws, gh | `remoteEnv.tools` — pinned and checksummed | this, and only this |
18
18
 
19
19
  Nothing populates that last row. So a project can ship scripts that invoke `maestro`, wire an MCP server whose CLI it also shells out to, and configure Playwright thresholds, while the manifest that actually provisions binaries stays empty — and every one of those fails at the moment of use rather than at setup.
@@ -25,7 +25,7 @@ That is the same failure this repository has now paid for twice: `gh` was declar
25
25
  Reads four signals, subtracts what `remoteEnv.tools` already declares, and prints what is left with the evidence for each:
26
26
 
27
27
  - **npm scripts** that invoke a binary. The strongest signal there is — a script running `maestro test` is the project stating a dependency in executable form. Matched on the script *body*, not its name, because the name is a label.
28
- - **MCP servers with a CLI equivalent.** An MCP server is not a substitute for the binary: several authenticate by browser OAuth, which a container cannot do, so a project relying on one remotely has *no* integration rather than a degraded one.
28
+ - **MCP servers with a CLI equivalent.** An MCP server is not a substitute for the binary: several authenticate by browser OAuth, which a container cannot do, so a project relying on one remotely has *no* integration rather than a degraded one. Do not infer a CLI for access layers that already define their own headless substrate; Linear is handled by `lisa-linear-access` through `LINEAR_API_KEY` + GraphQL when MCP OAuth is unavailable.
29
29
  - **Credential usage notes.** A note explaining what a token is for usually names the program that consumes it. `lisa-secrets-access` already exposes these without touching a value, which makes them a first-class input rather than a trick.
30
30
  - **Quality configuration**, where a threshold implies the tool that produces it.
31
31
 
@@ -98,6 +98,20 @@ export function toolsFromScripts(pkg) {
98
98
  return found;
99
99
  }
100
100
 
101
+ /**
102
+ * MCP servers that are access substrates rather than evidence for a CLI.
103
+ *
104
+ * Linear is the important case: Lisa's `lisa-linear-access` skill owns the
105
+ * headless path through `LINEAR_API_KEY` + GraphQL. There is no official Linear
106
+ * CLI to pin, and the unrelated `linear` npm package is not a tracker binary.
107
+ * Treating the MCP server as CLI evidence would push operators toward an
108
+ * arbitrary third-party executable instead of the access-layer contract.
109
+ */
110
+ const MCP_ACCESS_LAYER_SUBSTRATES = Object.freeze({
111
+ "linear-server":
112
+ "lisa-linear-access uses LINEAR_API_KEY in headless sessions",
113
+ });
114
+
101
115
  /**
102
116
  * Tools implied by MCP servers that also have a CLI.
103
117
  *
@@ -114,6 +128,14 @@ export function toolsFromMcp(mcp) {
114
128
  for (const [tool, meta] of Object.entries(KNOWN_TOOLS)) {
115
129
  if (!meta.mcpFallback) continue;
116
130
  const server = servers.find(name => name.includes(meta.mcpFallback));
131
+ if (
132
+ server &&
133
+ Object.keys(MCP_ACCESS_LAYER_SUBSTRATES).some(substrate =>
134
+ server.includes(substrate)
135
+ )
136
+ ) {
137
+ continue;
138
+ }
117
139
  if (server) {
118
140
  found.set(
119
141
  tool,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "AWS CDK-specific Lisa plugin.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -13,7 +13,7 @@ Lisa provisions tooling through four unrelated mechanisms, and only one of them
13
13
  | playwright, stryker | npm devDependency from a stack template | nothing — a local `node_modules` binary |
14
14
  | maestro | npm **scripts** in the Expo template | **nothing** |
15
15
  | sonar | `src/sonar/sonar-installer.ts` | nothing |
16
- | linear | MCP server | nothing, and it needs browser OAuth |
16
+ | linear | MCP server or `LINEAR_API_KEY` | `lisa-linear-access`, not a CLI |
17
17
  | bws, gh | `remoteEnv.tools` — pinned and checksummed | this, and only this |
18
18
 
19
19
  Nothing populates that last row. So a project can ship scripts that invoke `maestro`, wire an MCP server whose CLI it also shells out to, and configure Playwright thresholds, while the manifest that actually provisions binaries stays empty — and every one of those fails at the moment of use rather than at setup.
@@ -25,7 +25,7 @@ That is the same failure this repository has now paid for twice: `gh` was declar
25
25
  Reads four signals, subtracts what `remoteEnv.tools` already declares, and prints what is left with the evidence for each:
26
26
 
27
27
  - **npm scripts** that invoke a binary. The strongest signal there is — a script running `maestro test` is the project stating a dependency in executable form. Matched on the script *body*, not its name, because the name is a label.
28
- - **MCP servers with a CLI equivalent.** An MCP server is not a substitute for the binary: several authenticate by browser OAuth, which a container cannot do, so a project relying on one remotely has *no* integration rather than a degraded one.
28
+ - **MCP servers with a CLI equivalent.** An MCP server is not a substitute for the binary: several authenticate by browser OAuth, which a container cannot do, so a project relying on one remotely has *no* integration rather than a degraded one. Do not infer a CLI for access layers that already define their own headless substrate; Linear is handled by `lisa-linear-access` through `LINEAR_API_KEY` + GraphQL when MCP OAuth is unavailable.
29
29
  - **Credential usage notes.** A note explaining what a token is for usually names the program that consumes it. `lisa-secrets-access` already exposes these without touching a value, which makes them a first-class input rather than a trick.
30
30
  - **Quality configuration**, where a threshold implies the tool that produces it.
31
31
 
@@ -98,6 +98,20 @@ export function toolsFromScripts(pkg) {
98
98
  return found;
99
99
  }
100
100
 
101
+ /**
102
+ * MCP servers that are access substrates rather than evidence for a CLI.
103
+ *
104
+ * Linear is the important case: Lisa's `lisa-linear-access` skill owns the
105
+ * headless path through `LINEAR_API_KEY` + GraphQL. There is no official Linear
106
+ * CLI to pin, and the unrelated `linear` npm package is not a tracker binary.
107
+ * Treating the MCP server as CLI evidence would push operators toward an
108
+ * arbitrary third-party executable instead of the access-layer contract.
109
+ */
110
+ const MCP_ACCESS_LAYER_SUBSTRATES = Object.freeze({
111
+ "linear-server":
112
+ "lisa-linear-access uses LINEAR_API_KEY in headless sessions",
113
+ });
114
+
101
115
  /**
102
116
  * Tools implied by MCP servers that also have a CLI.
103
117
  *
@@ -114,6 +128,14 @@ export function toolsFromMcp(mcp) {
114
128
  for (const [tool, meta] of Object.entries(KNOWN_TOOLS)) {
115
129
  if (!meta.mcpFallback) continue;
116
130
  const server = servers.find(name => name.includes(meta.mcpFallback));
131
+ if (
132
+ server &&
133
+ Object.keys(MCP_ACCESS_LAYER_SUBSTRATES).some(substrate =>
134
+ server.includes(substrate)
135
+ )
136
+ ) {
137
+ continue;
138
+ }
117
139
  if (server) {
118
140
  found.set(
119
141
  tool,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -13,7 +13,7 @@ Lisa provisions tooling through four unrelated mechanisms, and only one of them
13
13
  | playwright, stryker | npm devDependency from a stack template | nothing — a local `node_modules` binary |
14
14
  | maestro | npm **scripts** in the Expo template | **nothing** |
15
15
  | sonar | `src/sonar/sonar-installer.ts` | nothing |
16
- | linear | MCP server | nothing, and it needs browser OAuth |
16
+ | linear | MCP server or `LINEAR_API_KEY` | `lisa-linear-access`, not a CLI |
17
17
  | bws, gh | `remoteEnv.tools` — pinned and checksummed | this, and only this |
18
18
 
19
19
  Nothing populates that last row. So a project can ship scripts that invoke `maestro`, wire an MCP server whose CLI it also shells out to, and configure Playwright thresholds, while the manifest that actually provisions binaries stays empty — and every one of those fails at the moment of use rather than at setup.
@@ -25,7 +25,7 @@ That is the same failure this repository has now paid for twice: `gh` was declar
25
25
  Reads four signals, subtracts what `remoteEnv.tools` already declares, and prints what is left with the evidence for each:
26
26
 
27
27
  - **npm scripts** that invoke a binary. The strongest signal there is — a script running `maestro test` is the project stating a dependency in executable form. Matched on the script *body*, not its name, because the name is a label.
28
- - **MCP servers with a CLI equivalent.** An MCP server is not a substitute for the binary: several authenticate by browser OAuth, which a container cannot do, so a project relying on one remotely has *no* integration rather than a degraded one.
28
+ - **MCP servers with a CLI equivalent.** An MCP server is not a substitute for the binary: several authenticate by browser OAuth, which a container cannot do, so a project relying on one remotely has *no* integration rather than a degraded one. Do not infer a CLI for access layers that already define their own headless substrate; Linear is handled by `lisa-linear-access` through `LINEAR_API_KEY` + GraphQL when MCP OAuth is unavailable.
29
29
  - **Credential usage notes.** A note explaining what a token is for usually names the program that consumes it. `lisa-secrets-access` already exposes these without touching a value, which makes them a first-class input rather than a trick.
30
30
  - **Quality configuration**, where a threshold implies the tool that produces it.
31
31
 
@@ -98,6 +98,20 @@ export function toolsFromScripts(pkg) {
98
98
  return found;
99
99
  }
100
100
 
101
+ /**
102
+ * MCP servers that are access substrates rather than evidence for a CLI.
103
+ *
104
+ * Linear is the important case: Lisa's `lisa-linear-access` skill owns the
105
+ * headless path through `LINEAR_API_KEY` + GraphQL. There is no official Linear
106
+ * CLI to pin, and the unrelated `linear` npm package is not a tracker binary.
107
+ * Treating the MCP server as CLI evidence would push operators toward an
108
+ * arbitrary third-party executable instead of the access-layer contract.
109
+ */
110
+ const MCP_ACCESS_LAYER_SUBSTRATES = Object.freeze({
111
+ "linear-server":
112
+ "lisa-linear-access uses LINEAR_API_KEY in headless sessions",
113
+ });
114
+
101
115
  /**
102
116
  * Tools implied by MCP servers that also have a CLI.
103
117
  *
@@ -114,6 +128,14 @@ export function toolsFromMcp(mcp) {
114
128
  for (const [tool, meta] of Object.entries(KNOWN_TOOLS)) {
115
129
  if (!meta.mcpFallback) continue;
116
130
  const server = servers.find(name => name.includes(meta.mcpFallback));
131
+ if (
132
+ server &&
133
+ Object.keys(MCP_ACCESS_LAYER_SUBSTRATES).some(substrate =>
134
+ server.includes(substrate)
135
+ )
136
+ ) {
137
+ continue;
138
+ }
117
139
  if (server) {
118
140
  found.set(
119
141
  tool,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Expo and React Native-specific skills, agents, rules, and MCP servers.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Harper/Fabric-specific Lisa rules for TypeScript component apps.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "NestJS-specific skills and migration write-protection hooks.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Ruby on Rails-specific skills and hooks for RuboCop and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "TypeScript-specific hooks for formatting, linting, and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "Distributable LLM Wiki kernel — ingest, query, lint, and maintain a git-native markdown knowledge base across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -13,7 +13,7 @@ Lisa provisions tooling through four unrelated mechanisms, and only one of them
13
13
  | playwright, stryker | npm devDependency from a stack template | nothing — a local `node_modules` binary |
14
14
  | maestro | npm **scripts** in the Expo template | **nothing** |
15
15
  | sonar | `src/sonar/sonar-installer.ts` | nothing |
16
- | linear | MCP server | nothing, and it needs browser OAuth |
16
+ | linear | MCP server or `LINEAR_API_KEY` | `lisa-linear-access`, not a CLI |
17
17
  | bws, gh | `remoteEnv.tools` — pinned and checksummed | this, and only this |
18
18
 
19
19
  Nothing populates that last row. So a project can ship scripts that invoke `maestro`, wire an MCP server whose CLI it also shells out to, and configure Playwright thresholds, while the manifest that actually provisions binaries stays empty — and every one of those fails at the moment of use rather than at setup.
@@ -25,7 +25,7 @@ That is the same failure this repository has now paid for twice: `gh` was declar
25
25
  Reads four signals, subtracts what `remoteEnv.tools` already declares, and prints what is left with the evidence for each:
26
26
 
27
27
  - **npm scripts** that invoke a binary. The strongest signal there is — a script running `maestro test` is the project stating a dependency in executable form. Matched on the script *body*, not its name, because the name is a label.
28
- - **MCP servers with a CLI equivalent.** An MCP server is not a substitute for the binary: several authenticate by browser OAuth, which a container cannot do, so a project relying on one remotely has *no* integration rather than a degraded one.
28
+ - **MCP servers with a CLI equivalent.** An MCP server is not a substitute for the binary: several authenticate by browser OAuth, which a container cannot do, so a project relying on one remotely has *no* integration rather than a degraded one. Do not infer a CLI for access layers that already define their own headless substrate; Linear is handled by `lisa-linear-access` through `LINEAR_API_KEY` + GraphQL when MCP OAuth is unavailable.
29
29
  - **Credential usage notes.** A note explaining what a token is for usually names the program that consumes it. `lisa-secrets-access` already exposes these without touching a value, which makes them a first-class input rather than a trick.
30
30
  - **Quality configuration**, where a threshold implies the tool that produces it.
31
31
 
@@ -98,6 +98,20 @@ export function toolsFromScripts(pkg) {
98
98
  return found;
99
99
  }
100
100
 
101
+ /**
102
+ * MCP servers that are access substrates rather than evidence for a CLI.
103
+ *
104
+ * Linear is the important case: Lisa's `lisa-linear-access` skill owns the
105
+ * headless path through `LINEAR_API_KEY` + GraphQL. There is no official Linear
106
+ * CLI to pin, and the unrelated `linear` npm package is not a tracker binary.
107
+ * Treating the MCP server as CLI evidence would push operators toward an
108
+ * arbitrary third-party executable instead of the access-layer contract.
109
+ */
110
+ const MCP_ACCESS_LAYER_SUBSTRATES = Object.freeze({
111
+ "linear-server":
112
+ "lisa-linear-access uses LINEAR_API_KEY in headless sessions",
113
+ });
114
+
101
115
  /**
102
116
  * Tools implied by MCP servers that also have a CLI.
103
117
  *
@@ -114,6 +128,14 @@ export function toolsFromMcp(mcp) {
114
128
  for (const [tool, meta] of Object.entries(KNOWN_TOOLS)) {
115
129
  if (!meta.mcpFallback) continue;
116
130
  const server = servers.find(name => name.includes(meta.mcpFallback));
131
+ if (
132
+ server &&
133
+ Object.keys(MCP_ACCESS_LAYER_SUBSTRATES).some(substrate =>
134
+ server.includes(substrate)
135
+ )
136
+ ) {
137
+ continue;
138
+ }
117
139
  if (server) {
118
140
  found.set(
119
141
  tool,