@codyswann/lisa 2.178.6 → 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-agy/plugin.json +1 -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-cursor/.claude-plugin/plugin.json +1 -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-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- 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-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +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/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/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": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.179.0",
|
|
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.
|
|
3
|
+
"version": "2.179.0",
|
|
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.
|
|
3
|
+
"version": "2.179.0",
|
|
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.
|
|
3
|
+
"version": "2.179.0",
|
|
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.
|
|
3
|
+
"version": "2.179.0",
|
|
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"
|