@codyswann/lisa 2.332.5 → 2.333.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 (78) hide show
  1. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  2. package/dist/core/upstream-evidence-manifest.js +6 -4
  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/aws-bootstrap.mjs +154 -9
  10. package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +93 -2
  11. package/plugins/lisa/skills/lisa-parity-sentry-sdk-setup/SKILL.md +2 -2
  12. package/plugins/lisa/skills/lisa-parity-sentry-seer/SKILL.md +2 -2
  13. package/plugins/lisa/skills/lisa-secrets-access/scripts/aws-bootstrap.mjs +154 -9
  14. package/plugins/lisa/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +93 -2
  15. package/plugins/lisa-agy/plugin.json +1 -1
  16. package/plugins/lisa-agy/skills/lisa-parity-sentry-sdk-setup/SKILL.md +2 -2
  17. package/plugins/lisa-agy/skills/lisa-parity-sentry-seer/SKILL.md +2 -2
  18. package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/aws-bootstrap.mjs +154 -9
  19. package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +93 -2
  20. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  21. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  22. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  23. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  24. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  25. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  26. package/plugins/lisa-copilot/skills/lisa-parity-sentry-sdk-setup/SKILL.md +2 -2
  27. package/plugins/lisa-copilot/skills/lisa-parity-sentry-seer/SKILL.md +2 -2
  28. package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/aws-bootstrap.mjs +154 -9
  29. package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +93 -2
  30. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  31. package/plugins/lisa-cursor/skills/lisa-parity-sentry-sdk-setup/SKILL.md +2 -2
  32. package/plugins/lisa-cursor/skills/lisa-parity-sentry-seer/SKILL.md +2 -2
  33. package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/aws-bootstrap.mjs +154 -9
  34. package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +93 -2
  35. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  37. package/plugins/lisa-expo-agy/plugin.json +1 -1
  38. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  40. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  41. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  42. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  43. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  46. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  47. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  48. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  52. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  53. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  57. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  58. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  62. package/plugins/lisa-rails-agy/plugin.json +1 -1
  63. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  65. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  67. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  68. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  69. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  70. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  71. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  72. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  73. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  74. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  75. package/plugins/src/base/skills/lisa-parity-sentry-sdk-setup/SKILL.md +2 -2
  76. package/plugins/src/base/skills/lisa-parity-sentry-seer/SKILL.md +2 -2
  77. package/plugins/src/base/skills/lisa-secrets-access/scripts/aws-bootstrap.mjs +154 -9
  78. package/plugins/src/base/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +93 -2
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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.332.5",
3
+ "version": "2.333.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"
@@ -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
@@ -33,9 +33,106 @@ const ACCESS_KEY = "AWS_ACCESS_KEY_ID";
33
33
  const SECRET_KEY = "AWS_SECRET_ACCESS_KEY";
34
34
  const REGION = "AWS_DEFAULT_REGION";
35
35
 
36
+ /** Selects which environment's role a session assumes. */
37
+ const PROFILE = "AWS_PROFILE";
38
+
36
39
  /** The bundle that carries the agent's identity. */
37
40
  export const BOOTSTRAP_KEY = "LISA_AWS_BOOTSTRAP_JSON";
38
41
 
