@codyswann/lisa 2.333.0 → 2.333.2

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 (72) hide show
  1. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  2. package/dist/core/upstream-evidence-manifest.js +4 -3
  3. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  4. package/package.json +1 -1
  5. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  6. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  7. package/plugins/lisa/.codex-plugin/skills/lisa-parity-sentry-sdk-setup/SKILL.md +2 -2
  8. package/plugins/lisa/.codex-plugin/skills/lisa-parity-sentry-seer/SKILL.md +2 -2
  9. package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +57 -26
  10. package/plugins/lisa/skills/lisa-parity-sentry-sdk-setup/SKILL.md +2 -2
  11. package/plugins/lisa/skills/lisa-parity-sentry-seer/SKILL.md +2 -2
  12. package/plugins/lisa/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +57 -26
  13. package/plugins/lisa-agy/plugin.json +1 -1
  14. package/plugins/lisa-agy/skills/lisa-parity-sentry-sdk-setup/SKILL.md +2 -2
  15. package/plugins/lisa-agy/skills/lisa-parity-sentry-seer/SKILL.md +2 -2
  16. package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +57 -26
  17. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  18. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  19. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  20. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  21. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  22. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  23. package/plugins/lisa-copilot/skills/lisa-parity-sentry-sdk-setup/SKILL.md +2 -2
  24. package/plugins/lisa-copilot/skills/lisa-parity-sentry-seer/SKILL.md +2 -2
  25. package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +57 -26
  26. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  27. package/plugins/lisa-cursor/skills/lisa-parity-sentry-sdk-setup/SKILL.md +2 -2
  28. package/plugins/lisa-cursor/skills/lisa-parity-sentry-seer/SKILL.md +2 -2
  29. package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +57 -26
  30. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  31. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  32. package/plugins/lisa-expo-agy/plugin.json +1 -1
  33. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  34. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  35. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  37. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  38. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  40. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  41. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  42. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  43. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  46. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  47. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  48. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  52. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  53. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  57. package/plugins/lisa-rails-agy/plugin.json +1 -1
  58. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  62. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  63. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  65. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  67. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  68. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  69. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  70. package/plugins/src/base/skills/lisa-parity-sentry-sdk-setup/SKILL.md +2 -2
  71. package/plugins/src/base/skills/lisa-parity-sentry-seer/SKILL.md +2 -2
  72. package/plugins/src/base/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +57 -26
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.333.0",
118
+ "version": "2.333.2",
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.333.0",
3
+ "version": "2.333.2",
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.333.0",
3
+ "version": "2.333.2",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -2,7 +2,7 @@
2
2
  name: lisa-parity-sentry-sdk-setup
3
3
  description: "Install and configure the…"
4
4
  allowed-tools: ["Read", "Edit", "Write", "Bash"]
5
- synced-from: sentry@claude-plugins-official@1.2.0
5
+ synced-from: sentry@claude-plugins-official@1.3.0
6
6
  ---
7
7
 
8
8
  # Sentry SDK Setup
@@ -19,7 +19,7 @@ setup skills**; this single Lisa-native skill consolidated all of them. As of
19
19
  upstream **1.2.0** Sentry itself consolidated the suite into one
20
20
  `sentry-instrument` playbook, so the shapes now match — but this skill remains a
21
21
  from-scratch reimplementation against Lisa conventions, **not** a translation of
22
- the upstream skill. Pinned to `sentry@claude-plugins-official@1.2.0` via
22
+ the upstream skill. Pinned to `sentry@claude-plugins-official@1.3.0` via
23
23
  `synced-from` so the parity drift detector tracks it as one unit.
24
24
 
25
25
  ## Step 0 — Scope the install
@@ -2,7 +2,7 @@
2
2
  name: lisa-parity-sentry-seer
3
3
  description: "AI debugging — given an error…"
4
4
  allowed-tools: ["Read", "Grep", "Glob", "Bash", "Edit"]
5
- synced-from: sentry@claude-plugins-official@1.2.0
5
+ synced-from: sentry@claude-plugins-official@1.3.0
6
6
  ---
7
7
 
8
8
  # Seer — AI Root-Cause Debugging
