roblox-guard 0.4.0 → 0.5.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/AGENTS.md ADDED
@@ -0,0 +1,77 @@
1
+ # Roblox and Luau standards
2
+
3
+ Scope: every `.luau` and `.lua` file in a Roblox project. These rules govern how each script is
4
+ written, not how the project is structured, so they hold under any framework or folder layout.
5
+
6
+ They are active instruction, not background reading. Carry them forward verbatim into any
7
+ summary, handoff, or task note. Never reconstruct them from memory: a half-remembered layout
8
+ rule looks deliberate and is worse than none.
9
+
10
+ ```text
11
+ ROBLOX LUAU SKILL - INVARIANT CARD
12
+ 1 Three sections, this order:
13
+ -- // VARIABLES // -- Services > Modules > Objects > Configuration > State Management
14
+ -- // FUNCTIONS // -- definitions only (ModuleScript: Private before Public)
15
+ -- // INITIALIZATION // -- everything that runs
16
+ Omit a section that would be empty. Never write a placeholder header.
17
+ 2 Documentation Comments (Luau Comments) - default style, adapts to the project.
18
+ Default block: --[[ ]] above the function, desc > @param > @return.
19
+ Moonwave --[=[ ]=] or --- is equally correct when that is the project's style.
20
+ - Desc <= 3 lines and <= 250 chars, contract-level, states PURPOSE.
21
+ - Desc never names what the body does to get there: no APIs, algorithms,
22
+ collaborators, data structures, or code paths.
23
+ - Desc carries NO volatile content: no numbers, thresholds, tunable names,
24
+ feature names, or anything that needs editing when the body is retuned.
25
+ - Tags use Moonwave syntax: @param <name> <type> -- <description>
26
+ and @return <type> -- <description>. Only when they add what the
27
+ signature cannot show.
28
+ - English preferred. No em dashes or double-hyphen dashes as punctuation
29
+ (the -- in a tag is a separator, not punctuation). No emoji.
30
+ - IN-BODY COMMENTS: banned in code you write. Make names and structure say
31
+ it; put the why in the block above. Never delete an existing one;
32
+ propose removal once, Advisory only.
33
+ - Self-documenting code outranks commentary everywhere.
34
+ - Existing project comment style wins. Recommend this style when the user
35
+ asks to restyle; never impose it.
36
+ 3 Server is authoritative. Validate every remote arg: type, range, ownership, rate.
37
+ 4 Clean up everything created. Every connection has an owner and a teardown path.
38
+ 5 No avoidable per-frame garbage. Never poll what has a signal.
39
+ 6 UpdateAsync + backoff. Save on PlayerRemoving. Flush on BindToClose.
40
+ 7 Re-validate after every yield: player gone? instance dead? session changed?
41
+ 8 Never add --!strict unbidden. Never make a [Beta] feature the production default.
42
+ 9 Reuse before writing: project, then stdlib, then engine API. No wrapper or
43
+ abstraction without a caller. But brevity has two hard limits:
44
+ - It NEVER reduces what was asked for. Short because it does less = failed.
45
+ - It NEVER costs readability. One statement per line, descriptive names,
46
+ blank lines kept. Less code means less WORK, not less whitespace.
47
+ 10 No deprecated APIs: wait, spawn, delay, tick, lowercase :connect,
48
+ Humanoid:LoadAnimation, SetPrimaryPartCFrame, Body* movers.
49
+ 11 Engine facts are cited, not remembered. Confirm a newer API against the
50
+ version dump or an in-Studio probe before relying on it.
51
+ 12 User authority outranks these rules. Recommend; never refactor unasked.
52
+ ```
53
+
54
+ ## Full standards
55
+
56
+ This card is the part that must survive a summary. The complete standards, with the reference
57
+ files behind each rule, live in this repository:
58
+
59
+ | Path | Covers |
60
+ |---|---|
61
+ | `skills/best-practices/SKILL.md` | Writing and refactoring Luau |
62
+ | `skills/code-review/SKILL.md` | Reviewing, auditing, and scoring existing code |
63
+ | `skills/studio-ops/SKILL.md` | Studio MCP, sync toolchains, verifying in a running session |
64
+
65
+ Read the one whose task matches. Each reference file is self-contained; read one, not the set.
66
+
67
+ ## The checks run outside you
68
+
69
+ `scripts/roblox-guard.mjs` reports deprecated APIs and out-of-order section headers
70
+ deterministically, with no model involved. Run it on the files you touched before you report
71
+ work as done:
72
+
73
+ ```
74
+ node scripts/roblox-guard.mjs --check <files>
75
+ ```
76
+
77
+ It exits 1 when a file has findings, and each finding names the line and the replacement.
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Muhammad Andriansyah
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Muhammad Andriansyah
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -9,6 +9,7 @@ Professional Roblox and Luau standards for AI agents, and a checker that runs wi
9
9
  [![CI](https://github.com/andrian-syh/roblox-optimum/actions/workflows/ci.yml/badge.svg)](https://github.com/andrian-syh/roblox-optimum/actions/workflows/ci.yml)
10
10
  [![version](https://img.shields.io/github/package-json/v/andrian-syh/roblox-optimum?label=version&color=blue)](CHANGELOG.md)
11
11
  [![license](https://img.shields.io/github/license/andrian-syh/roblox-optimum?color=green)](LICENSE)
12
+ [![npm](https://img.shields.io/npm/v/roblox-guard?label=npm&color=CB3837)](https://www.npmjs.com/package/roblox-guard)
12
13
  [![node](https://img.shields.io/badge/node-%3E%3D18-brightgreen)](package.json)
13
14
  [![dependencies](https://img.shields.io/badge/dependencies-0-brightgreen)](package.json)
14
15
 
@@ -25,8 +26,8 @@ Claude Code, and as a project instruction file everywhere else. [AGENTS.md](AGEN
25
26
  ready to copy, along with a matching file for Cursor, Windsurf, Cline, Kiro, Qoder, Copilot,
26
27
  Qwen Code, and Antigravity.
27
28
 
28
- **The checker** is [`scripts/roblox-guard.mjs`](scripts/roblox-guard.mjs), one Node file with no
29
- dependencies. It reads Luau and reports the same findings whoever wrote the file, so it works as
29
+ **The checker** is [`roblox-guard`](https://www.npmjs.com/package/roblox-guard) on npm, one Node
30
+ file with no dependencies. It reads Luau and reports the same findings whoever wrote the file, so it works as
30
31
  an agent hook, a commit hook, or a CI step. It never asks a model anything, which is why it still
31
32
  holds after a long session has been summarized and the rules have fallen out of context.
32
33
 
@@ -54,9 +55,15 @@ Qwen Code:
54
55
  qwen extensions install https://github.com/andrian-syh/roblox-optimum
55
56
  ```
56
57
 
57
- Cursor, Antigravity, and Kiro install it as a plugin from this repository. For those, plus
58
- OpenCode, Copilot, or a plain commit hook, see **[INSTALL.md](INSTALL.md)**, which also states
59
- plainly what each setup can and cannot do.
58
+ Cursor, Antigravity, Kiro, and Copilot CLI install it as a plugin from this repository. For those,
59
+ plus OpenCode or a plain commit hook, see **[INSTALL.md](INSTALL.md)**, which also states plainly
60
+ what each setup can and cannot do.
61
+
62
+ The checker on its own needs no repository at all:
63
+
64
+ ```
65
+ npx roblox-guard --check src/**/*.luau
66
+ ```
60
67
 
61
68
  ## Skills
62
69
 
@@ -113,6 +120,16 @@ or synced, belong to a project rather than to a person, and are resolved per ses
113
120
  Deprecated APIs and out-of-order section headers. Where the agent can receive them, findings go
114
121
  straight back to it and it fixes its own output before you see it.
115
122
 
123
+ ```
124
+ $ npx roblox-guard --check CoinService.luau
125
+ Roblox standards check failed for CoinService.luau:
126
+ - Line 5: :connect() is deprecated. Use :Connect().
127
+ - Line 6: wait() is deprecated. Use task.wait().
128
+ - Line 8: Humanoid:LoadAnimation() is deprecated. Use Animator:LoadAnimation().
129
+ ```
130
+
131
+ Exit 1, so a commit hook or a build step stops on it.
132
+
116
133
  The check is deliberately conservative, because a wrong complaint gets a guard switched off:
117
134
 
118
135
  - Comments and string literals are excluded, so a rule quoted in prose is never reported as a
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roblox-guard",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Deterministic Roblox and Luau standards checks: deprecated APIs and out-of-order section headers, as an agent hook, a commit hook, or a CI step.",
5
5
  "keywords": [
6
6
  "roblox",
@@ -17,7 +17,8 @@
17
17
  "roblox-guard": "scripts/roblox-guard.mjs"
18
18
  },
19
19
  "files": [
20
- "scripts/roblox-guard.mjs"
20
+ "scripts/roblox-guard.mjs",
21
+ "AGENTS.md"
21
22
  ],
22
23
  "scripts": {
23
24
  "test": "node scripts/roblox-guard.mjs --selftest"
@@ -188,15 +188,21 @@ export function inspect(source) {
188
188
  }
189
189
 
190
190
  const lines = code.split("\n");
191
+ const deprecated = [];
192
+
191
193
  for (const [pattern, name, replacement] of DEPRECATED) {
192
194
  for (let k = 0; k < lines.length; k++) {
193
195
  if (pattern.test(lines[k])) {
194
- problems.push(`Line ${k + 1}: ${name} is deprecated. Use ${replacement}.`);
196
+ deprecated.push({ line: k + 1, text: `Line ${k + 1}: ${name} is deprecated. Use ${replacement}.` });
195
197
  break;
196
198
  }
197
199
  }
198
200
  }
199
201
 
202
+ // Report in reading order. Grouping by pattern is how they are found, not how they are read.
203
+ deprecated.sort((a, b) => a.line - b.line);
204
+ problems.push(...deprecated.map((d) => d.text));
205
+
200
206
  return problems;
201
207
  }
202
208
 
@@ -399,6 +405,15 @@ Players.PlayerAdded:Connect(greet)
399
405
  inspect(good.replace("task.wait(1)", "wait(1)")).some((p) => p.includes("wait()")),
400
406
  "bare wait() is caught",
401
407
  );
408
+ ok(
409
+ (() => {
410
+ const lines = inspect(`-- // VARIABLES // --\nlocal a = 1\n-- // INITIALIZATION // --\nspawn(function()\n\twait(1)\nend)\nx:connect(f)`)
411
+ .map((p) => Number(p.match(/^Line (\d+)/)?.[1]))
412
+ .filter(Number.isFinite);
413
+ return lines.length === 3 && lines.every((n, k) => k === 0 || n >= lines[k - 1]);
414
+ })(),
415
+ "findings are reported in line order, not pattern order",
416
+ );
402
417
  ok(
403
418
  !inspect(good).some((p) => p.includes("wait()")),
404
419
  "task.wait() is not mistaken for wait()",