42
+ /**
43
+ * The profile that holds the bootstrap key pair and is assumed FROM.
44
+ *
45
+ * Named rather than `default` so it can never be picked up by accident: this
46
+ * identity can assume roles and do nothing else, so a call that silently ran as
47
+ * it would fail with a permissions error far from its cause.
48
+ */
49
+ export const SOURCE_PROFILE = "lisa-bootstrap";
50
+
51
+ /**
52
+ * Read the bundle's `profiles`, which may be an object OR a JSON string.
53
+ *
54
+ * The real bundle stores it double-encoded — a string containing JSON — so a
55
+ * plain `typeof === "object"` check silently yields zero profiles and every
56
+ * environment quietly disappears. Failing that way is worse than throwing:
57
+ * everything still "works", as the assume-only identity, with no permissions.
58
+ * @param {object|null} bundle Parsed bootstrap bundle.
59
+ * @returns {Record<string, {roleArn?: string, region?: string}>} Profiles by name.
60
+ */
61
+ export function readProfiles(bundle) {
62
+ const raw = bundle?.profiles;
63
+ if (!raw) return {};
64
+ if (typeof raw === "object") return raw;
65
+ if (typeof raw !== "string") return {};
66
+ try {
67
+ const parsed = JSON.parse(raw);
68
+ return parsed && typeof parsed === "object" ? parsed : {};
69
+ } catch {
70
+ return {};
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Render `~/.aws/credentials` and `~/.aws/config` from the bundle.
76
+ *
77
+ * The bundle carries a `profiles` map — one entry per environment, each a
78
+ * `roleArn` in a DIFFERENT account — plus the `externalId` those roles require.
79
+ * Nothing consumed any of it, so `--profile agent-dev` failed with "profile not
80
+ * found" and every call fell back to the bootstrap identity in the shared
81
+ * account. That identity can assume roles and nothing else, which is why
82
+ * `aws sts get-caller-identity` could succeed while real work had no
83
+ * permissions anywhere: a green check that proved only the first link.
84
+ *
85
+ * Writing the pair here rather than exporting it is deliberate. Exported
86
+ * environment credentials OUTRANK `AWS_PROFILE`, so a session that exports them
87
+ * ignores whichever profile it selects — the profiles would exist and never be
88
+ * used.
89
+ * @param {object} bundle Parsed bootstrap bundle.
90
+ * @returns {{credentials: string, config: string, profiles: string[]}|null}
91
+ * Rendered file contents and the profile names, or null when unusable.
92
+ */
93
+ export function renderAwsProfiles(bundle) {
94
+ if (!bundle) return null;
95
+
96
+ const accessKeyId = bundle.accessKeyId ?? bundle.aws_access_key_id;
97
+ const secretAccessKey =
98
+ bundle.secretAccessKey ?? bundle.aws_secret_access_key;
99
+ if (!accessKeyId || !secretAccessKey) return null;
100
+
101
+ const profiles = readProfiles(bundle);
102
+
103
+ const credentials = [
104
+ `[${SOURCE_PROFILE}]`,
105
+ `aws_access_key_id = ${accessKeyId}`,
106
+ `aws_secret_access_key = ${secretAccessKey}`,
107
+ "",
108
+ ].join("\n");
109
+
110
+ const sections = [];
111
+ const names = [];
112
+ for (const [name, entry] of Object.entries(profiles)) {
113
+ const roleArn = entry?.roleArn ?? entry?.role_arn;
114
+ if (!roleArn) continue;
115
+
116
+ // A name is only usable if it can be written as an ini section header and
117
+ // read back as the same string. Anything with a bracket or newline would
118
+ // either truncate or inject extra lines into ~/.aws/config, and a config
119
+ // file this corrupts is worse than one it never wrote.
120
+ if (!/^[\w.@-]+$/.test(name)) continue;
121
+
122
+ const lines = [`[profile ${name}]`, `role_arn = ${roleArn}`];
123
+ lines.push(`source_profile = ${SOURCE_PROFILE}`);
124
+ if (bundle.externalId) lines.push(`external_id = ${bundle.externalId}`);
125
+ if (entry.region) lines.push(`region = ${entry.region}`);
126
+ sections.push(`${lines.join("\n")}\n`);
127
+ // Collected here, where the name is already in scope. Recovering it by
128
+ // re-parsing the rendered text made the header format load-bearing: a
129
+ // change to it would silently corrupt every returned name.
130
+ names.push(name);
131
+ }
132
+
133
+ return { credentials, config: sections.join("\n"), profiles: names };
134
+ }
135
+
39
136
  /**
40
137
  * Read the bootstrap bundle, treating anything malformed as absent.
41
138
  *
@@ -80,16 +177,64 @@ export function deriveAwsEnvironment(selected) {
80
177
  // explicit. Overriding that would be this module guessing against an operator.
81
178
  if (selected.has(ACCESS_KEY) || selected.has(SECRET_KEY)) return derived;
82
179
 
83
- const note =
84
- `Derived from ${BOOTSTRAP_KEY} by lisa-secrets-access. Exported ` +
85
- `deliberately so it overrides any ambient ${ACCESS_KEY} the host injects ` +
86
- `environment variables outrank profile files in the AWS credential chain, ` +
87
- `so without this a stale host value wins and every call fails with ` +
88
- `InvalidClientTokenId. This is the assume-only bootstrap identity; real ` +
89
- `work assumes a role from it.`;
180
+ // The key pair is deliberately NOT exported.
181
+ //
182
+ // It used to be, to out-shout the ambient pair a cloud container injects. That
183
+ // worked and cost more than it bought: exported environment credentials
184
+ // outrank `AWS_PROFILE`, so every call ran as the bootstrap identity which
185
+ // can assume roles and do nothing else. `aws sts get-caller-identity`
186
+ // succeeded while real work had no permissions in any environment account,
187
+ // because each environment is a SEPARATE account reached by assuming a role.
188
+ //
189
+ // The pair now lives in ~/.aws/credentials as the source profile, and the
190
+ // session selects an environment instead. The ambient pair is unset by the
191
+ // shell profile rather than overridden — removing the poison beats out-
192
+ // shouting it, and it is what makes `--profile agent-staging` behave exactly
193
+ // as it does on a developer's machine.
194
+ // Only profiles that actually get WRITTEN are candidates. Selecting a name
195
+ // that ~/.aws/config never contains — an entry with no roleArn, or a name too
196
+ // exotic to be an ini header — fails with "profile not found", which is the
197
+ // exact failure this whole change removes.
198
+ const names = renderAwsProfiles(bundle)?.profiles ?? [];
90
199
 
91
- derived.set(ACCESS_KEY, { value: String(accessKeyId), note });
92
- derived.set(SECRET_KEY, { value: String(secretAccessKey), note });
200
+ // No usable profiles is not a reason to hand back a session with NOTHING.
201
+ //
202
+ // The pair stops being exported only because a profile supersedes it. With no
203
+ // profile to select, exporting it is the difference between a degraded
204
+ // session (the assume-only identity, which at least authenticates) and a dead
205
+ // one — and the managed shell block unsets the ambient pair, so nothing would
206
+ // fill the gap.
207
+ if (names.length === 0) {
208
+ const note =
209
+ `Derived from ${BOOTSTRAP_KEY} by lisa-secrets-access. The bundle ` +
210
+ `declares no usable per-environment profile, so this falls back to the ` +
211
+ `bootstrap identity. It can assume roles and little else — if AWS calls ` +
212
+ `fail with permission errors, the bundle's "profiles" map is the thing ` +
213
+ `to check.`;
214
+ derived.set(ACCESS_KEY, { value: String(accessKeyId), note });
215
+ derived.set(SECRET_KEY, { value: String(secretAccessKey), note });
216
+ }
217
+
218
+ if (names.length > 0 && !selected.has(PROFILE)) {
219
+ // Never production by default. An implicit production profile is one
220
+ // careless command away from a bad afternoon; that one must be typed.
221
+ const preferred =
222
+ names.find(name => /dev/i.test(name)) ??
223
+ names.find(name => !/prod/i.test(name)) ??
224
+ names[0];
225
+
226
+ derived.set(PROFILE, {
227
+ value: preferred,
228
+ note:
229
+ `Derived from ${BOOTSTRAP_KEY} by lisa-secrets-access. Selects the ` +
230
+ `environment whose role this session assumes, via ~/.aws/config. ` +
231
+ `Defaults to a non-production profile deliberately — reach production ` +
232
+ `by naming it (\`--profile ${names.find(n => /prod/i.test(n)) ?? "…"}\`). ` +
233
+ `The bootstrap key pair is NOT exported: environment credentials ` +
234
+ `outrank AWS_PROFILE, so exporting them would ignore this selection ` +
235
+ `and run everything as the assume-only identity.`,
236
+ });
237
+ }
93
238
 
94
239
  const region = bundle.region ?? bundle.defaultRegion;
95
240
  if (region && !selected.has(REGION)) {