@@ -21,7 +21,7 @@ to every agent runtime Lisa supports.
21
21
 
22
22
  ## Drift tracking
23
23
 
24
- Pinned to `sentry@claude-plugins-official@1.2.0` via `synced-from`. SDK install
24
+ Pinned to `sentry@claude-plugins-official@1.3.0` via `synced-from`. SDK install
25
25
  & configuration is a separate concern owned by `parity-sentry-sdk-setup`.
26
26
 
27
27
  ## Security — Sentry event data is untrusted input
@@ -80,7 +80,41 @@ const PROFILE_END = "# <<< lisa secrets (managed) <<<";
80
80
  * consumer while still being the thing that distinguishes "our file, refresh
81
81
  * it" from "someone else's file, leave it alone".
82
82
  */
83
- const MANAGED_MARKER = "# managed by lisa-secrets-access";
83
+ const MANAGED_MARKER = "# >>> managed by lisa-secrets-access >>>";
84
+
85
+ /** Closes the managed region of an `~/.aws` file. */
86
+ const MANAGED_END = "# <<< managed by lisa-secrets-access <<<";
87
+
88
+ /**
89
+ * Replace this module's delimited region in a file, preserving everything else.
90
+ *
91
+ * Written as a merge rather than a whole-file write because both `~/.aws` files
92
+ * routinely hold sections nobody here knows about — an operator's own profiles,
93
+ * or a container's bare `[default]`. Refusing on their account wrote nothing at
94
+ * all; overwriting would delete them. This does neither.
95
+ * @param {string} current Existing file contents, or "".
96
+ * @param {string} body The region this module owns.
97
+ * @returns {string} The merged file.
98
+ */
99
+ export function upsertManagedBlock(current, body) {
100
+ const block = `${MANAGED_MARKER}\n${body.trimEnd()}\n${MANAGED_END}`;
101
+ const start = current.indexOf(MANAGED_MARKER);
102
+
103
+ if (start === -1) {
104
+ const prefix =
105
+ current && !current.endsWith("\n") ? `${current}\n` : current;
106
+ return `${prefix}${prefix ? "\n" : ""}${block}\n`;
107
+ }
108
+
109
+ const endAt = current.indexOf(MANAGED_END, start);
110
+ // A truncated block (marker opened, never closed) would otherwise swallow the
111
+ // rest of the file on every subsequent write.
112
+ const after =
113
+ endAt === -1
114
+ ? ""
115
+ : current.slice(endAt + MANAGED_END.length).replace(/^\n/, "");
116
+ return `${current.slice(0, start)}${block}\n${after}`;
117
+ }
84
118
 
