@codyswann/lisa 1.36.0 → 1.38.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/all/copy-overwrite/CLAUDE.md +1 -0
- package/dist/core/config.d.ts +1 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +2 -0
- package/dist/core/config.js.map +1 -1
- package/dist/detection/detectors/rails.d.ts +15 -0
- package/dist/detection/detectors/rails.d.ts.map +1 -0
- package/dist/detection/detectors/rails.js +34 -0
- package/dist/detection/detectors/rails.js.map +1 -0
- package/dist/detection/index.d.ts.map +1 -1
- package/dist/detection/index.js +2 -0
- package/dist/detection/index.js.map +1 -1
- package/package.json +2 -1
- package/rails/copy-contents/Gemfile +3 -0
- package/rails/copy-overwrite/.claude/rules/lisa.md +44 -0
- package/rails/copy-overwrite/.claude/rules/rails-conventions.md +176 -0
- package/rails/copy-overwrite/.claude/skills/action-controller-best-practices/SKILL.md +374 -0
- package/rails/copy-overwrite/.claude/skills/action-view-best-practices/SKILL.md +335 -0
- package/rails/copy-overwrite/.claude/skills/active-record-model-best-practices/SKILL.md +166 -0
- package/rails/copy-overwrite/.claude/skills/plan-add-test-coverage/SKILL.md +45 -0
- package/rails/copy-overwrite/.claude/skills/plan-fix-linter-error/SKILL.md +45 -0
- package/rails/copy-overwrite/.claude/skills/plan-lower-code-complexity/SKILL.md +48 -0
- package/rails/copy-overwrite/.claude/skills/plan-reduce-max-lines/SKILL.md +46 -0
- package/rails/copy-overwrite/.claude/skills/plan-reduce-max-lines-per-function/SKILL.md +46 -0
- package/rails/copy-overwrite/.rubocop.yml +32 -0
- package/rails/copy-overwrite/.versionrc +48 -0
- package/rails/copy-overwrite/CLAUDE.md +56 -0
- package/rails/copy-overwrite/Gemfile.lisa +52 -0
- package/rails/copy-overwrite/config/initializers/version.rb +5 -0
- package/rails/copy-overwrite/lefthook.yml +20 -0
- package/rails/create-only/.github/workflows/ci.yml +11 -0
- package/rails/create-only/.github/workflows/quality.yml +96 -0
- package/rails/create-only/.github/workflows/release.yml +94 -0
- package/rails/create-only/.mise.toml +2 -0
- package/rails/create-only/.reek.yml +34 -0
- package/rails/create-only/.rspec +3 -0
- package/rails/create-only/.rubocop.local.yml +22 -0
- package/rails/create-only/.simplecov +20 -0
- package/rails/create-only/VERSION +1 -0
- package/rails/create-only/sonar-project.properties +15 -0
- package/rails/create-only/spec/rails_helper.rb +33 -0
- package/rails/create-only/spec/spec_helper.rb +21 -0
- package/rails/deletions.json +3 -0
|
@@ -46,6 +46,7 @@ Never delete anything outside of this project's directory
|
|
|
46
46
|
Never add "BREAKING CHANGE" to a commit message unless there is actually a breaking change
|
|
47
47
|
Never stash changes you can't commit. Either fix whatever is prevening the commit or fail out and let the human know why.
|
|
48
48
|
Never lower thresholds for tests to pass a pre-push hook. You must increase test coverage to make it pass
|
|
49
|
+
Never handle tasks yourself when working in a team of agents. Always delegate to a specialied agent.
|
|
49
50
|
|
|
50
51
|
ONLY use eslint-disable as a last resort and confirm with human before doing so
|
|
51
52
|
ONLY use eslint-disable for test file max-lines when comprehensive test coverage requires extensive test cases (must include matching eslint-enable)
|
package/dist/core/config.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export type CopyStrategy = "copy-overwrite" | "copy-contents" | "create-only" |
|
|
|
5
5
|
/**
|
|
6
6
|
* Available project types that Lisa can detect and configure
|
|
7
7
|
*/
|
|
8
|
-
export type ProjectType = "typescript" | "expo" | "nestjs" | "cdk" | "npm-package";
|
|
8
|
+
export type ProjectType = "typescript" | "expo" | "nestjs" | "cdk" | "npm-package" | "rails";
|
|
9
9
|
/**
|
|
10
10
|
* Project type hierarchy - child types include their parent types
|
|
11
11
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,YAAY,GACpB,gBAAgB,GAChB,eAAe,GACf,aAAa,GACb,OAAO,GACP,cAAc,GACd,cAAc,CAAC;AAEnB;;GAEG;AACH,MAAM,MAAM,WAAW,GACnB,YAAY,GACZ,MAAM,GACN,QAAQ,GACR,KAAK,GACL,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,YAAY,GACpB,gBAAgB,GAChB,eAAe,GACf,aAAa,GACb,OAAO,GACP,cAAc,GACd,cAAc,CAAC;AAEnB;;GAEG;AACH,MAAM,MAAM,WAAW,GACnB,YAAY,GACZ,MAAM,GACN,QAAQ,GACR,KAAK,GACL,aAAa,GACb,OAAO,CAAC;AAEZ;;GAEG;AACH,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAC3C,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC,CAQ/B,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAAS,WAAW,EAO3C,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,SAAS,YAAY,EAOzC,CAAC;AAEX;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,4CAA4C;IAC5C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAEzB,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAE1B,4DAA4D;IAC5D,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;CAChC;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,UAAU,GAAG,WAAW,CAAC;AAE/D;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChC,QAAQ,CAAC,MAAM,EACX,QAAQ,GACR,SAAS,GACT,aAAa,GACb,UAAU,GACV,QAAQ,GACR,SAAS,CAAC;IACd,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,6CAA6C;IAC7C,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,aAAa,EAAE,SAAS,WAAW,EAAE,CAAC;IAC/C,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,iBAAiB,CAUzD"}
|
package/dist/core/config.js
CHANGED
|
@@ -7,6 +7,7 @@ export const PROJECT_TYPE_HIERARCHY = {
|
|
|
7
7
|
cdk: "typescript",
|
|
8
8
|
"npm-package": "typescript",
|
|
9
9
|
typescript: undefined,
|
|
10
|
+
rails: undefined,
|
|
10
11
|
};
|
|
11
12
|
/**
|
|
12
13
|
* Canonical order for processing project types (parents before children)
|
|
@@ -17,6 +18,7 @@ export const PROJECT_TYPE_ORDER = [
|
|
|
17
18
|
"expo",
|
|
18
19
|
"nestjs",
|
|
19
20
|
"cdk",
|
|
21
|
+
"rails",
|
|
20
22
|
];
|
|
21
23
|
/**
|
|
22
24
|
* All available copy strategies in processing order
|
package/dist/core/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAsBA;;GAEG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAE/B;IACF,IAAI,EAAE,YAAY;IAClB,MAAM,EAAE,YAAY;IACpB,GAAG,EAAE,YAAY;IACjB,aAAa,EAAE,YAAY;IAC3B,UAAU,EAAE,SAAS;IACrB,KAAK,EAAE,SAAS;CACR,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAA2B;IACxD,YAAY;IACZ,aAAa;IACb,MAAM;IACN,QAAQ;IACR,KAAK;IACL,OAAO;CACC,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,eAAe,GAA4B;IACtD,gBAAgB;IAChB,eAAe;IACf,aAAa;IACb,OAAO;IACP,cAAc;IACd,cAAc;CACN,CAAC;AA2EX;;;GAGG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO;QACL,MAAM,EAAE,CAAC;QACT,OAAO,EAAE,CAAC;QACV,WAAW,EAAE,CAAC;QACd,QAAQ,EAAE,CAAC;QACX,MAAM,EAAE,CAAC;QACT,OAAO,EAAE,CAAC;QACV,OAAO,EAAE,CAAC;KACX,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { IProjectTypeDetector } from "../detector.interface.js";
|
|
2
|
+
/**
|
|
3
|
+
* Detector for Ruby on Rails projects
|
|
4
|
+
* Detects by presence of bin/rails or config/application.rb
|
|
5
|
+
*/
|
|
6
|
+
export declare class RailsDetector implements IProjectTypeDetector {
|
|
7
|
+
readonly type: "rails";
|
|
8
|
+
/**
|
|
9
|
+
* Detect if the project uses Ruby on Rails
|
|
10
|
+
* @param destDir - Project directory to check
|
|
11
|
+
* @returns True if Rails is detected
|
|
12
|
+
*/
|
|
13
|
+
detect(destDir: string): Promise<boolean>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=rails.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rails.d.ts","sourceRoot":"","sources":["../../../src/detection/detectors/rails.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAGrE;;;GAGG;AACH,qBAAa,aAAc,YAAW,oBAAoB;IACxD,QAAQ,CAAC,IAAI,EAAG,OAAO,CAAU;IAEjC;;;;OAIG;IACG,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAWhD"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rails project type detector
|
|
3
|
+
*
|
|
4
|
+
* Identifies Ruby on Rails projects by checking for definitive Rails signals:
|
|
5
|
+
* `bin/rails` (primary) or `config/application.rb` (secondary). These markers
|
|
6
|
+
* avoid false positives from other Ruby frameworks like Hanami.
|
|
7
|
+
*
|
|
8
|
+
* @module detection/detectors/rails
|
|
9
|
+
*/
|
|
10
|
+
import * as path from "node:path";
|
|
11
|
+
import { pathExists } from "../../utils/index.js";
|
|
12
|
+
/**
|
|
13
|
+
* Detector for Ruby on Rails projects
|
|
14
|
+
* Detects by presence of bin/rails or config/application.rb
|
|
15
|
+
*/
|
|
16
|
+
export class RailsDetector {
|
|
17
|
+
type = "rails";
|
|
18
|
+
/**
|
|
19
|
+
* Detect if the project uses Ruby on Rails
|
|
20
|
+
* @param destDir - Project directory to check
|
|
21
|
+
* @returns True if Rails is detected
|
|
22
|
+
*/
|
|
23
|
+
async detect(destDir) {
|
|
24
|
+
// Check for bin/rails (primary indicator)
|
|
25
|
+
const binRailsPath = path.join(destDir, "bin", "rails");
|
|
26
|
+
if (await pathExists(binRailsPath)) {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
// Check for config/application.rb (secondary indicator)
|
|
30
|
+
const configAppPath = path.join(destDir, "config", "application.rb");
|
|
31
|
+
return pathExists(configAppPath);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=rails.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rails.js","sourceRoot":"","sources":["../../../src/detection/detectors/rails.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElD;;;GAGG;AACH,MAAM,OAAO,aAAa;IACf,IAAI,GAAG,OAAgB,CAAC;IAEjC;;;;OAIG;IACH,KAAK,CAAC,MAAM,CAAC,OAAe;QAC1B,0CAA0C;QAC1C,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QACxD,IAAI,MAAM,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YACnC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,wDAAwD;QACxD,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAC;QACrE,OAAO,UAAU,CAAC,aAAa,CAAC,CAAC;IACnC,CAAC;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/detection/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/detection/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAQpE,YAAY,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAEpE;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkC;IAE5D;;;OAGG;gBACS,SAAS,CAAC,EAAE,SAAS,oBAAoB,EAAE;IAWvD;;;;OAIG;IACG,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAYxD;;;;;;OAMG;IACH,mBAAmB,CAAC,aAAa,EAAE,SAAS,WAAW,EAAE,GAAG,WAAW,EAAE;CAgB1E;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,gBAAgB,CAEzD"}
|
package/dist/detection/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { ExpoDetector } from "./detectors/expo.js";
|
|
|
4
4
|
import { NestJSDetector } from "./detectors/nestjs.js";
|
|
5
5
|
import { CDKDetector } from "./detectors/cdk.js";
|
|
6
6
|
import { NpmPackageDetector } from "./detectors/npm-package.js";
|
|
7
|
+
import { RailsDetector } from "./detectors/rails.js";
|
|
7
8
|
/**
|
|
8
9
|
* Registry for project type detectors
|
|
9
10
|
*/
|
|
@@ -20,6 +21,7 @@ export class DetectorRegistry {
|
|
|
20
21
|
new ExpoDetector(),
|
|
21
22
|
new NestJSDetector(),
|
|
22
23
|
new CDKDetector(),
|
|
24
|
+
new RailsDetector(),
|
|
23
25
|
];
|
|
24
26
|
}
|
|
25
27
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/detection/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/detection/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD;;GAEG;AACH,MAAM,OAAO,gBAAgB;IACV,SAAS,CAAkC;IAE5D;;;OAGG;IACH,YAAY,SAA2C;QACrD,IAAI,CAAC,SAAS,GAAG,SAAS,IAAI;YAC5B,IAAI,kBAAkB,EAAE;YACxB,IAAI,kBAAkB,EAAE;YACxB,IAAI,YAAY,EAAE;YAClB,IAAI,cAAc,EAAE;YACpB,IAAI,WAAW,EAAE;YACjB,IAAI,aAAa,EAAE;SACpB,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,SAAS,CAAC,OAAe;QAC7B,MAAM,aAAa,GAAkB,EAAE,CAAC;QAExC,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACtC,IAAI,MAAM,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;gBACnC,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACpC,CAAC;QACH,CAAC;QAED,OAAO,aAAa,CAAC;IACvB,CAAC;IAED;;;;;;OAMG;IACH,mBAAmB,CAAC,aAAqC;QACvD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAe,CAAC;QAExC,2CAA2C;QAC3C,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE,CAAC;YACjC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAEnB,MAAM,MAAM,GAAG,sBAAsB,CAAC,IAAI,CAAC,CAAC;YAC5C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;QAED,4DAA4D;QAC5D,OAAO,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/D,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO,IAAI,gBAAgB,EAAE,CAAC;AAChC,CAAC"}
|
package/package.json
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"expo",
|
|
14
14
|
"nestjs",
|
|
15
15
|
"cdk",
|
|
16
|
+
"rails",
|
|
16
17
|
"eslint-plugin-code-organization"
|
|
17
18
|
],
|
|
18
19
|
"trustedDependencies": [
|
|
@@ -88,7 +89,7 @@
|
|
|
88
89
|
"@isaacs/brace-expansion": "^5.0.1"
|
|
89
90
|
},
|
|
90
91
|
"name": "@codyswann/lisa",
|
|
91
|
-
"version": "1.
|
|
92
|
+
"version": "1.38.0",
|
|
92
93
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
93
94
|
"main": "dist/index.js",
|
|
94
95
|
"bin": {
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Lisa-Managed Files
|
|
2
|
+
|
|
3
|
+
The following files are managed by Lisa and will be overwritten on every `lisa` run. Never edit them directly. Where a local override exists, edit that instead.
|
|
4
|
+
|
|
5
|
+
## Files with local overrides (edit the override, not the managed file)
|
|
6
|
+
|
|
7
|
+
| Managed File (do not edit) | Local Override (edit this instead) |
|
|
8
|
+
|---|---|
|
|
9
|
+
| `.rubocop.yml` | `.rubocop.local.yml` |
|
|
10
|
+
|
|
11
|
+
## Create-only files (edit freely, Lisa won't overwrite)
|
|
12
|
+
|
|
13
|
+
- `.claude/rules/PROJECT_RULES.md`
|
|
14
|
+
- `.rubocop.local.yml`
|
|
15
|
+
- `.simplecov`
|
|
16
|
+
- `.reek.yml`
|
|
17
|
+
- `.rspec`
|
|
18
|
+
- `sonar-project.properties`
|
|
19
|
+
- `spec/spec_helper.rb`
|
|
20
|
+
- `spec/rails_helper.rb`
|
|
21
|
+
- `.github/workflows/quality.yml`
|
|
22
|
+
- `.github/workflows/ci.yml`
|
|
23
|
+
- `.github/workflows/release.yml`
|
|
24
|
+
- `VERSION`
|
|
25
|
+
|
|
26
|
+
## Directories with both Lisa-managed and project content
|
|
27
|
+
|
|
28
|
+
These directories contain files deployed by Lisa **and** files you create. Do not edit or delete Lisa-managed files — they will be overwritten. You **can** freely add your own. Check `.lisa-manifest` to see which specific files Lisa manages.
|
|
29
|
+
|
|
30
|
+
- `.claude/skills/` — Add your own skill directories alongside Lisa's
|
|
31
|
+
- `.claude/commands/` — Add your own command namespaces alongside Lisa's
|
|
32
|
+
- `.claude/hooks/` — Add your own hook scripts alongside Lisa's
|
|
33
|
+
- `.claude/agents/` — Add your own agent files alongside Lisa's
|
|
34
|
+
|
|
35
|
+
## Files and directories with NO local override (do not edit at all)
|
|
36
|
+
|
|
37
|
+
- `.claude/rules/coding-philosophy.md`, `.claude/rules/plan.md`, `.claude/rules/verfication.md`
|
|
38
|
+
- `.claude/rules/rails-conventions.md`
|
|
39
|
+
- `CLAUDE.md`, `HUMAN.md`, `.safety-net.json`
|
|
40
|
+
- `.rubocop.yml`, `.versionrc`, `lefthook.yml`, `Gemfile.lisa`
|
|
41
|
+
- `config/initializers/version.rb`
|
|
42
|
+
- `.coderabbit.yml`, `commitlint.config.cjs`
|
|
43
|
+
- `.claude/settings.json`
|
|
44
|
+
- `.claude/README.md`, `.claude/REFERENCE.md`
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# Rails Coding Conventions
|
|
2
|
+
|
|
3
|
+
This rule enforces Rails-specific coding standards for consistency, maintainability, and performance.
|
|
4
|
+
|
|
5
|
+
## Fat Models, Skinny Controllers
|
|
6
|
+
|
|
7
|
+
Controllers handle HTTP concerns only. Business logic belongs in models or service objects.
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
# Correct — controller delegates to model
|
|
11
|
+
class OrdersController < ApplicationController
|
|
12
|
+
def create
|
|
13
|
+
@order = Order.place(order_params, current_user)
|
|
14
|
+
redirect_to @order
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Wrong — business logic in controller
|
|
19
|
+
class OrdersController < ApplicationController
|
|
20
|
+
def create
|
|
21
|
+
@order = Order.new(order_params)
|
|
22
|
+
@order.user = current_user
|
|
23
|
+
@order.total = @order.line_items.sum(&:price)
|
|
24
|
+
@order.apply_discount(current_user.discount_rate)
|
|
25
|
+
@order.save!
|
|
26
|
+
OrderMailer.confirmation(@order).deliver_later
|
|
27
|
+
redirect_to @order
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Service Objects
|
|
33
|
+
|
|
34
|
+
Extract complex business logic into service objects when a model method would be too large or spans multiple models.
|
|
35
|
+
|
|
36
|
+
```ruby
|
|
37
|
+
# app/services/order_placement_service.rb
|
|
38
|
+
class OrderPlacementService
|
|
39
|
+
def initialize(user:, params:)
|
|
40
|
+
@user = user
|
|
41
|
+
@params = params
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def call
|
|
45
|
+
order = Order.new(@params)
|
|
46
|
+
order.user = @user
|
|
47
|
+
order.calculate_total
|
|
48
|
+
order.save!
|
|
49
|
+
OrderMailer.confirmation(order).deliver_later
|
|
50
|
+
order
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Concerns
|
|
56
|
+
|
|
57
|
+
Use concerns to share behavior across models or controllers. Keep concerns focused on a single responsibility.
|
|
58
|
+
|
|
59
|
+
```ruby
|
|
60
|
+
# app/models/concerns/searchable.rb
|
|
61
|
+
module Searchable
|
|
62
|
+
extend ActiveSupport::Concern
|
|
63
|
+
|
|
64
|
+
included do
|
|
65
|
+
scope :search, ->(query) { where("name ILIKE ?", "%#{query}%") }
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## ActiveRecord Patterns
|
|
71
|
+
|
|
72
|
+
### Scopes over class methods for chainable queries
|
|
73
|
+
|
|
74
|
+
```ruby
|
|
75
|
+
# Correct — scope
|
|
76
|
+
scope :active, -> { where(active: true) }
|
|
77
|
+
scope :recent, -> { order(created_at: :desc) }
|
|
78
|
+
|
|
79
|
+
# Wrong — class method for simple query
|
|
80
|
+
def self.active
|
|
81
|
+
where(active: true)
|
|
82
|
+
end
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Validations
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
# Use built-in validators
|
|
89
|
+
validates :email, presence: true, uniqueness: true, format: { with: URI::MailTo::EMAIL_REGEXP }
|
|
90
|
+
validates :age, numericality: { greater_than: 0 }
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Callbacks — use sparingly
|
|
94
|
+
|
|
95
|
+
Prefer explicit service objects over callbacks for complex side effects. Callbacks are acceptable for simple data normalization.
|
|
96
|
+
|
|
97
|
+
```ruby
|
|
98
|
+
# Acceptable — simple normalization
|
|
99
|
+
before_validation :normalize_email
|
|
100
|
+
|
|
101
|
+
private
|
|
102
|
+
|
|
103
|
+
def normalize_email
|
|
104
|
+
self.email = email&.downcase&.strip
|
|
105
|
+
end
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## N+1 Query Prevention
|
|
109
|
+
|
|
110
|
+
Always use `includes`, `preload`, or `eager_load` to prevent N+1 queries. The Bullet gem is included to detect these in development.
|
|
111
|
+
|
|
112
|
+
```ruby
|
|
113
|
+
# Correct — eager loading
|
|
114
|
+
@posts = Post.includes(:author, :comments).where(published: true)
|
|
115
|
+
|
|
116
|
+
# Wrong — N+1 query
|
|
117
|
+
@posts = Post.where(published: true)
|
|
118
|
+
@posts.each { |post| post.author.name } # N+1!
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Strong Parameters
|
|
122
|
+
|
|
123
|
+
Always use strong parameters in controllers. Never use `permit!`.
|
|
124
|
+
|
|
125
|
+
```ruby
|
|
126
|
+
# Correct
|
|
127
|
+
def order_params
|
|
128
|
+
params.require(:order).permit(:product_id, :quantity, :notes)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Wrong — permits everything
|
|
132
|
+
def order_params
|
|
133
|
+
params.require(:order).permit!
|
|
134
|
+
end
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Database Migrations
|
|
138
|
+
|
|
139
|
+
- Use `strong_migrations` gem constraints (included via Gemfile.lisa)
|
|
140
|
+
- Never modify `db/schema.rb` directly
|
|
141
|
+
- Always add indexes for foreign keys and commonly queried columns
|
|
142
|
+
- Use `change` method when the migration is reversible; use `up`/`down` when it is not
|
|
143
|
+
|
|
144
|
+
```ruby
|
|
145
|
+
class AddIndexToOrdersUserId < ActiveRecord::Migration[7.2]
|
|
146
|
+
def change
|
|
147
|
+
add_index :orders, :user_id
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Testing with RSpec
|
|
153
|
+
|
|
154
|
+
- Use `let` and `let!` for test setup
|
|
155
|
+
- Use `described_class` instead of repeating the class name
|
|
156
|
+
- Use `factory_bot` for test data, not fixtures
|
|
157
|
+
- Use `shoulda-matchers` for model validation tests
|
|
158
|
+
- Keep tests focused — one assertion concept per example
|
|
159
|
+
|
|
160
|
+
```ruby
|
|
161
|
+
RSpec.describe Order, type: :model do
|
|
162
|
+
describe "validations" do
|
|
163
|
+
it { is_expected.to validate_presence_of(:user) }
|
|
164
|
+
it { is_expected.to validate_numericality_of(:total).is_greater_than(0) }
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
describe ".recent" do
|
|
168
|
+
it "returns orders in descending creation order" do
|
|
169
|
+
old_order = create(:order, created_at: 1.day.ago)
|
|
170
|
+
new_order = create(:order, created_at: 1.hour.ago)
|
|
171
|
+
|
|
172
|
+
expect(described_class.recent).to eq([new_order, old_order])
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
```
|