@codyswann/lisa 2.178.5 → 2.179.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/configs/eslint/phaser.d.ts +2 -8
- package/dist/configs/eslint/phaser.d.ts.map +1 -1
- package/dist/configs/eslint/phaser.js +143 -17
- package/dist/configs/eslint/phaser.js.map +1 -1
- package/eslint-plugin-phaser/README.md +19 -0
- package/eslint-plugin-phaser/index.js +35 -0
- package/eslint-plugin-phaser/package.json +10 -0
- package/eslint-plugin-phaser/rules/no-allocation-in-update.js +189 -0
- package/eslint-plugin-phaser/rules/no-create-in-update.js +200 -0
- package/eslint-plugin-phaser/rules/require-shutdown-cleanup.js +191 -0
- package/package.json +5 -3
- package/phaser/package-lisa/package.lisa.json +11 -3
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/skills/analyze-claude-remote/SKILL.md +72 -2
- package/plugins/lisa/skills/generate-claude-remote-build-script/SKILL.md +30 -1
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/skills/analyze-claude-remote/SKILL.md +72 -2
- package/plugins/lisa-agy/skills/generate-claude-remote-build-script/SKILL.md +30 -1
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/skills/analyze-claude-remote/SKILL.md +72 -2
- package/plugins/lisa-copilot/skills/generate-claude-remote-build-script/SKILL.md +30 -1
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/skills/analyze-claude-remote/SKILL.md +72 -2
- package/plugins/lisa-cursor/skills/generate-claude-remote-build-script/SKILL.md +30 -1
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/agents/ops-specialist.md +2 -2
- package/plugins/lisa-expo/skills/ops-check-logs/SKILL.md +8 -2
- package/plugins/lisa-expo/skills/ops-db-ops/SKILL.md +7 -3
- package/plugins/lisa-expo/skills/ops-deploy/SKILL.md +6 -2
- package/plugins/lisa-expo/skills/ops-run-local/SKILL.md +5 -2
- package/plugins/lisa-expo-agy/agents/ops-specialist.md +2 -2
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-agy/skills/ops-check-logs/SKILL.md +8 -2
- package/plugins/lisa-expo-agy/skills/ops-db-ops/SKILL.md +7 -3
- package/plugins/lisa-expo-agy/skills/ops-deploy/SKILL.md +6 -2
- package/plugins/lisa-expo-agy/skills/ops-run-local/SKILL.md +5 -2
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/agents/ops-specialist.agent.md +2 -2
- package/plugins/lisa-expo-copilot/skills/ops-check-logs/SKILL.md +8 -2
- package/plugins/lisa-expo-copilot/skills/ops-db-ops/SKILL.md +7 -3
- package/plugins/lisa-expo-copilot/skills/ops-deploy/SKILL.md +6 -2
- package/plugins/lisa-expo-copilot/skills/ops-run-local/SKILL.md +5 -2
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/agents/ops-specialist.md +2 -2
- package/plugins/lisa-expo-cursor/skills/ops-check-logs/SKILL.md +8 -2
- package/plugins/lisa-expo-cursor/skills/ops-db-ops/SKILL.md +7 -3
- package/plugins/lisa-expo-cursor/skills/ops-deploy/SKILL.md +6 -2
- package/plugins/lisa-expo-cursor/skills/ops-run-local/SKILL.md +5 -2
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/rules/phaser.md +111 -44
- package/plugins/lisa-phaser/skills/phaser-accessibility/SKILL.md +135 -0
- package/plugins/lisa-phaser/skills/phaser-accessibility/agents/openai.yaml +4 -0
- package/plugins/lisa-phaser/skills/phaser-asset-pipeline/SKILL.md +148 -0
- package/plugins/lisa-phaser/skills/phaser-asset-pipeline/agents/openai.yaml +4 -0
- package/plugins/lisa-phaser/skills/phaser-build-deploy/SKILL.md +148 -0
- package/plugins/lisa-phaser/skills/phaser-build-deploy/agents/openai.yaml +4 -0
- package/plugins/lisa-phaser/skills/phaser-i18n/SKILL.md +122 -0
- package/plugins/lisa-phaser/skills/phaser-i18n/agents/openai.yaml +4 -0
- package/plugins/lisa-phaser/skills/phaser-services/SKILL.md +208 -0
- package/plugins/lisa-phaser/skills/phaser-services/agents/openai.yaml +4 -0
- package/plugins/lisa-phaser/skills/phaser-testing/SKILL.md +103 -10
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/skills/phaser-accessibility/SKILL.md +135 -0
- package/plugins/lisa-phaser-agy/skills/phaser-asset-pipeline/SKILL.md +148 -0
- package/plugins/lisa-phaser-agy/skills/phaser-build-deploy/SKILL.md +148 -0
- package/plugins/lisa-phaser-agy/skills/phaser-i18n/SKILL.md +122 -0
- package/plugins/lisa-phaser-agy/skills/phaser-services/SKILL.md +208 -0
- package/plugins/lisa-phaser-agy/skills/phaser-testing/SKILL.md +103 -10
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/rules/phaser.md +111 -44
- package/plugins/lisa-phaser-copilot/skills/phaser-accessibility/SKILL.md +135 -0
- package/plugins/lisa-phaser-copilot/skills/phaser-asset-pipeline/SKILL.md +148 -0
- package/plugins/lisa-phaser-copilot/skills/phaser-build-deploy/SKILL.md +148 -0
- package/plugins/lisa-phaser-copilot/skills/phaser-i18n/SKILL.md +122 -0
- package/plugins/lisa-phaser-copilot/skills/phaser-services/SKILL.md +208 -0
- package/plugins/lisa-phaser-copilot/skills/phaser-testing/SKILL.md +103 -10
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/rules/phaser.mdc +111 -44
- package/plugins/lisa-phaser-cursor/skills/phaser-accessibility/SKILL.md +135 -0
- package/plugins/lisa-phaser-cursor/skills/phaser-asset-pipeline/SKILL.md +148 -0
- package/plugins/lisa-phaser-cursor/skills/phaser-build-deploy/SKILL.md +148 -0
- package/plugins/lisa-phaser-cursor/skills/phaser-i18n/SKILL.md +122 -0
- package/plugins/lisa-phaser-cursor/skills/phaser-services/SKILL.md +208 -0
- package/plugins/lisa-phaser-cursor/skills/phaser-testing/SKILL.md +103 -10
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/agents/ops-specialist.md +1 -1
- package/plugins/lisa-rails-agy/agents/ops-specialist.md +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/agents/ops-specialist.agent.md +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/agents/ops-specialist.md +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/src/base/skills/analyze-claude-remote/SKILL.md +72 -2
- package/plugins/src/base/skills/generate-claude-remote-build-script/SKILL.md +30 -1
- package/plugins/src/expo/agents/ops-specialist.md +2 -2
- package/plugins/src/expo/skills/ops-check-logs/SKILL.md +8 -2
- package/plugins/src/expo/skills/ops-db-ops/SKILL.md +7 -3
- package/plugins/src/expo/skills/ops-deploy/SKILL.md +6 -2
- package/plugins/src/expo/skills/ops-run-local/SKILL.md +5 -2
- package/plugins/src/phaser/rules/phaser.md +111 -44
- package/plugins/src/phaser/skills/phaser-accessibility/SKILL.md +135 -0
- package/plugins/src/phaser/skills/phaser-asset-pipeline/SKILL.md +148 -0
- package/plugins/src/phaser/skills/phaser-build-deploy/SKILL.md +148 -0
- package/plugins/src/phaser/skills/phaser-i18n/SKILL.md +122 -0
- package/plugins/src/phaser/skills/phaser-services/SKILL.md +208 -0
- package/plugins/src/phaser/skills/phaser-testing/SKILL.md +103 -10
- package/plugins/src/rails/agents/ops-specialist.md +1 -1
- package/tsconfig/phaser.json +8 -1
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is managed by Lisa.
|
|
3
|
+
* Do not edit directly — changes will be overwritten on the next `lisa` run.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* ESLint rule: require-shutdown-cleanup
|
|
8
|
+
*
|
|
9
|
+
* A Phaser Scene is reused across restarts, and listeners registered on objects
|
|
10
|
+
* that OUTLIVE the scene (this.input, this.scale, this.game.events, window,
|
|
11
|
+
* document) are NOT auto-removed on shutdown — they leak and double-fire after a
|
|
12
|
+
* restart. (Listeners on this.events are auto-cleaned, so they're exempt.)
|
|
13
|
+
*
|
|
14
|
+
* This rule flags a class that registers such a persistent external listener but
|
|
15
|
+
* provides no cleanup path. Cleanup is satisfied by EITHER:
|
|
16
|
+
* - a `shutdown()` method on the class, OR
|
|
17
|
+
* - a `this.events.once('shutdown', ...)` / `Phaser.Scenes.Events.SHUTDOWN`
|
|
18
|
+
* handler registered in the class.
|
|
19
|
+
* @module eslint-plugin-phaser/rules/require-shutdown-cleanup
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Resolve a property/method key node to its string name.
|
|
24
|
+
* @param {object} key - An Identifier or Literal key node
|
|
25
|
+
* @returns {string|null} The key name, or null if not resolvable
|
|
26
|
+
*/
|
|
27
|
+
function keyName(key) {
|
|
28
|
+
if (!key) return null;
|
|
29
|
+
if (key.type === "Identifier") return key.name;
|
|
30
|
+
if (key.type === "Literal") return String(key.value);
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Decode a MemberExpression chain into its root node and ordered property names.
|
|
36
|
+
* @param {object} node - A MemberExpression node
|
|
37
|
+
* @returns {{root: object, props: (string|null)[]}} Root node and property names
|
|
38
|
+
*/
|
|
39
|
+
function memberInfo(node) {
|
|
40
|
+
const props = [];
|
|
41
|
+
/**
|
|
42
|
+
* Walk up the member chain, collecting property names.
|
|
43
|
+
* @param {object} cur - Current node in the chain
|
|
44
|
+
* @returns {object} The non-member root node
|
|
45
|
+
*/
|
|
46
|
+
const walk = cur => {
|
|
47
|
+
if (cur && cur.type === "MemberExpression") {
|
|
48
|
+
props.unshift(
|
|
49
|
+
cur.property && cur.property.type === "Identifier"
|
|
50
|
+
? cur.property.name
|
|
51
|
+
: null
|
|
52
|
+
);
|
|
53
|
+
return walk(cur.object);
|
|
54
|
+
}
|
|
55
|
+
return cur;
|
|
56
|
+
};
|
|
57
|
+
return { root: walk(node), props };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Whether a call registers a listener on an emitter that outlives the scene.
|
|
62
|
+
* @param {object} node - A CallExpression node
|
|
63
|
+
* @returns {boolean} True for a persistent external listener registration
|
|
64
|
+
*/
|
|
65
|
+
function isLeakyListener(node) {
|
|
66
|
+
if (node.callee.type !== "MemberExpression") return false;
|
|
67
|
+
const method =
|
|
68
|
+
node.callee.property.type === "Identifier"
|
|
69
|
+
? node.callee.property.name
|
|
70
|
+
: null;
|
|
71
|
+
// window/document/globalThis.addEventListener — external, outlives the scene.
|
|
72
|
+
if (method === "addEventListener") {
|
|
73
|
+
const obj = node.callee.object;
|
|
74
|
+
return (
|
|
75
|
+
obj.type === "Identifier" &&
|
|
76
|
+
(obj.name === "window" ||
|
|
77
|
+
obj.name === "document" ||
|
|
78
|
+
obj.name === "globalThis")
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
if (method !== "on") return false;
|
|
82
|
+
const { root, props } = memberInfo(node.callee);
|
|
83
|
+
if (root.type !== "ThisExpression") return false;
|
|
84
|
+
// this.input(.keyboard|.gamepad|.mouse)?.on(...) and this.scale.on(...)
|
|
85
|
+
if (props[0] === "input" || props[0] === "scale") return true;
|
|
86
|
+
// this.game.events.on(...) — the global game emitter.
|
|
87
|
+
if (props[0] === "game" && props[1] === "events") return true;
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Whether a call registers a scene 'shutdown' handler (in-place cleanup).
|
|
93
|
+
* @param {object} node - A CallExpression node
|
|
94
|
+
* @returns {boolean} True for this.events.on/once('shutdown'|SHUTDOWN, ...)
|
|
95
|
+
*/
|
|
96
|
+
function isShutdownHandler(node) {
|
|
97
|
+
if (node.callee.type !== "MemberExpression") return false;
|
|
98
|
+
const method =
|
|
99
|
+
node.callee.property.type === "Identifier"
|
|
100
|
+
? node.callee.property.name
|
|
101
|
+
: null;
|
|
102
|
+
if (method !== "on" && method !== "once") return false;
|
|
103
|
+
const { root, props } = memberInfo(node.callee);
|
|
104
|
+
if (root.type !== "ThisExpression" || props[0] !== "events") return false;
|
|
105
|
+
const arg = node.arguments[0];
|
|
106
|
+
if (!arg) return false;
|
|
107
|
+
if (arg.type === "Literal" && arg.value === "shutdown") return true;
|
|
108
|
+
// Phaser.Scenes.Events.SHUTDOWN
|
|
109
|
+
if (arg.type === "MemberExpression" && arg.property.type === "Identifier") {
|
|
110
|
+
return arg.property.name === "SHUTDOWN";
|
|
111
|
+
}
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Whether a class body declares a `shutdown` method or field.
|
|
117
|
+
* @param {object} classNode - A ClassDeclaration/ClassExpression node
|
|
118
|
+
* @returns {boolean} True if a `shutdown` member exists
|
|
119
|
+
*/
|
|
120
|
+
function hasShutdownMember(classNode) {
|
|
121
|
+
return classNode.body.body.some(
|
|
122
|
+
el =>
|
|
123
|
+
(el.type === "MethodDefinition" || el.type === "PropertyDefinition") &&
|
|
124
|
+
keyName(el.key) === "shutdown"
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
module.exports = {
|
|
129
|
+
meta: {
|
|
130
|
+
type: "problem",
|
|
131
|
+
docs: {
|
|
132
|
+
description:
|
|
133
|
+
"Require a shutdown cleanup path when a Scene registers persistent external listeners",
|
|
134
|
+
category: "Best Practices",
|
|
135
|
+
recommended: true,
|
|
136
|
+
},
|
|
137
|
+
fixable: null,
|
|
138
|
+
schema: [],
|
|
139
|
+
messages: {
|
|
140
|
+
requireShutdown:
|
|
141
|
+
"This Scene registers a persistent external listener (this.input/scale/game.events or window/document) but has no cleanup. Add a shutdown() method, or this.events.once('shutdown', () => ...), and .off() every listener there — they are not auto-removed and will leak across scene restarts.",
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
create(context) {
|
|
146
|
+
const classStack = [];
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Push class scope state on entry.
|
|
150
|
+
* @param {object} node - The class node being entered
|
|
151
|
+
* @returns {void}
|
|
152
|
+
*/
|
|
153
|
+
const enterClass = node =>
|
|
154
|
+
classStack.push({
|
|
155
|
+
node,
|
|
156
|
+
leaky: [],
|
|
157
|
+
hasShutdown: hasShutdownMember(node),
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Report uncleaned listeners on class exit.
|
|
162
|
+
* @returns {void}
|
|
163
|
+
*/
|
|
164
|
+
const exitClass = () => {
|
|
165
|
+
const frame = classStack.pop();
|
|
166
|
+
if (!frame.hasShutdown && frame.leaky.length > 0) {
|
|
167
|
+
for (const leakyNode of frame.leaky) {
|
|
168
|
+
context.report({ node: leakyNode, messageId: "requireShutdown" });
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
return {
|
|
174
|
+
ClassDeclaration: enterClass,
|
|
175
|
+
ClassExpression: enterClass,
|
|
176
|
+
"ClassDeclaration:exit": exitClass,
|
|
177
|
+
"ClassExpression:exit": exitClass,
|
|
178
|
+
CallExpression(node) {
|
|
179
|
+
if (classStack.length === 0) return;
|
|
180
|
+
const frame = classStack[classStack.length - 1];
|
|
181
|
+
if (isShutdownHandler(node)) {
|
|
182
|
+
frame.hasShutdown = true;
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (isLeakyListener(node)) {
|
|
186
|
+
frame.leaky.push(node);
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
},
|
|
191
|
+
};
|
package/package.json
CHANGED
|
@@ -43,7 +43,8 @@
|
|
|
43
43
|
"workspaces": [
|
|
44
44
|
"eslint-plugin-code-organization",
|
|
45
45
|
"eslint-plugin-component-structure",
|
|
46
|
-
"eslint-plugin-ui-standards"
|
|
46
|
+
"eslint-plugin-ui-standards",
|
|
47
|
+
"eslint-plugin-phaser"
|
|
47
48
|
],
|
|
48
49
|
"files": [
|
|
49
50
|
"dist",
|
|
@@ -63,7 +64,8 @@
|
|
|
63
64
|
".claude-plugin",
|
|
64
65
|
"eslint-plugin-code-organization",
|
|
65
66
|
"eslint-plugin-component-structure",
|
|
66
|
-
"eslint-plugin-ui-standards"
|
|
67
|
+
"eslint-plugin-ui-standards",
|
|
68
|
+
"eslint-plugin-phaser"
|
|
67
69
|
],
|
|
68
70
|
"trustedDependencies": [
|
|
69
71
|
"@ast-grep/cli",
|
|
@@ -91,7 +93,7 @@
|
|
|
91
93
|
"ws": ">=8.20.1"
|
|
92
94
|
},
|
|
93
95
|
"name": "@codyswann/lisa",
|
|
94
|
-
"version": "2.
|
|
96
|
+
"version": "2.179.0",
|
|
95
97
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
96
98
|
"main": "dist/index.js",
|
|
97
99
|
"exports": {
|
|
@@ -64,13 +64,21 @@
|
|
|
64
64
|
"scripts": {
|
|
65
65
|
"dev": "vite",
|
|
66
66
|
"build": "vite build",
|
|
67
|
-
"preview": "vite preview"
|
|
67
|
+
"preview": "vite preview",
|
|
68
|
+
"test:e2e": "playwright test",
|
|
69
|
+
"size": "size-limit"
|
|
68
70
|
},
|
|
69
71
|
"dependencies": {
|
|
70
|
-
"phaser": "^4.
|
|
72
|
+
"phaser": "^4.2.0"
|
|
71
73
|
},
|
|
72
74
|
"devDependencies": {
|
|
73
|
-
"vite": "^
|
|
75
|
+
"vite": "^8.0.0",
|
|
76
|
+
"vite-plugin-pwa": "^1.3.0",
|
|
77
|
+
"@playwright/test": "^1.56.1",
|
|
78
|
+
"free-tex-packer-core": "^0.3.8",
|
|
79
|
+
"audiosprite": "^0.7.2",
|
|
80
|
+
"size-limit": "^12.1.0",
|
|
81
|
+
"@size-limit/preset-app": "^12.1.0"
|
|
74
82
|
}
|
|
75
83
|
},
|
|
76
84
|
"remove": {
|
|
@@ -78,13 +78,18 @@ Group the findings as:
|
|
|
78
78
|
git, and coreutils are present; `gh` is available but should be installed explicitly if scripts
|
|
79
79
|
call it. Classify each `REQUIRED` (core path uses it) vs `OPTIONAL` (only a dormant stack/skill
|
|
80
80
|
uses it). Typical finds: `gh`, `jq`, `docker` (ZAP), `aws`, `acli`, `ruby`/`rubocop`,
|
|
81
|
-
`python3`, `playwright`/chromium, secret scanners.
|
|
81
|
+
`python3`, `playwright`/chromium, secret scanners. Treat AWS as more than a
|
|
82
|
+
binary install: if the repo invokes `aws`, imports AWS SDK packages, uses CDK/Serverless/SST,
|
|
83
|
+
references `AWS_*` env vars, or documents `aws sso login` / `sso_*` profile setup, add the AWS
|
|
84
|
+
credential findings in group 4b as well as the `aws` CLI tool finding.
|
|
82
85
|
|
|
83
86
|
4. **Environment variables & secrets** — scan for `process.env.*`, `${VAR}`/`$VAR` in shell,
|
|
84
87
|
`secrets.*`/`env:` in CI, and config-referenced tokens. Group by integration (GitHub, AWS,
|
|
85
88
|
Atlassian/JIRA/Confluence, Notion, Linear, Anthropic, notifications, feature flags, other).
|
|
86
89
|
Cross-reference `.lisa.config.json` `tracker`/`source` to mark which credentials are **active**
|
|
87
|
-
for this repo vs **dormant** (`OPTIONAL`).
|
|
90
|
+
for this repo vs **dormant** (`OPTIONAL`). Separately classify host-project AWS usage in group 4b:
|
|
91
|
+
AWS can be required even when it is not the tracker or PRD source. Distinguish *where* each var
|
|
92
|
+
must be set, because the
|
|
88
93
|
answer differs and getting it wrong sends the user to do redundant work:
|
|
89
94
|
|
|
90
95
|
- **Committed `.claude/settings.json` `env` flags** (e.g. `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS`,
|
|
@@ -128,6 +133,34 @@ Group the findings as:
|
|
|
128
133
|
guessed. If a value the table needs (server URL, project key, workspace id, email, team key) is
|
|
129
134
|
missing from `.lisa.config.json`, flag it as a `GAP`/`Action:` to set it, rather than inventing one.
|
|
130
135
|
|
|
136
|
+
4b. **AWS operations credentials** — scan the host project for AWS usage independent of Lisa's
|
|
137
|
+
tracker/source config:
|
|
138
|
+
|
|
139
|
+
- `aws` CLI invocations in `scripts/`, package scripts, committed skills/agents, or
|
|
140
|
+
`.github/workflows/`.
|
|
141
|
+
- AWS SDK imports/packages (`@aws-sdk/*`, `aws-sdk`, `boto3`, CDK, Serverless, SST, Amplify,
|
|
142
|
+
Terraform providers).
|
|
143
|
+
- `aws sso login`, `aws:signin:*`, `sso_start_url`, `sso_account_id`, `sso_role_name`, or
|
|
144
|
+
`sso_session` in docs or config.
|
|
145
|
+
- `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`, `AWS_DEFAULT_REGION`,
|
|
146
|
+
`AWS_PROFILE`, role ARN, external ID, account, or CloudWatch/STS references.
|
|
147
|
+
|
|
148
|
+
If AWS is present, emit an AWS credential finding and inventory entry. If the repo's current
|
|
149
|
+
local path is `aws sso login` or an `aws:signin:*` script, classify that local path as a `GAP`
|
|
150
|
+
for headless remote routines: it is an interactive browser/device-authorization flow and cannot
|
|
151
|
+
complete in the cloud. Route to the AWS row in the Credential reference instead of suggesting
|
|
152
|
+
SSO auth. The finding must name the headless substrate: a dedicated IAM principal (user or role)
|
|
153
|
+
with only permission to `sts:AssumeRole`, environment credentials in the routine UI, and
|
|
154
|
+
`~/.aws/config` profiles using `role_arn`, `credential_source = Environment`, optional
|
|
155
|
+
`external_id`, and `region`.
|
|
156
|
+
|
|
157
|
+
When the repository contains concrete non-secret AWS metadata (role ARNs, account aliases,
|
|
158
|
+
profile names, regions, or ExternalId values), include it in an `awsProfiles` inventory array so
|
|
159
|
+
`/lisa:generate-claude-remote-build-script` can write matching `~/.aws/config` profiles. Never
|
|
160
|
+
invent account IDs, ExternalIds, role names, or regions. If AWS is detected but profile metadata
|
|
161
|
+
is absent, emit the required AWS secret names plus an action to add project-specific profile
|
|
162
|
+
metadata to the generated artifact or environment notes.
|
|
163
|
+
|
|
131
164
|
5. **MCP servers** — read every committed `.mcp.json`. For each server report transport and auth.
|
|
132
165
|
Project-scoped HTTP/SSE servers with no interactive auth are `OK`. Flag stdio servers as
|
|
133
166
|
`RISK`/`GAP` (need a local process — only viable if the cloud session can spawn them from the
|
|
@@ -234,6 +267,31 @@ unsuffixed `…_TOKEN`/`…_KEY` is the simplest to set in a single-account rout
|
|
|
234
267
|
- Acquire: `https://linear.app/<workspace>/settings/account/security` → Personal API keys → New API key.
|
|
235
268
|
- Access: the personal API key inherits the user's workspace permissions — the user must be able to read/create/update Issues in the destination team.
|
|
236
269
|
|
|
270
|
+
### AWS — host-project operations, logs, deploys, CDK/Serverless/SST, or AWS SDK usage
|
|
271
|
+
- Headless substrate: a dedicated IAM principal (user or role) with long-lived bootstrap credentials
|
|
272
|
+
stored in the routine environment, used only to call `sts:AssumeRole` into per-account operational
|
|
273
|
+
roles. The routine writes `~/.aws/config` profiles with `role_arn`, `credential_source =
|
|
274
|
+
Environment`, optional `external_id`, and `region`; agents use `aws --profile <profile> ...`.
|
|
275
|
+
- Env: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`; optional `AWS_SESSION_TOKEN` for temporary
|
|
276
|
+
bootstrap credentials; `AWS_DEFAULT_REGION` when no profile region is provided. Role ARNs,
|
|
277
|
+
ExternalIds, profile names, and regions are non-secret project metadata and belong in generated
|
|
278
|
+
artifacts or project docs, not in the skill's global guidance.
|
|
279
|
+
- Allowlist: `*.amazonaws.com`, or narrower service hosts such as `sts.amazonaws.com`,
|
|
280
|
+
`logs.<region>.amazonaws.com`, `cloudwatch.<region>.amazonaws.com`,
|
|
281
|
+
`xray.<region>.amazonaws.com`, `ssm.<region>.amazonaws.com`, and service-specific endpoints the
|
|
282
|
+
repo uses.
|
|
283
|
+
- Access: the bootstrap principal should have only `sts:AssumeRole` on the scoped operational role
|
|
284
|
+
ARNs, preferably guarded by an `ExternalId` condition. The assumed roles carry the real
|
|
285
|
+
permissions needed by the repo (CloudWatch Logs, deploy, SSM, etc.) as short-lived STS
|
|
286
|
+
credentials.
|
|
287
|
+
- IAM Identity Center caveat: an IAM Identity Center permission set provisions an `AWSReservedSSO_*`
|
|
288
|
+
role whose trust allows the SSO service, not an arbitrary IAM principal. A headless IAM principal
|
|
289
|
+
cannot directly assume that reserved role. Use a separate assumable role that attaches the same
|
|
290
|
+
policy as the permission set, with the delegated Identity Center admin keeping that policy as the
|
|
291
|
+
source of truth.
|
|
292
|
+
- Alternative: IAM Roles Anywhere (X.509 to STS) when long-lived bootstrap access keys are
|
|
293
|
+
unacceptable.
|
|
294
|
+
|
|
237
295
|
## Output
|
|
238
296
|
|
|
239
297
|
Render the report grouped exactly as above. Start with one `Summary:` line, then a `Counts:` line
|
|
@@ -296,6 +354,15 @@ so the generator can render acquisition comments into its template:
|
|
|
296
354
|
{ "name": "jam", "transport": "http", "auth": "oauth", "headlessUsable": true, "replacedBy": "jam CLI + JAM_PAT", "dormant": true },
|
|
297
355
|
{ "name": "sonarqube", "transport": "stdio", "auth": "local-wrapper", "headlessUsable": true, "replacedBy": "SONAR_TOKEN + SonarCloud Web API", "dormant": true }
|
|
298
356
|
],
|
|
357
|
+
"awsProfiles": [
|
|
358
|
+
{
|
|
359
|
+
"name": "dev",
|
|
360
|
+
"roleArn": "arn:aws:iam::<account-id>:role/<role-name>",
|
|
361
|
+
"credentialSource": "Environment",
|
|
362
|
+
"externalId": "<project-external-id>",
|
|
363
|
+
"region": "us-east-1"
|
|
364
|
+
}
|
|
365
|
+
],
|
|
299
366
|
"gaps": [ "auto-memory not synced to cloud", "bun package fetch behind proxy", "OS keychain absent — env-var token form only" ],
|
|
300
367
|
"platform": {
|
|
301
368
|
"githubProxy": {
|
|
@@ -346,6 +413,9 @@ so the generator can render acquisition comments into its template:
|
|
|
346
413
|
to environment editors; never imply the generated script can hide them.
|
|
347
414
|
- A browser-OAuth MCP (or interactively-authed CLI) backing an active integration is a `GAP`; the
|
|
348
415
|
remediation is its token substrate from the table, not "authenticate the MCP".
|
|
416
|
+
- `aws sso login`, `sso_*` profile configuration, and project scripts that wrap AWS SSO are
|
|
417
|
+
interactive-auth paths. In a headless routine they are a `GAP`, not a setup step. Route AWS access
|
|
418
|
+
to env-var bootstrap credentials plus assume-role profiles.
|
|
349
419
|
- For non-tracker MCPs, a documented CLI, PAT/API-key, or REST substrate converts the finding from
|
|
350
420
|
a flat `GAP` into an `OPTIONAL` headless recovery path; unknown vendors remain gaps with a
|
|
351
421
|
vendor-substrate follow-up, not invented credentials.
|
|
@@ -31,7 +31,7 @@ tracker/source, plus the host project's own package manager and tooling — not
|
|
|
31
31
|
|
|
32
32
|
1. **Inventory.** Invoke `/lisa:analyze-claude-remote --json` and parse its machine-readable
|
|
33
33
|
inventory block (`packageManager`, `tools`, `env`, `mcp`, `gaps`, `platform`,
|
|
34
|
-
`networkAccess`, `allowlistDomains`). If the analysis cannot run, stop and report why — never
|
|
34
|
+
`networkAccess`, `allowlistDomains`, `awsProfiles`). If the analysis cannot run, stop and report why — never
|
|
35
35
|
emit a script from guesses.
|
|
36
36
|
|
|
37
37
|
2. **Compose the setup script** from the inventory. The script must be:
|
|
@@ -71,6 +71,9 @@ tracker/source, plus the host project's own package manager and tooling — not
|
|
|
71
71
|
include `JAM_PAT`, `SONAR_TOKEN`, or similar documented substrate env vars
|
|
72
72
|
only as optional secrets, with their acquire/scope comments when the analysis
|
|
73
73
|
supplied them. Never invent values or promote dormant substrates to required.
|
|
74
|
+
When AWS entries are present, list `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, optional
|
|
75
|
+
`AWS_SESSION_TOKEN`, and `AWS_DEFAULT_REGION` exactly as the analysis reported. State that these
|
|
76
|
+
bootstrap credentials are for STS assume-role only; do not emit or recommend `aws sso login`.
|
|
74
77
|
|
|
75
78
|
3a. **Emit substrate setup snippets.** When the inventory marks an MCP
|
|
76
79
|
`headlessUsable: true` through a documented substrate, render the matching
|
|
@@ -88,6 +91,19 @@ tracker/source, plus the host project's own package manager and tooling — not
|
|
|
88
91
|
transport supports static-token auth. Do not print a Jam `.mcp.json` header snippet because
|
|
89
92
|
Jam's preferred headless substrate is its PAT-authenticated CLI.
|
|
90
93
|
|
|
94
|
+
3b. **Emit AWS assume-role profile setup.** When the inventory includes `awsProfiles`, write an
|
|
95
|
+
idempotent `~/.aws/config` block gated on `[ -n "${AWS_ACCESS_KEY_ID:-}" ]`. The generated block
|
|
96
|
+
must:
|
|
97
|
+
- `mkdir -p "$HOME/.aws"` and create or append profile stanzas without writing secrets.
|
|
98
|
+
- Emit one `[profile <name>]` stanza per inventory profile with `role_arn`,
|
|
99
|
+
`credential_source = Environment`, `region` when present, and `external_id` when present.
|
|
100
|
+
- Keep regions and ExternalIds as non-secret project metadata from the inventory; never invent
|
|
101
|
+
account IDs, role names, profile names, regions, or ExternalIds.
|
|
102
|
+
- Warn and skip profile writing when AWS profile metadata is absent, while still listing the
|
|
103
|
+
required `AWS_*` env var names in the secret template.
|
|
104
|
+
- Include a comment that agents should use `aws --profile <name> ...` and must not run
|
|
105
|
+
`aws sso login` in headless routines.
|
|
106
|
+
|
|
91
107
|
4. **Emit the allowlist + gaps notice.** List any custom domains the setup or runtime reaches
|
|
92
108
|
(from `networkAccess.allowlistDomains`, falling back to legacy `allowlistDomains`) that the user
|
|
93
109
|
must add when the environment needs Custom network access. Do not include default Trusted domains
|
|
@@ -123,6 +139,9 @@ shape, not a fixed payload):
|
|
|
123
139
|
# # Note: GH_TOKEN is for gh CLI only. Raw git uses Claude's connected-GitHub proxy/identity;
|
|
124
140
|
# # sibling repos reached only by raw git do not need to be in this token scope.
|
|
125
141
|
# - GH_TOKEN=<token> # REQUIRED, github is the active tracker+source
|
|
142
|
+
# - AWS_ACCESS_KEY_ID=<access-key-id> # REQUIRED when AWS inventory is active
|
|
143
|
+
# - AWS_SECRET_ACCESS_KEY=<secret-access-key> # REQUIRED when AWS inventory is active
|
|
144
|
+
# - AWS_SESSION_TOKEN=<session-token> # OPTIONAL for temporary bootstrap creds
|
|
126
145
|
# NETWORK: set the environment to Custom and allowlist these non-default domains if not on Full:
|
|
127
146
|
# - <networkAccess.allowlistDomains, if any>
|
|
128
147
|
set -uo pipefail
|
|
@@ -165,6 +184,14 @@ need gh || (sudo apt-get update -y && sudo apt-get install -y gh)
|
|
|
165
184
|
need jq || sudo apt-get install -y jq
|
|
166
185
|
require gh; require jq
|
|
167
186
|
|
|
187
|
+
# --- AWS assume-role profiles, when inventory includes awsProfiles ---
|
|
188
|
+
if [ -n "${AWS_ACCESS_KEY_ID:-}" ]; then
|
|
189
|
+
mkdir -p "$HOME/.aws"
|
|
190
|
+
# Generated stanzas use credential_source=Environment and contain no secrets.
|
|
191
|
+
# Agents should run: aws --profile <profile> ...
|
|
192
|
+
# Do not run aws sso login in headless routines; SSO requires an interactive browser/device flow.
|
|
193
|
+
fi
|
|
194
|
+
|
|
168
195
|
# --- optional, only with --include-optional ---
|
|
169
196
|
# (docker / ruby / chromium / etc., guarded)
|
|
170
197
|
```
|
|
@@ -186,6 +213,8 @@ to stop are: the analysis could not run, or the `--out` path is not writable.
|
|
|
186
213
|
raw git/cross-repo clone guidance must not expand the token scope to sibling repositories.
|
|
187
214
|
- Never emit an install for a tool the analysis did not surface, and never install `OPTIONAL` tools
|
|
188
215
|
unless `--include-optional` is set.
|
|
216
|
+
- When AWS is in the inventory, generate environment-backed assume-role profile stanzas from
|
|
217
|
+
`awsProfiles`; never emit `aws sso login` as a remote setup step.
|
|
189
218
|
- Prefer `networkAccess.allowlistDomains` over legacy top-level `allowlistDomains`; never emit
|
|
190
219
|
domains already covered by the routine environment's default Trusted list.
|
|
191
220
|
- Keep the script idempotent and detect-before-install so it is safe to re-run and cache.
|
|
@@ -78,13 +78,18 @@ Group the findings as:
|
|
|
78
78
|
git, and coreutils are present; `gh` is available but should be installed explicitly if scripts
|
|
79
79
|
call it. Classify each `REQUIRED` (core path uses it) vs `OPTIONAL` (only a dormant stack/skill
|
|
80
80
|
uses it). Typical finds: `gh`, `jq`, `docker` (ZAP), `aws`, `acli`, `ruby`/`rubocop`,
|
|
81
|
-
`python3`, `playwright`/chromium, secret scanners.
|
|
81
|
+
`python3`, `playwright`/chromium, secret scanners. Treat AWS as more than a
|
|
82
|
+
binary install: if the repo invokes `aws`, imports AWS SDK packages, uses CDK/Serverless/SST,
|
|
83
|
+
references `AWS_*` env vars, or documents `aws sso login` / `sso_*` profile setup, add the AWS
|
|
84
|
+
credential findings in group 4b as well as the `aws` CLI tool finding.
|
|
82
85
|
|
|
83
86
|
4. **Environment variables & secrets** — scan for `process.env.*`, `${VAR}`/`$VAR` in shell,
|
|
84
87
|
`secrets.*`/`env:` in CI, and config-referenced tokens. Group by integration (GitHub, AWS,
|
|
85
88
|
Atlassian/JIRA/Confluence, Notion, Linear, Anthropic, notifications, feature flags, other).
|
|
86
89
|
Cross-reference `.lisa.config.json` `tracker`/`source` to mark which credentials are **active**
|
|
87
|
-
for this repo vs **dormant** (`OPTIONAL`).
|
|
90
|
+
for this repo vs **dormant** (`OPTIONAL`). Separately classify host-project AWS usage in group 4b:
|
|
91
|
+
AWS can be required even when it is not the tracker or PRD source. Distinguish *where* each var
|
|
92
|
+
must be set, because the
|
|
88
93
|
answer differs and getting it wrong sends the user to do redundant work:
|
|
89
94
|
|
|
90
95
|
- **Committed `.claude/settings.json` `env` flags** (e.g. `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS`,
|
|
@@ -128,6 +133,34 @@ Group the findings as:
|
|
|
128
133
|
guessed. If a value the table needs (server URL, project key, workspace id, email, team key) is
|
|
129
134
|
missing from `.lisa.config.json`, flag it as a `GAP`/`Action:` to set it, rather than inventing one.
|
|
130
135
|
|
|
136
|
+
4b. **AWS operations credentials** — scan the host project for AWS usage independent of Lisa's
|
|
137
|
+
tracker/source config:
|
|
138
|
+
|
|
139
|
+
- `aws` CLI invocations in `scripts/`, package scripts, committed skills/agents, or
|
|
140
|
+
`.github/workflows/`.
|
|
141
|
+
- AWS SDK imports/packages (`@aws-sdk/*`, `aws-sdk`, `boto3`, CDK, Serverless, SST, Amplify,
|
|
142
|
+
Terraform providers).
|
|
143
|
+
- `aws sso login`, `aws:signin:*`, `sso_start_url`, `sso_account_id`, `sso_role_name`, or
|
|
144
|
+
`sso_session` in docs or config.
|
|
145
|
+
- `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`, `AWS_DEFAULT_REGION`,
|
|
146
|
+
`AWS_PROFILE`, role ARN, external ID, account, or CloudWatch/STS references.
|
|
147
|
+
|
|
148
|
+
If AWS is present, emit an AWS credential finding and inventory entry. If the repo's current
|
|
149
|
+
local path is `aws sso login` or an `aws:signin:*` script, classify that local path as a `GAP`
|
|
150
|
+
for headless remote routines: it is an interactive browser/device-authorization flow and cannot
|
|
151
|
+
complete in the cloud. Route to the AWS row in the Credential reference instead of suggesting
|
|
152
|
+
SSO auth. The finding must name the headless substrate: a dedicated IAM principal (user or role)
|
|
153
|
+
with only permission to `sts:AssumeRole`, environment credentials in the routine UI, and
|
|
154
|
+
`~/.aws/config` profiles using `role_arn`, `credential_source = Environment`, optional
|
|
155
|
+
`external_id`, and `region`.
|
|
156
|
+
|
|
157
|
+
When the repository contains concrete non-secret AWS metadata (role ARNs, account aliases,
|
|
158
|
+
profile names, regions, or ExternalId values), include it in an `awsProfiles` inventory array so
|
|
159
|
+
`/lisa:generate-claude-remote-build-script` can write matching `~/.aws/config` profiles. Never
|
|
160
|
+
invent account IDs, ExternalIds, role names, or regions. If AWS is detected but profile metadata
|
|
161
|
+
is absent, emit the required AWS secret names plus an action to add project-specific profile
|
|
162
|
+
metadata to the generated artifact or environment notes.
|
|
163
|
+
|
|
131
164
|
5. **MCP servers** — read every committed `.mcp.json`. For each server report transport and auth.
|
|
132
165
|
Project-scoped HTTP/SSE servers with no interactive auth are `OK`. Flag stdio servers as
|
|
133
166
|
`RISK`/`GAP` (need a local process — only viable if the cloud session can spawn them from the
|
|
@@ -234,6 +267,31 @@ unsuffixed `…_TOKEN`/`…_KEY` is the simplest to set in a single-account rout
|
|
|
234
267
|
- Acquire: `https://linear.app/<workspace>/settings/account/security` → Personal API keys → New API key.
|
|
235
268
|
- Access: the personal API key inherits the user's workspace permissions — the user must be able to read/create/update Issues in the destination team.
|
|
236
269
|
|
|
270
|
+
### AWS — host-project operations, logs, deploys, CDK/Serverless/SST, or AWS SDK usage
|
|
271
|
+
- Headless substrate: a dedicated IAM principal (user or role) with long-lived bootstrap credentials
|
|
272
|
+
stored in the routine environment, used only to call `sts:AssumeRole` into per-account operational
|
|
273
|
+
roles. The routine writes `~/.aws/config` profiles with `role_arn`, `credential_source =
|
|
274
|
+
Environment`, optional `external_id`, and `region`; agents use `aws --profile <profile> ...`.
|
|
275
|
+
- Env: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`; optional `AWS_SESSION_TOKEN` for temporary
|
|
276
|
+
bootstrap credentials; `AWS_DEFAULT_REGION` when no profile region is provided. Role ARNs,
|
|
277
|
+
ExternalIds, profile names, and regions are non-secret project metadata and belong in generated
|
|
278
|
+
artifacts or project docs, not in the skill's global guidance.
|
|
279
|
+
- Allowlist: `*.amazonaws.com`, or narrower service hosts such as `sts.amazonaws.com`,
|
|
280
|
+
`logs.<region>.amazonaws.com`, `cloudwatch.<region>.amazonaws.com`,
|
|
281
|
+
`xray.<region>.amazonaws.com`, `ssm.<region>.amazonaws.com`, and service-specific endpoints the
|
|
282
|
+
repo uses.
|
|
283
|
+
- Access: the bootstrap principal should have only `sts:AssumeRole` on the scoped operational role
|
|
284
|
+
ARNs, preferably guarded by an `ExternalId` condition. The assumed roles carry the real
|
|
285
|
+
permissions needed by the repo (CloudWatch Logs, deploy, SSM, etc.) as short-lived STS
|
|
286
|
+
credentials.
|
|
287
|
+
- IAM Identity Center caveat: an IAM Identity Center permission set provisions an `AWSReservedSSO_*`
|
|
288
|
+
role whose trust allows the SSO service, not an arbitrary IAM principal. A headless IAM principal
|
|
289
|
+
cannot directly assume that reserved role. Use a separate assumable role that attaches the same
|
|
290
|
+
policy as the permission set, with the delegated Identity Center admin keeping that policy as the
|
|
291
|
+
source of truth.
|
|
292
|
+
- Alternative: IAM Roles Anywhere (X.509 to STS) when long-lived bootstrap access keys are
|
|
293
|
+
unacceptable.
|
|
294
|
+
|
|
237
295
|
## Output
|
|
238
296
|
|
|
239
297
|
Render the report grouped exactly as above. Start with one `Summary:` line, then a `Counts:` line
|
|
@@ -296,6 +354,15 @@ so the generator can render acquisition comments into its template:
|
|
|
296
354
|
{ "name": "jam", "transport": "http", "auth": "oauth", "headlessUsable": true, "replacedBy": "jam CLI + JAM_PAT", "dormant": true },
|
|
297
355
|
{ "name": "sonarqube", "transport": "stdio", "auth": "local-wrapper", "headlessUsable": true, "replacedBy": "SONAR_TOKEN + SonarCloud Web API", "dormant": true }
|
|
298
356
|
],
|
|
357
|
+
"awsProfiles": [
|
|
358
|
+
{
|
|
359
|
+
"name": "dev",
|
|
360
|
+
"roleArn": "arn:aws:iam::<account-id>:role/<role-name>",
|
|
361
|
+
"credentialSource": "Environment",
|
|
362
|
+
"externalId": "<project-external-id>",
|
|
363
|
+
"region": "us-east-1"
|
|
364
|
+
}
|
|
365
|
+
],
|
|
299
366
|
"gaps": [ "auto-memory not synced to cloud", "bun package fetch behind proxy", "OS keychain absent — env-var token form only" ],
|
|
300
367
|
"platform": {
|
|
301
368
|
"githubProxy": {
|
|
@@ -346,6 +413,9 @@ so the generator can render acquisition comments into its template:
|
|
|
346
413
|
to environment editors; never imply the generated script can hide them.
|
|
347
414
|
- A browser-OAuth MCP (or interactively-authed CLI) backing an active integration is a `GAP`; the
|
|
348
415
|
remediation is its token substrate from the table, not "authenticate the MCP".
|
|
416
|
+
- `aws sso login`, `sso_*` profile configuration, and project scripts that wrap AWS SSO are
|
|
417
|
+
interactive-auth paths. In a headless routine they are a `GAP`, not a setup step. Route AWS access
|
|
418
|
+
to env-var bootstrap credentials plus assume-role profiles.
|
|
349
419
|
- For non-tracker MCPs, a documented CLI, PAT/API-key, or REST substrate converts the finding from
|
|
350
420
|
a flat `GAP` into an `OPTIONAL` headless recovery path; unknown vendors remain gaps with a
|
|
351
421
|
vendor-substrate follow-up, not invented credentials.
|
|
@@ -31,7 +31,7 @@ tracker/source, plus the host project's own package manager and tooling — not
|
|
|
31
31
|
|
|
32
32
|
1. **Inventory.** Invoke `/lisa:analyze-claude-remote --json` and parse its machine-readable
|
|
33
33
|
inventory block (`packageManager`, `tools`, `env`, `mcp`, `gaps`, `platform`,
|
|
34
|
-
`networkAccess`, `allowlistDomains`). If the analysis cannot run, stop and report why — never
|
|
34
|
+
`networkAccess`, `allowlistDomains`, `awsProfiles`). If the analysis cannot run, stop and report why — never
|
|
35
35
|
emit a script from guesses.
|
|
36
36
|
|
|
37
37
|
2. **Compose the setup script** from the inventory. The script must be:
|
|
@@ -71,6 +71,9 @@ tracker/source, plus the host project's own package manager and tooling — not
|
|
|
71
71
|
include `JAM_PAT`, `SONAR_TOKEN`, or similar documented substrate env vars
|
|
72
72
|
only as optional secrets, with their acquire/scope comments when the analysis
|
|
73
73
|
supplied them. Never invent values or promote dormant substrates to required.
|
|
74
|
+
When AWS entries are present, list `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, optional
|
|
75
|
+
`AWS_SESSION_TOKEN`, and `AWS_DEFAULT_REGION` exactly as the analysis reported. State that these
|
|
76
|
+
bootstrap credentials are for STS assume-role only; do not emit or recommend `aws sso login`.
|
|
74
77
|
|
|
75
78
|
3a. **Emit substrate setup snippets.** When the inventory marks an MCP
|
|
76
79
|
`headlessUsable: true` through a documented substrate, render the matching
|
|
@@ -88,6 +91,19 @@ tracker/source, plus the host project's own package manager and tooling — not
|
|
|
88
91
|
transport supports static-token auth. Do not print a Jam `.mcp.json` header snippet because
|
|
89
92
|
Jam's preferred headless substrate is its PAT-authenticated CLI.
|
|
90
93
|
|
|
94
|
+
3b. **Emit AWS assume-role profile setup.** When the inventory includes `awsProfiles`, write an
|
|
95
|
+
idempotent `~/.aws/config` block gated on `[ -n "${AWS_ACCESS_KEY_ID:-}" ]`. The generated block
|
|
96
|
+
must:
|
|
97
|
+
- `mkdir -p "$HOME/.aws"` and create or append profile stanzas without writing secrets.
|
|
98
|
+
- Emit one `[profile <name>]` stanza per inventory profile with `role_arn`,
|
|
99
|
+
`credential_source = Environment`, `region` when present, and `external_id` when present.
|
|
100
|
+
- Keep regions and ExternalIds as non-secret project metadata from the inventory; never invent
|
|
101
|
+
account IDs, role names, profile names, regions, or ExternalIds.
|
|
102
|
+
- Warn and skip profile writing when AWS profile metadata is absent, while still listing the
|
|
103
|
+
required `AWS_*` env var names in the secret template.
|
|
104
|
+
- Include a comment that agents should use `aws --profile <name> ...` and must not run
|
|
105
|
+
`aws sso login` in headless routines.
|
|
106
|
+
|
|
91
107
|
4. **Emit the allowlist + gaps notice.** List any custom domains the setup or runtime reaches
|
|
92
108
|
(from `networkAccess.allowlistDomains`, falling back to legacy `allowlistDomains`) that the user
|
|
93
109
|
must add when the environment needs Custom network access. Do not include default Trusted domains
|
|
@@ -123,6 +139,9 @@ shape, not a fixed payload):
|
|
|
123
139
|
# # Note: GH_TOKEN is for gh CLI only. Raw git uses Claude's connected-GitHub proxy/identity;
|
|
124
140
|
# # sibling repos reached only by raw git do not need to be in this token scope.
|
|
125
141
|
# - GH_TOKEN=<token> # REQUIRED, github is the active tracker+source
|
|
142
|
+
# - AWS_ACCESS_KEY_ID=<access-key-id> # REQUIRED when AWS inventory is active
|
|
143
|
+
# - AWS_SECRET_ACCESS_KEY=<secret-access-key> # REQUIRED when AWS inventory is active
|
|
144
|
+
# - AWS_SESSION_TOKEN=<session-token> # OPTIONAL for temporary bootstrap creds
|
|
126
145
|
# NETWORK: set the environment to Custom and allowlist these non-default domains if not on Full:
|
|
127
146
|
# - <networkAccess.allowlistDomains, if any>
|
|
128
147
|
set -uo pipefail
|
|
@@ -165,6 +184,14 @@ need gh || (sudo apt-get update -y && sudo apt-get install -y gh)
|
|
|
165
184
|
need jq || sudo apt-get install -y jq
|
|
166
185
|
require gh; require jq
|
|
167
186
|
|
|
187
|
+
# --- AWS assume-role profiles, when inventory includes awsProfiles ---
|
|
188
|
+
if [ -n "${AWS_ACCESS_KEY_ID:-}" ]; then
|
|
189
|
+
mkdir -p "$HOME/.aws"
|
|
190
|
+
# Generated stanzas use credential_source=Environment and contain no secrets.
|
|
191
|
+
# Agents should run: aws --profile <profile> ...
|
|
192
|
+
# Do not run aws sso login in headless routines; SSO requires an interactive browser/device flow.
|
|
193
|
+
fi
|
|
194
|
+
|
|
168
195
|
# --- optional, only with --include-optional ---
|
|
169
196
|
# (docker / ruby / chromium / etc., guarded)
|
|
170
197
|
```
|
|
@@ -186,6 +213,8 @@ to stop are: the analysis could not run, or the `--out` path is not writable.
|
|
|
186
213
|
raw git/cross-repo clone guidance must not expand the token scope to sibling repositories.
|
|
187
214
|
- Never emit an install for a tool the analysis did not surface, and never install `OPTIONAL` tools
|
|
188
215
|
unless `--include-optional` is set.
|
|
216
|
+
- When AWS is in the inventory, generate environment-backed assume-role profile stanzas from
|
|
217
|
+
`awsProfiles`; never emit `aws sso login` as a remote setup step.
|
|
189
218
|
- Prefer `networkAccess.allowlistDomains` over legacy top-level `allowlistDomains`; never emit
|
|
190
219
|
domains already covered by the routine environment's default Trusted list.
|
|
191
220
|
- Keep the script idempotent and detect-before-install so it is safe to re-run and cache.
|