85
119
  /**
86
120
  * Make every shell in this container load the materialized secrets.
@@ -161,7 +195,7 @@ export function installAwsProfiles(bundle, options = {}) {
161
195
  const {
162
196
  home = process.env.HOME || homedir(),
163
197
  mkdir = mkdirSync,
164
- write = writeFileSync,
198
+ write = writeAtomic,
165
199
  read = readFileSync,
166
200
  exists = existsSync,
167
201
  chmod = chmodSync,
@@ -171,35 +205,32 @@ export function installAwsProfiles(bundle, options = {}) {
171
205
  if (!rendered) return [];
172
206
 
173
207
  const dir = join(home, ".aws");
208
+ mkdir(dir, { recursive: true, mode: 0o700 });
209
+ chmod(dir, 0o700);
174
210
 
175
- // Never overwrite an ~/.aws this did not write.
211
+ // Merge into a delimited block; never replace the file.
212
+ //
213
+ // Refusing whole files whenever one already existed sounded safe and was
214
+ // worse than useless: a container ships `~/.aws/config` containing a bare
215
+ // `[default]`, so the guard fired every time, wrote nothing, and returned
216
+ // silently — while AWS_PROFILE was still derived from the bundle. The session
217
+ // got a pointer to a profile that did not exist:
218
+ //
219
+ // The config profile (agent-dev) could not be found
176
220
  //
177
- // These are whole-file writes, so a pre-existing credentials file a
178
- // developer's own profiles, or something another tool set up would be
179
- // destroyed rather than merged. This only runs on a surface allowed to write
180
- // secrets to disk (a disposable container), but "usually disposable" is not a
181
- // reason to be able to delete someone's credentials. The marker makes our own
182
- // file re-writable while anything else is left alone and reported.
183
- for (const name of ["credentials", "config"]) {
221
+ // Merging keeps the operator's own sections intact AND writes ours, which is
222
+ // what the guard was actually for. Same delimited-block approach as the shell
223
+ // profile, and `#` is a comment in the shared-config format so the markers are
224
+ // inert to every consumer.
225
+ for (const [name, body] of [
226
+ ["credentials", rendered.credentials],
227
+ ["config", rendered.config],
228
+ ]) {
184
229
  const file = join(dir, name);
185
- if (exists(file) && !String(read(file, "utf8")).includes(MANAGED_MARKER)) {
186
- return [];
187
- }
230
+ const current = exists(file) ? String(read(file, "utf8")) : "";
231
+ write(file, upsertManagedBlock(current, body));
188
232
  }
189
233
 
190
- mkdir(dir, { recursive: true, mode: 0o700 });
191
- chmod(dir, 0o700);
192
- write(
193
- join(dir, "credentials"),
194
- `${MANAGED_MARKER}\n${rendered.credentials}`,
195
- {
196
- mode: 0o600,
197
- }
198
- );
199
- write(join(dir, "config"), `${MANAGED_MARKER}\n${rendered.config}`, {
200
- mode: 0o600,
201
- });
202
-
203
234
  return rendered.profiles;
204
235
  }
205
236
 
@@ -2,7 +2,7 @@
2
2
  name: lisa-parity-sentry-sdk-setup
3
3
  description: "Install and configure the Sentry SDK for a project — detect the framework/runtime, add the correct @sentry/<framework> package, initialize the client, wire the DSN through env, enable error + performance monitoring, and set up source map upload for readable stack traces. One consolidated skill covering react, nextjs, node, nestjs, express, python, django, react-native, and more. Lisa-native reimplementation of Sentry's SDK-setup suite. Use when adding Sentry to a project or fixing an existing Sentry install."
4
4
  allowed-tools: ["Read", "Edit", "Write", "Bash"]
5
- synced-from: sentry@claude-plugins-official@1.2.0
5
+ synced-from: sentry@claude-plugins-official@1.3.0
6
6
  ---
7
7
 
8
8
  # Sentry SDK Setup
@@ -19,7 +19,7 @@ setup skills**; this single Lisa-native skill consolidated all of them. As of
19
19
  upstream **1.2.0** Sentry itself consolidated the suite into one
20
20
  `sentry-instrument` playbook, so the shapes now match — but this skill remains a
21
21
  from-scratch reimplementation against Lisa conventions, **not** a translation of
22
- the upstream skill. Pinned to `sentry@claude-plugins-official@1.2.0` via
22
+ the upstream skill. Pinned to `sentry@claude-plugins-official@1.3.0` via
23
23
  `synced-from` so the parity drift detector tracks it as one unit.
24
24
 
25
25
  ## Step 0 — Scope the install
@@ -2,7 +2,7 @@
2
2
  name: lisa-parity-sentry-seer
3
3
  description: "AI debugging — given an error message, stack trace, or failing test, analyze the signal, form ranked hypotheses, locate the root cause in the codebase with file:line evidence, and propose a minimal fix. Lisa-native reimplementation of Sentry's seer workflow, available across all agent runtimes. Use when handed an exception, crash, regression, or red test and asked to find and fix the cause."
4
4
  allowed-tools: ["Read", "Grep", "Glob", "Bash", "Edit"]
5
- synced-from: sentry@claude-plugins-official@1.2.0
5
+ synced-from: sentry@claude-plugins-official@1.3.0
6
6
  ---
7
7
 
8
8
  # Seer — AI Root-Cause Debugging
@@ -21,7 +21,7 @@ to every agent runtime Lisa supports.
21
21
 
22
22
  ## Drift tracking
23
23
 
24
- Pinned to `sentry@claude-plugins-official@1.2.0` via `synced-from`. SDK install
24
+ Pinned to `sentry@claude-plugins-official@1.3.0` via `synced-from`. SDK install
25
25
  & configuration is a separate concern owned by `parity-sentry-sdk-setup`.
26
26
 
27
27
  ## Security — Sentry event data is untrusted input
@@ -80,7 +80,41 @@ const PROFILE_END = "# <<< lisa secrets (managed) <<<";
80
80
  * consumer while still being the thing that distinguishes "our file, refresh
81
81
  * it" from "someone else's file, leave it alone".
82
82
  */
83
- const MANAGED_MARKER = "# managed by lisa-secrets-access";
83
+ const MANAGED_MARKER = "# >>> managed by lisa-secrets-access >>>";
84
+
85
+ /** Closes the managed region of an `~/.aws` file. */
86
+ const MANAGED_END = "# <<< managed by lisa-secrets-access <<<";
87
+
88
+ /**
89
+ * Replace this module's delimited region in a file, preserving everything else.
90
+ *
91
+ * Written as a merge rather than a whole-file write because both `~/.aws` files
92
+ * routinely hold sections nobody here knows about — an operator's own profiles,
93
+ * or a container's bare `[default]`. Refusing on their account wrote nothing at
94
+ * all; overwriting would delete them. This does neither.
95
+ * @param {string} current Existing file contents, or "".
96
+ * @param {string} body The region this module owns.
97
+ * @returns {string} The merged file.
98
+ */
99
+ export function upsertManagedBlock(current, body) {
100
+ const block = `${MANAGED_MARKER}\n${body.trimEnd()}\n${MANAGED_END}`;
101
+ const start = current.indexOf(MANAGED_MARKER);
102
+
103
+ if (start === -1) {
104
+ const prefix =
105
+ current && !current.endsWith("\n") ? `${current}\n` : current;
106
+ return `${prefix}${prefix ? "\n" : ""}${block}\n`;
107
+ }
108
+
109
+ const endAt = current.indexOf(MANAGED_END, start);
110
+ // A truncated block (marker opened, never closed) would otherwise swallow the
111
+ // rest of the file on every subsequent write.
112
+ const after =
113
+ endAt === -1
114
+ ? ""
115
+ : current.slice(endAt + MANAGED_END.length).replace(/^\n/, "");
116
+ return `${current.slice(0, start)}${block}\n${after}`;
117
+ }
84
118
 
85
119
  /**
86
120
  * Make every shell in this container load the materialized secrets.
@@ -161,7 +195,7 @@ export function installAwsProfiles(bundle, options = {}) {
161
195
  const {
162
196
  home = process.env.HOME || homedir(),
163
197
  mkdir = mkdirSync,
164
- write = writeFileSync,
198
+ write = writeAtomic,
165
199
  read = readFileSync,
166
200
  exists = existsSync,
167
201
  chmod = chmodSync,
@@ -171,35 +205,32 @@ export function installAwsProfiles(bundle, options = {}) {
171
205
  if (!rendered) return [];
172
206
 
173
207
  const dir = join(home, ".aws");
208
+ mkdir(dir, { recursive: true, mode: 0o700 });
209
+ chmod(dir, 0o700);
174
210
 
175
- // Never overwrite an ~/.aws this did not write.
211
+ // Merge into a delimited block; never replace the file.
212
+ //
213
+ // Refusing whole files whenever one already existed sounded safe and was
214
+ // worse than useless: a container ships `~/.aws/config` containing a bare
215
+ // `[default]`, so the guard fired every time, wrote nothing, and returned
216
+ // silently — while AWS_PROFILE was still derived from the bundle. The session
217
+ // got a pointer to a profile that did not exist:
218
+ //
219
+ // The config profile (agent-dev) could not be found
176
220
  //
177
- // These are whole-file writes, so a pre-existing credentials file a
178
- // developer's own profiles, or something another tool set up would be
179
- // destroyed rather than merged. This only runs on a surface allowed to write
180
- // secrets to disk (a disposable container), but "usually disposable" is not a
181
- // reason to be able to delete someone's credentials. The marker makes our own
182
- // file re-writable while anything else is left alone and reported.
183
- for (const name of ["credentials", "config"]) {
221
+ // Merging keeps the operator's own sections intact AND writes ours, which is
222
+ // what the guard was actually for. Same delimited-block approach as the shell
223
+ // profile, and `#` is a comment in the shared-config format so the markers are
224
+ // inert to every consumer.
225
+ for (const [name, body] of [
226
+ ["credentials", rendered.credentials],
227
+ ["config", rendered.config],
228
+ ]) {
184
229
  const file = join(dir, name);
185
- if (exists(file) && !String(read(file, "utf8")).includes(MANAGED_MARKER)) {
186
- return [];
187
- }
230
+ const current = exists(file) ? String(read(file, "utf8")) : "";
231
+ write(file, upsertManagedBlock(current, body));
188
232
  }
189
233
 
190
- mkdir(dir, { recursive: true, mode: 0o700 });
191
- chmod(dir, 0o700);
192
- write(
193
- join(dir, "credentials"),
194
- `${MANAGED_MARKER}\n${rendered.credentials}`,
195
- {
196
- mode: 0o600,
197
- }
198
- );
199
- write(join(dir, "config"), `${MANAGED_MARKER}\n${rendered.config}`, {
200
- mode: 0o600,
201
- });
202
-
203
234
  return rendered.profiles;
204
235
  }
205
236
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.333.0",
3
+ "version": "2.333.2",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -2,7 +2,7 @@
2
2
  name: lisa-parity-sentry-sdk-setup
3
3
  description: "Install and configure the Sentry SDK for a project — detect the framework/runtime, add the correct @sentry/<framework> package, initialize the client, wire the DSN through env, enable error + performance monitoring, and set up source map upload for readable stack traces. One consolidated skill covering react, nextjs, node, nestjs, express, python, django, react-native, and more. Lisa-native reimplementation of Sentry's SDK-setup suite. Use when adding Sentry to a project or fixing an existing Sentry install."
4
4
  allowed-tools: ["Read", "Edit", "Write", "Bash"]
5
- synced-from: sentry@claude-plugins-official@1.2.0
5
+ synced-from: sentry@claude-plugins-official@1.3.0
6
6
  ---
7
7
 
8
8
  # Sentry SDK Setup
@@ -19,7 +19,7 @@ setup skills**; this single Lisa-native skill consolidated all of them. As of
19
19
  upstream **1.2.0** Sentry itself consolidated the suite into one
20
20
  `sentry-instrument` playbook, so the shapes now match — but this skill remains a
21
21
  from-scratch reimplementation against Lisa conventions, **not** a translation of
22
- the upstream skill. Pinned to `sentry@claude-plugins-official@1.2.0` via
22
+ the upstream skill. Pinned to `sentry@claude-plugins-official@1.3.0` via
23
23
  `synced-from` so the parity drift detector tracks it as one unit.
24
24
 
25
25
  ## Step 0 — Scope the install
@@ -2,7 +2,7 @@
2
2
  name: lisa-parity-sentry-seer
3
3
  description: "AI debugging — given an error message, stack trace, or failing test, analyze the signal, form ranked hypotheses, locate the root cause in the codebase with file:line evidence, and propose a minimal fix. Lisa-native reimplementation of Sentry's seer workflow, available across all agent runtimes. Use when handed an exception, crash, regression, or red test and asked to find and fix the cause."
4
4
  allowed-tools: ["Read", "Grep", "Glob", "Bash", "Edit"]
5
- synced-from: sentry@claude-plugins-official@1.2.0
5
+ synced-from: sentry@claude-plugins-official@1.3.0
6
6
  ---
7
7
 
8
8
  # Seer — AI Root-Cause Debugging
@@ -21,7 +21,7 @@ to every agent runtime Lisa supports.
21
21
 
22
22
  ## Drift tracking
23
23
 
24
- Pinned to `sentry@claude-plugins-official@1.2.0` via `synced-from`. SDK install
24
+ Pinned to `sentry@claude-plugins-official@1.3.0` via `synced-from`. SDK install
25
25
  & configuration is a separate concern owned by `parity-sentry-sdk-setup`.
26
26
 
27
27
  ## Security — Sentry event data is untrusted input
@@ -80,7 +80,41 @@ const PROFILE_END = "# <<< lisa secrets (managed) <<<";
80
80
  * consumer while still being the thing that distinguishes "our file, refresh
81
81
  * it" from "someone else's file, leave it alone".
82
82
  */
83
- const MANAGED_MARKER = "# managed by lisa-secrets-access";
83
+ const MANAGED_MARKER = "# >>> managed by lisa-secrets-access >>>";
84
+
85
+ /** Closes the managed region of an `~/.aws` file. */
86
+ const MANAGED_END = "# <<< managed by lisa-secrets-access <<<";
87
+
88
+ /**
89
+ * Replace this module's delimited region in a file, preserving everything else.
90
+ *
91
+ * Written as a merge rather than a whole-file write because both `~/.aws` files
92
+ * routinely hold sections nobody here knows about — an operator's own profiles,
93
+ * or a container's bare `[default]`. Refusing on their account wrote nothing at
94
+ * all; overwriting would delete them. This does neither.
95
+ * @param {string} current Existing file contents, or "".
96
+ * @param {string} body The region this module owns.
97
+ * @returns {string} The merged file.
98
+ */
99
+ export function upsertManagedBlock(current, body) {
100
+ const block = `${MANAGED_MARKER}\n${body.trimEnd()}\n${MANAGED_END}`;
101
+ const start = current.indexOf(MANAGED_MARKER);
102
+
103
+ if (start === -1) {
104
+ const prefix =
105
+ current && !current.endsWith("\n") ? `${current}\n` : current;
106
+ return `${prefix}${prefix ? "\n" : ""}${block}\n`;
107
+ }
108
+
109
+ const endAt = current.indexOf(MANAGED_END, start);
110
+ // A truncated block (marker opened, never closed) would otherwise swallow the
111
+ // rest of the file on every subsequent write.
112
+ const after =
113
+ endAt === -1
114
+ ? ""
115
+ : current.slice(endAt + MANAGED_END.length).replace(/^\n/, "");
116
+ return `${current.slice(0, start)}${block}\n${after}`;
117
+ }
84
118
 
85
119
  /**
86
120
  * Make every shell in this container load the materialized secrets.
@@ -161,7 +195,7 @@ export function installAwsProfiles(bundle, options = {}) {
161
195
  const {
162
196
  home = process.env.HOME || homedir(),
163
197
  mkdir = mkdirSync,
164
- write = writeFileSync,
198
+ write = writeAtomic,
165
199
  read = readFileSync,
166
200
  exists = existsSync,
167
201
  chmod = chmodSync,
@@ -171,35 +205,32 @@ export function installAwsProfiles(bundle, options = {}) {
171
205
  if (!rendered) return [];
172
206
 
173
207
  const dir = join(home, ".aws");
208
+ mkdir(dir, { recursive: true, mode: 0o700 });
209
+ chmod(dir, 0o700);
174
210
 
175
- // Never overwrite an ~/.aws this did not write.
211
+ // Merge into a delimited block; never replace the file.
212
+ //
213
+ // Refusing whole files whenever one already existed sounded safe and was
214
+ // worse than useless: a container ships `~/.aws/config` containing a bare
215
+ // `[default]`, so the guard fired every time, wrote nothing, and returned
216
+ // silently — while AWS_PROFILE was still derived from the bundle. The session
217
+ // got a pointer to a profile that did not exist:
218
+ //
219
+ // The config profile (agent-dev) could not be found
176
220
  //
177
- // These are whole-file writes, so a pre-existing credentials file a
178
- // developer's own profiles, or something another tool set up would be
179
- // destroyed rather than merged. This only runs on a surface allowed to write
180
- // secrets to disk (a disposable container), but "usually disposable" is not a
181
- // reason to be able to delete someone's credentials. The marker makes our own
182
- // file re-writable while anything else is left alone and reported.
183
- for (const name of ["credentials", "config"]) {
221
+ // Merging keeps the operator's own sections intact AND writes ours, which is
222
+ // what the guard was actually for. Same delimited-block approach as the shell
223
+ // profile, and `#` is a comment in the shared-config format so the markers are
224
+ // inert to every consumer.
225
+ for (const [name, body] of [
226
+ ["credentials", rendered.credentials],
227
+ ["config", rendered.config],
228
+ ]) {
184
229
  const file = join(dir, name);
185
- if (exists(file) && !String(read(file, "utf8")).includes(MANAGED_MARKER)) {
186
- return [];
187
- }
230
+ const current = exists(file) ? String(read(file, "utf8")) : "";
231
+ write(file, upsertManagedBlock(current, body));
188
232
  }
189
233
 
190
- mkdir(dir, { recursive: true, mode: 0o700 });
191
- chmod(dir, 0o700);
192
- write(
193
- join(dir, "credentials"),
194
- `${MANAGED_MARKER}\n${rendered.credentials}`,
195
- {
196
- mode: 0o600,
197
- }
198
- );
199
- write(join(dir, "config"), `${MANAGED_MARKER}\n${rendered.config}`, {
200
- mode: 0o600,
201
- });
202
-
203
234
  return rendered.profiles;
204
235
  }
205
236
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.333.0",
3
+ "version": "2.333.2",
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.333.0",
3
+ "version": "2.333.2",
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.333.0",
3
+ "version": "2.333.2",
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.333.0",
3
+ "version": "2.333.2",
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.333.0",
3
+ "version": "2.333.2",
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.333.0",
3
+ "version": "2.333.2",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -2,7 +2,7 @@
2
2
  name: lisa-parity-sentry-sdk-setup
3
3
  description: "Install and configure the Sentry SDK for a project — detect the framework/runtime, add the correct @sentry/<framework> package, initialize the client, wire the DSN through env, enable error + performance monitoring, and set up source map upload for readable stack traces. One consolidated skill covering react, nextjs, node, nestjs, express, python, django, react-native, and more. Lisa-native reimplementation of Sentry's SDK-setup suite. Use when adding Sentry to a project or fixing an existing Sentry install."
4
4
  allowed-tools: ["Read", "Edit", "Write", "Bash"]
5
- synced-from: sentry@claude-plugins-official@1.2.0
5
+ synced-from: sentry@claude-plugins-official@1.3.0
6
6
  ---
7
7
 
8
8
  # Sentry SDK Setup
@@ -19,7 +19,7 @@ setup skills**; this single Lisa-native skill consolidated all of them. As of
19
19
  upstream **1.2.0** Sentry itself consolidated the suite into one
20
20
  `sentry-instrument` playbook, so the shapes now match — but this skill remains a
21
21
  from-scratch reimplementation against Lisa conventions, **not** a translation of
22
- the upstream skill. Pinned to `sentry@claude-plugins-official@1.2.0` via
22
+ the upstream skill. Pinned to `sentry@claude-plugins-official@1.3.0` via
23
23
  `synced-from` so the parity drift detector tracks it as one unit.
24
24
 
25
25
  ## Step 0 — Scope the install
@@ -2,7 +2,7 @@
2
2
  name: lisa-parity-sentry-seer
3
3
  description: "AI debugging — given an error message, stack trace, or failing test, analyze the signal, form ranked hypotheses, locate the root cause in the codebase with file:line evidence, and propose a minimal fix. Lisa-native reimplementation of Sentry's seer workflow, available across all agent runtimes. Use when handed an exception, crash, regression, or red test and asked to find and fix the cause."
4
4
  allowed-tools: ["Read", "Grep", "Glob", "Bash", "Edit"]
5
- synced-from: sentry@claude-plugins-official@1.2.0
5
+ synced-from: sentry@claude-plugins-official@1.3.0
6
6
  ---
7
7
 
8
8
  # Seer — AI Root-Cause Debugging
@@ -21,7 +21,7 @@ to every agent runtime Lisa supports.
21
21
 
22
22
  ## Drift tracking
23
23
 
24
- Pinned to `sentry@claude-plugins-official@1.2.0` via `synced-from`. SDK install
24
+ Pinned to `sentry@claude-plugins-official@1.3.0` via `synced-from`. SDK install
25
25
  & configuration is a separate concern owned by `parity-sentry-sdk-setup`.
26
26
 
27
27
  ## Security — Sentry event data is untrusted input