@codyswann/lisa 1.35.0 → 1.37.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.
Files changed (41) hide show
  1. package/all/copy-overwrite/.claude/hooks/setup-jira-cli.sh +52 -0
  2. package/all/copy-overwrite/.claude/settings.json +12 -0
  3. package/all/copy-overwrite/CLAUDE.md +1 -0
  4. package/dist/core/config.d.ts +1 -1
  5. package/dist/core/config.d.ts.map +1 -1
  6. package/dist/core/config.js +2 -0
  7. package/dist/core/config.js.map +1 -1
  8. package/dist/detection/detectors/rails.d.ts +15 -0
  9. package/dist/detection/detectors/rails.d.ts.map +1 -0
  10. package/dist/detection/detectors/rails.js +34 -0
  11. package/dist/detection/detectors/rails.js.map +1 -0
  12. package/dist/detection/index.d.ts.map +1 -1
  13. package/dist/detection/index.js +2 -0
  14. package/dist/detection/index.js.map +1 -1
  15. package/expo/copy-overwrite/.mcp.json +0 -8
  16. package/package.json +2 -1
  17. package/rails/copy-contents/Gemfile +3 -0
  18. package/rails/copy-overwrite/.claude/rules/lisa.md +40 -0
  19. package/rails/copy-overwrite/.claude/rules/rails-conventions.md +176 -0
  20. package/rails/copy-overwrite/.claude/skills/plan-add-test-coverage/SKILL.md +45 -0
  21. package/rails/copy-overwrite/.claude/skills/plan-fix-linter-error/SKILL.md +45 -0
  22. package/rails/copy-overwrite/.claude/skills/plan-lower-code-complexity/SKILL.md +48 -0
  23. package/rails/copy-overwrite/.claude/skills/plan-reduce-max-lines/SKILL.md +46 -0
  24. package/rails/copy-overwrite/.claude/skills/plan-reduce-max-lines-per-function/SKILL.md +46 -0
  25. package/rails/copy-overwrite/.rubocop.yml +32 -0
  26. package/rails/copy-overwrite/CLAUDE.md +55 -0
  27. package/rails/copy-overwrite/Gemfile.lisa +52 -0
  28. package/rails/copy-overwrite/lefthook.yml +20 -0
  29. package/rails/create-only/.github/workflows/ci.yml +11 -0
  30. package/rails/create-only/.github/workflows/quality.yml +75 -0
  31. package/rails/create-only/.mise.toml +2 -0
  32. package/rails/create-only/.reek.yml +31 -0
  33. package/rails/create-only/.rspec +3 -0
  34. package/rails/create-only/.rubocop.local.yml +9 -0
  35. package/rails/create-only/.simplecov +20 -0
  36. package/rails/create-only/sonar-project.properties +15 -0
  37. package/rails/create-only/spec/rails_helper.rb +33 -0
  38. package/rails/create-only/spec/spec_helper.rb +21 -0
  39. package/rails/deletions.json +3 -0
  40. package/typescript/copy-overwrite/.claude/hooks/install_pkgs.sh +13 -0
  41. package/typescript/copy-overwrite/.claude/settings.json +10 -0
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env bash
2
+ ##
3
+ # Writes the JIRA CLI config file from environment variables.
4
+ # Runs on SessionStart so the config is available for every session.
5
+ #
6
+ # Required env vars (must be created in your Claude Code Web environment):
7
+ # JIRA_INSTALLATION - cloud or local
8
+ # JIRA_SERVER - Atlassian instance URL
9
+ # JIRA_LOGIN - login email
10
+ # JIRA_PROJECT - default project key
11
+ # JIRA_API_TOKEN - already expected by jira-cli natively
12
+ #
13
+ # Optional env vars:
14
+ # JIRA_BOARD - default board name
15
+ ##
16
+
17
+ set -euo pipefail
18
+
19
+ # Fix jira-cli installation if install_pkgs.sh failed to extract correctly.
20
+ # The tarball nests the binary at jira_VERSION_linux_x86_64/bin/jira,
21
+ # but install_pkgs.sh expects a top-level "jira" file.
22
+ if ! command -v jira &>/dev/null; then
23
+ JIRA_CLI_VERSION="1.7.0"
24
+ TMPDIR=$(mktemp -d)
25
+ curl -sSfL "https://github.com/ankitpokhrel/jira-cli/releases/download/v${JIRA_CLI_VERSION}/jira_${JIRA_CLI_VERSION}_linux_x86_64.tar.gz" \
26
+ | tar -xz -C "${TMPDIR}"
27
+ cp "${TMPDIR}/jira_${JIRA_CLI_VERSION}_linux_x86_64/bin/jira" /usr/local/bin/jira
28
+ chmod +x /usr/local/bin/jira
29
+ rm -rf "${TMPDIR}"
30
+ fi
31
+
32
+ CONFIG_DIR="${HOME}/.config/.jira"
33
+ CONFIG_FILE="${CONFIG_DIR}/.config.yml"
34
+
35
+ # Skip config write if required vars are missing
36
+ if [[ -z "${JIRA_SERVER:-}" || -z "${JIRA_LOGIN:-}" ]]; then
37
+ exit 0
38
+ fi
39
+
40
+ mkdir -p "${CONFIG_DIR}"
41
+
42
+ cat > "${CONFIG_FILE}" << EOF
43
+ installation: ${JIRA_INSTALLATION:-cloud}
44
+ server: ${JIRA_SERVER}
45
+ login: ${JIRA_LOGIN}
46
+ project: ${JIRA_PROJECT:-}
47
+ board: "${JIRA_BOARD:-}"
48
+ auth_type: basic
49
+ epic:
50
+ name: Epic Name
51
+ link: Epic Link
52
+ EOF
@@ -32,6 +32,18 @@
32
32
  ]
33
33
  }
34
34
  ],
35
+ "SessionStart": [
36
+ {
37
+ "matcher": "",
38
+ "hooks": [
39
+ {
40
+ "type": "command",
41
+ "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/setup-jira-cli.sh",
42
+ "timeout": 5
43
+ }
44
+ ]
45
+ }
46
+ ],
35
47
  "PostToolUse": [
36
48
  {
37
49
  "matcher": "Write|Edit",
@@ -45,6 +45,7 @@ Never delete anything that isn't tracked in git
45
45
  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
+ Never lower thresholds for tests to pass a pre-push hook. You must increase test coverage to make it pass
48
49
 
49
50
  ONLY use eslint-disable as a last resort and confirm with human before doing so
50
51
  ONLY use eslint-disable for test file max-lines when comprehensive test coverage requires extensive test cases (must include matching eslint-enable)
@@ -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;AAElB;;GAEG;AACH,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAC3C,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC,CAO/B,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAAS,WAAW,EAM3C,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"}
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"}
@@ -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
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAqBA;;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;CACb,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAA2B;IACxD,YAAY;IACZ,aAAa;IACb,MAAM;IACN,QAAQ;IACR,KAAK;CACG,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"}
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;AAOpE,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;IAUvD;;;;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"}
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"}
@@ -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;AAIhE;;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;SAClB,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"}
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"}
@@ -20,14 +20,6 @@
20
20
  "SONARQUBE_TOKEN": "${SONAR_TOKEN}",
21
21
  "SONARQUBE_ORG": "${SONAR_ORG}"
22
22
  }
23
- },
24
- "atlassian": {
25
- "type": "sse",
26
- "url": "https://mcp.atlassian.com/v1/sse"
27
- },
28
- "playwright": {
29
- "command": "npx",
30
- "args": ["@playwright/mcp@latest"]
31
23
  }
32
24
  }
33
25
  }
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.35.0",
92
+ "version": "1.37.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,3 @@
1
+ # BEGIN: AI GUARDRAILS
2
+ eval_gemfile "Gemfile.lisa"
3
+ # END: AI GUARDRAILS
@@ -0,0 +1,40 @@
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
+
23
+ ## Directories with both Lisa-managed and project content
24
+
25
+ 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.
26
+
27
+ - `.claude/skills/` — Add your own skill directories alongside Lisa's
28
+ - `.claude/commands/` — Add your own command namespaces alongside Lisa's
29
+ - `.claude/hooks/` — Add your own hook scripts alongside Lisa's
30
+ - `.claude/agents/` — Add your own agent files alongside Lisa's
31
+
32
+ ## Files and directories with NO local override (do not edit at all)
33
+
34
+ - `.claude/rules/coding-philosophy.md`, `.claude/rules/plan.md`, `.claude/rules/verfication.md`
35
+ - `.claude/rules/rails-conventions.md`
36
+ - `CLAUDE.md`, `HUMAN.md`, `.safety-net.json`
37
+ - `.rubocop.yml`, `lefthook.yml`, `Gemfile.lisa`
38
+ - `.coderabbit.yml`, `commitlint.config.cjs`
39
+ - `.claude/settings.json`
40
+ - `.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
+ ```
@@ -0,0 +1,45 @@
1
+ ---
2
+ name: plan-add-test-coverage
3
+ description: This skill should be used when increasing test coverage to a specified threshold percentage. It runs the test suite with SimpleCov, identifies files with the lowest coverage, generates a brief with coverage gaps, and creates a plan with tasks to add the missing tests.
4
+ allowed-tools: ["Read", "Bash", "Glob", "Grep"]
5
+
6
+ ---
7
+
8
+ # Increase Test Coverage
9
+
10
+ Target threshold: $ARGUMENTS%
11
+
12
+ If no argument provided, prompt the user for a target.
13
+
14
+ ## Step 1: Gather Requirements
15
+
16
+ 1. **Find coverage config** (`.simplecov` or `spec/spec_helper.rb`)
17
+ 2. **Run test suite with coverage** to get current state:
18
+ ```bash
19
+ bundle exec rspec 2>&1 | tail -50
20
+ ```
21
+ 3. **Check SimpleCov output** in `coverage/index.html` or console output
22
+ 4. **Identify the 20 files with lowest coverage**, noting:
23
+ - File path
24
+ - Current coverage % (lines, branches)
25
+ - Which lines/branches are uncovered
26
+
27
+ ## Step 2: Compile Brief and Delegate
28
+
29
+ Compile the gathered information into a structured brief:
30
+
31
+ ```
32
+ Increase test coverage from [current]% to $ARGUMENTS%.
33
+
34
+ Files needing coverage (ordered by coverage gap):
35
+ 1. [file] - [current]% coverage (target: $ARGUMENTS%)
36
+ - Uncovered: [lines]
37
+ - Missing branch coverage: [lines]
38
+ 2. ...
39
+
40
+ Configuration: .simplecov, update minimum_coverage to $ARGUMENTS%
41
+
42
+ Verification: `bundle exec rspec` -> Expected: SimpleCov reports >= $ARGUMENTS% coverage
43
+ ```
44
+
45
+ Invoke `/plan-create` with this brief to create the implementation plan.
@@ -0,0 +1,45 @@
1
+ ---
2
+ name: plan-fix-linter-error
3
+ description: This skill should be used when fixing all violations of one or more RuboCop cops across the codebase. It runs RuboCop, groups violations by cop and file, generates a brief with fix strategies, and creates a plan with tasks to implement the fixes.
4
+ allowed-tools: ["Read", "Bash", "Glob", "Grep"]
5
+
6
+ ---
7
+
8
+ # Fix Linter Errors
9
+
10
+ Target cops: $ARGUMENTS
11
+
12
+ If no arguments provided, prompt the user for at least one RuboCop cop name.
13
+
14
+ ## Step 1: Gather Requirements
15
+
16
+ 1. **Parse cops** from $ARGUMENTS (space-separated)
17
+ 2. **Run RuboCop** to collect all violations:
18
+ ```bash
19
+ bundle exec rubocop --format json 2>&1
20
+ ```
21
+ 3. **Group violations** by cop, then by file, noting:
22
+ - File path and line numbers
23
+ - Violation count per file
24
+ - Sample offense messages
25
+
26
+ ## Step 2: Compile Brief and Delegate
27
+
28
+ Compile the gathered information into a structured brief:
29
+
30
+ ```
31
+ Fix RuboCop violations for cops: $ARGUMENTS
32
+
33
+ Violations by cop:
34
+ - [CopName1]: X total violations across Y files
35
+ - [file]: N violations (lines: ...)
36
+ - ...
37
+ - [CopName2]: X total violations across Y files
38
+ - ...
39
+
40
+ Fix strategies: extract methods, reduce complexity, apply auto-correct where safe
41
+
42
+ Verification: `bundle exec rubocop --format simple 2>&1 | grep -E "($ARGUMENTS)" | wc -l` -> Expected: 0
43
+ ```
44
+
45
+ Invoke `/plan-create` with this brief to create the implementation plan.
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: plan-lower-code-complexity
3
+ description: This skill should be used when reducing the code complexity threshold of the codebase. It lowers the CyclomaticComplexity threshold by 2, identifies methods that exceed the new limit, generates a brief with refactoring strategies, and creates a plan with tasks to fix all violations.
4
+ allowed-tools: ["Read", "Bash", "Glob", "Grep"]
5
+ ---
6
+
7
+ # Lower Code Complexity
8
+
9
+ Reduces the CyclomaticComplexity threshold by 2 and fixes all violations.
10
+
11
+ ## Step 1: Gather Requirements
12
+
13
+ 1. **Read current threshold** from `.rubocop.yml` (`Metrics/CyclomaticComplexity` Max)
14
+ 2. **Calculate new threshold**: current - 2 (e.g., 10 -> 8)
15
+ 3. **Run RuboCop and flog** to find violations:
16
+ ```bash
17
+ bundle exec rubocop --only Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity --format json 2>&1
18
+ ```
19
+ ```bash
20
+ bundle exec flog --all --group app/ 2>&1 | head -50
21
+ ```
22
+ 4. **Note for each violation**:
23
+ - File path and line number
24
+ - Method name
25
+ - Current complexity score (RuboCop and/or flog)
26
+
27
+ If no violations at new threshold, report success and exit.
28
+
29
+ ## Step 2: Compile Brief and Delegate
30
+
31
+ Compile the gathered information into a structured brief:
32
+
33
+ ```
34
+ Reduce CyclomaticComplexity threshold from [current] to [new].
35
+
36
+ Methods exceeding threshold (ordered by complexity):
37
+ 1. [file:method_name] (complexity: X, target: [new]) - Line Y
38
+ - flog score: Z
39
+ 2. ...
40
+
41
+ Configuration change: .rubocop.local.yml, Metrics/CyclomaticComplexity Max from [current] to [new]
42
+
43
+ Refactoring strategies: extract methods, early returns, extract conditions, use lookup hashes, replace conditionals with polymorphism
44
+
45
+ Verification: `bundle exec rubocop --only Metrics/CyclomaticComplexity --format simple 2>&1 | grep "offense" | wc -l` -> Expected: 0
46
+ ```
47
+
48
+ Invoke `/plan-create` with this brief to create the implementation plan.
@@ -0,0 +1,46 @@
1
+ ---
2
+ name: plan-reduce-max-lines
3
+ description: This skill should be used when reducing the maximum class/module lines threshold and fixing all violations. It updates the RuboCop configuration, identifies classes and modules exceeding the new limit, generates a brief with refactoring strategies, and creates a plan with tasks to split oversized files.
4
+ allowed-tools: ["Read", "Bash", "Glob", "Grep"]
5
+
6
+ ---
7
+
8
+ # Reduce Max Lines
9
+
10
+ Target threshold: $ARGUMENTS lines per class/module
11
+
12
+ If no argument provided, prompt the user for a target.
13
+
14
+ ## Step 1: Gather Requirements
15
+
16
+ 1. **Read current config** from `.rubocop.yml` or `.rubocop.local.yml` (`Metrics/ClassLength` and `Metrics/ModuleLength`)
17
+ 2. **Run RuboCop** with the target threshold to find violations:
18
+ ```bash
19
+ bundle exec rubocop --only Metrics/ClassLength,Metrics/ModuleLength --format json 2>&1
20
+ ```
21
+ 3. **Note for each violation**:
22
+ - File path
23
+ - Class/module name
24
+ - Current line count
25
+
26
+ If no violations at $ARGUMENTS, report success and exit.
27
+
28
+ ## Step 2: Compile Brief and Delegate
29
+
30
+ Compile the gathered information into a structured brief:
31
+
32
+ ```
33
+ Reduce max class/module lines threshold to $ARGUMENTS.
34
+
35
+ Classes/modules exceeding threshold (ordered by line count):
36
+ 1. [file:ClassName] - [current] lines (target: $ARGUMENTS)
37
+ 2. ...
38
+
39
+ Configuration change: .rubocop.local.yml, Metrics/ClassLength Max to $ARGUMENTS, Metrics/ModuleLength Max to $ARGUMENTS
40
+
41
+ Refactoring strategies: extract concerns, extract service objects, remove duplication, delete dead code, simplify logic
42
+
43
+ Verification: `bundle exec rubocop --only Metrics/ClassLength,Metrics/ModuleLength --format simple 2>&1 | grep "offense" | wc -l` -> Expected: 0
44
+ ```
45
+
46
+ Invoke `/plan-create` with this brief to create the implementation plan.
@@ -0,0 +1,46 @@
1
+ ---
2
+ name: plan-reduce-max-lines-per-function
3
+ description: This skill should be used when reducing the maximum lines per method threshold and fixing all violations. It updates the RuboCop configuration, identifies methods exceeding the new limit, generates a brief with refactoring strategies, and creates a plan with tasks to split oversized methods.
4
+ allowed-tools: ["Read", "Bash", "Glob", "Grep"]
5
+
6
+ ---
7
+
8
+ # Reduce Max Lines Per Method
9
+
10
+ Target threshold: $ARGUMENTS lines per method
11
+
12
+ If no argument provided, prompt the user for a target.
13
+
14
+ ## Step 1: Gather Requirements
15
+
16
+ 1. **Read current config** from `.rubocop.yml` or `.rubocop.local.yml` (`Metrics/MethodLength`)
17
+ 2. **Run RuboCop** with the target threshold to find violations:
18
+ ```bash
19
+ bundle exec rubocop --only Metrics/MethodLength --format json 2>&1
20
+ ```
21
+ 3. **Note for each violation**:
22
+ - File path and line number
23
+ - Method name
24
+ - Current line count
25
+
26
+ If no violations at $ARGUMENTS, report success and exit.
27
+
28
+ ## Step 2: Compile Brief and Delegate
29
+
30
+ Compile the gathered information into a structured brief:
31
+
32
+ ```
33
+ Reduce max lines per method threshold to $ARGUMENTS.
34
+
35
+ Methods exceeding threshold (ordered by line count):
36
+ 1. [file:method_name] (lines: X, target: $ARGUMENTS) - Line Y
37
+ 2. ...
38
+
39
+ Configuration change: .rubocop.local.yml, Metrics/MethodLength Max to $ARGUMENTS
40
+
41
+ Refactoring strategies: extract methods, early returns, extract conditions, use lookup hashes, consolidate logic
42
+
43
+ Verification: `bundle exec rubocop --only Metrics/MethodLength --format simple 2>&1 | grep "offense" | wc -l` -> Expected: 0
44
+ ```
45
+
46
+ Invoke `/plan-create` with this brief to create the implementation plan.
@@ -0,0 +1,32 @@
1
+ inherit_from: .rubocop.local.yml
2
+
3
+ require:
4
+ - rubocop-rails
5
+ - rubocop-performance
6
+ - rubocop-rspec
7
+ - rubocop-capybara
8
+ - rubocop-factory_bot
9
+ - rubocop-yard
10
+
11
+ AllCops:
12
+ NewCops: enable
13
+ TargetRubyVersion: 3.4
14
+ Exclude:
15
+ - 'db/schema.rb'
16
+ - 'db/migrate/**/*'
17
+ - 'bin/**/*'
18
+ - 'vendor/**/*'
19
+ - 'node_modules/**/*'
20
+ - 'tmp/**/*'
21
+
22
+ Metrics/MethodLength:
23
+ Max: 20
24
+
25
+ Metrics/ClassLength:
26
+ Max: 200
27
+
28
+ Metrics/AbcSize:
29
+ Max: 25
30
+
31
+ Metrics/CyclomaticComplexity:
32
+ Max: 10
@@ -0,0 +1,55 @@
1
+ You take orders from dumb humans who don't know anything about software development. Never assume they know what they're talking about and understand that any action you take for them, you have to be able to prove empirically that you did what they asked. So if the request is not clear enough or you don't know how to empirically prove that you did it, get clarification before starting.
2
+
3
+ CRITICAL RULES:
4
+
5
+ Always output "I'm tired boss" before starting any task, request or anything else.
6
+ Always figure out the Ruby version the project uses: !`cat .ruby-version`
7
+ Always follow YARD documentation conventions when writing or reviewing documentation to ensure "why" over "what" and proper tag usage
8
+ Always read @Gemfile without limit or offset to understand what gems and dependencies are used
9
+ Always regenerate the lockfile (by running `bundle install`) after adding, removing, or updating gems in the Gemfile
10
+ Always read @.rubocop.yml without limit or offset to understand this project's linting and formatting standards
11
+ Always make atomic commits with clear conventional messages
12
+ Always create clear documentation preambles with YARD for new code
13
+ Always update preambles when updating or modifying code
14
+ Always add language specifiers to fenced code blocks in Markdown.
15
+ Always use project-relative paths rather than absolute paths in documentation and Markdown.
16
+ Always ignore build folders (tmp, log, etc) unless specified otherwise
17
+ Always delete and remove old code completely - no deprecation needed
18
+ Always add `GIT_SSH_COMMAND="ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=5" ` when running `git push`
19
+ Always run `bundle exec rubocop` to verify code style after making changes
20
+ Always run `bundle exec brakeman --no-pager` to verify security after making changes
21
+ Always use `bin/rails` commands instead of `rails` to ensure binstubs are used
22
+
23
+ Never modify this file (CLAUDE.md) directly. To add a memory or learning, add it to .claude/rules/PROJECT_RULES.md or create a skill with /skill-creator.
24
+ Never commit changes to an environment branch (dev, staging, main) directly. This is enforced by the pre-commit hook.
25
+ Never skip or disable any tests or quality checks.
26
+ Never add .skip to a test unless explicitly asked to
27
+ Never directly modify a file in vendor/bundle/
28
+ Never use --no-verify with git commands.
29
+ Never make assumptions about whether something worked. Test it empirically to confirm.
30
+ Never cover up bugs or issues. Always fix them properly.
31
+ Never write functions or methods unless they are needed.
32
+ Never say "not related to our changes" or "not relevant to this task". Always provide a solution.
33
+ Never create functions or variables with versioned names (processV2, handleNew, ClientOld)
34
+ Never write migration code unless explicitly requested
35
+ Never write unhelpful comments like "removed code"
36
+ Never commit changes to an environment branch (dev, staging, main) directly. This is enforced by the pre-commit hook.
37
+ Never skip or disable any tests or quality checks.
38
+ Never use --no-verify or attempt to bypass a git hook
39
+ Never create placeholders
40
+ Never create TODOs
41
+ Never create versions of files (i.e. V2 or Optimized)
42
+ Never assume test expectations before verifying actual implementation behavior (run tests to learn the behavior, then adjust expectations to match)
43
+ Never add rubocop:disable for lint warnings unless absolutely necessary
44
+ Never delete anything that isn't tracked in git
45
+ Never delete anything outside of this project's directory
46
+ Never add "BREAKING CHANGE" to a commit message unless there is actually a breaking change
47
+ Never stash changes you can't commit. Either fix whatever is preventing the commit or fail out and let the human know why.
48
+ Never lower thresholds for tests to pass a pre-push hook. You must increase test coverage to make it pass
49
+ Never modify db/schema.rb directly. Use migrations to change the database schema.
50
+
51
+ ONLY use rubocop:disable as a last resort and confirm with human before doing so
52
+ ONLY use rubocop:disable for specific cops, never disable all cops at once
53
+ ONLY add inline rubocop:disable with matching rubocop:enable
54
+
55
+ Never update CHANGELOG
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is managed by Lisa. Do not edit directly.
4
+ # These gems are governance-critical and will be overwritten on every `lisa` run.
5
+
6
+ # Runtime governance (all environments)
7
+ gem "strong_migrations", "~> 2.5"
8
+ gem "rack-attack", "~> 6.8"
9
+
10
+ group :development, :test do
11
+ # Linting & Style
12
+ gem "rubocop", "~> 1.75", require: false
13
+ gem "rubocop-rails", "~> 2.30", require: false
14
+ gem "rubocop-performance", "~> 1.24", require: false
15
+ gem "rubocop-rspec", "~> 3.5", require: false
16
+ gem "rubocop-capybara", "~> 2.22", require: false
17
+ gem "rubocop-factory_bot", "~> 2.26", require: false
18
+ gem "rubocop-yard", "~> 0.9", require: false
19
+
20
+ # Testing
21
+ gem "rspec-rails", "~> 7.1"
22
+ gem "factory_bot_rails", "~> 6.4"
23
+ gem "faker", "~> 3.5"
24
+ gem "shoulda-matchers", "~> 6.4"
25
+ gem "simplecov", "~> 0.22", require: false
26
+ gem "webmock", "~> 3.24"
27
+ gem "vcr", "~> 6.3"
28
+
29
+ # Code Quality
30
+ gem "reek", "~> 6.3", require: false
31
+ gem "flog", "~> 4.8", require: false
32
+ gem "flay", "~> 2.13", require: false
33
+
34
+ # Security
35
+ gem "brakeman", "~> 7.0", require: false
36
+ gem "bundler-audit", "~> 0.9", require: false
37
+
38
+ # Documentation
39
+ gem "yard", "~> 0.9", require: false
40
+
41
+ # Database Quality
42
+ gem "database_consistency", "~> 1.7", require: false
43
+ end
44
+
45
+ group :development do
46
+ # Performance
47
+ gem "bullet", "~> 8.0"
48
+ gem "rack-mini-profiler", "~> 3.3"
49
+
50
+ # Git Hooks
51
+ gem "lefthook", require: false
52
+ end
@@ -0,0 +1,20 @@
1
+ pre-commit:
2
+ parallel: true
3
+ commands:
4
+ rubocop:
5
+ glob: '*.rb'
6
+ run: bundle exec rubocop --force-exclusion {staged_files}
7
+ bundler-audit:
8
+ run: bundle exec bundler-audit check --update
9
+
10
+ commit-msg:
11
+ commands:
12
+ conventional-commit:
13
+ run: 'head -1 {1} | grep -qE "^(feat|fix|chore|docs|style|refactor|perf|test|build|ci|revert)(\(.+\))?: .+" || (echo "Commit message must follow conventional format" && exit 1)'
14
+
15
+ pre-push:
16
+ commands:
17
+ rspec:
18
+ run: bundle exec rspec
19
+ brakeman:
20
+ run: bundle exec brakeman --no-pager --quiet
@@ -0,0 +1,11 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ workflow_dispatch:
6
+
7
+ jobs:
8
+ quality:
9
+ name: Quality Checks
10
+ uses: ./.github/workflows/quality.yml
11
+ secrets: inherit
@@ -0,0 +1,75 @@
1
+ name: Quality
2
+
3
+ on:
4
+ workflow_call:
5
+ pull_request:
6
+ branches: [main, dev, staging]
7
+ push:
8
+ branches: [main]
9
+
10
+ permissions:
11
+ contents: read
12
+ checks: write
13
+ pull-requests: write
14
+
15
+ jobs:
16
+ lint:
17
+ name: Lint
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - uses: ruby/setup-ruby@v1
22
+ with:
23
+ bundler-cache: true
24
+ - run: bundle exec rubocop --format github
25
+
26
+ security:
27
+ name: Security
28
+ runs-on: ubuntu-latest
29
+ steps:
30
+ - uses: actions/checkout@v4
31
+ - uses: ruby/setup-ruby@v1
32
+ with:
33
+ bundler-cache: true
34
+ - run: bundle exec brakeman --no-pager --quiet
35
+ - run: bundle exec bundler-audit check --update
36
+
37
+ test:
38
+ name: Test
39
+ runs-on: ubuntu-latest
40
+ services:
41
+ postgres:
42
+ image: postgres:16
43
+ env:
44
+ POSTGRES_USER: postgres
45
+ POSTGRES_PASSWORD: postgres
46
+ POSTGRES_DB: test
47
+ ports:
48
+ - 5432:5432
49
+ options: >-
50
+ --health-cmd pg_isready
51
+ --health-interval 10s
52
+ --health-timeout 5s
53
+ --health-retries 5
54
+ env:
55
+ RAILS_ENV: test
56
+ DATABASE_URL: postgres://postgres:postgres@localhost:5432/test
57
+ steps:
58
+ - uses: actions/checkout@v4
59
+ - uses: ruby/setup-ruby@v1
60
+ with:
61
+ bundler-cache: true
62
+ - run: bin/rails db:schema:load
63
+ - run: bundle exec rspec
64
+
65
+ code-quality:
66
+ name: Code Quality
67
+ runs-on: ubuntu-latest
68
+ steps:
69
+ - uses: actions/checkout@v4
70
+ - uses: ruby/setup-ruby@v1
71
+ with:
72
+ bundler-cache: true
73
+ - run: bundle exec reek app/ lib/
74
+ - run: bundle exec flog --all --group app/ lib/
75
+ - run: bundle exec flay app/ lib/
@@ -0,0 +1,2 @@
1
+ [tools]
2
+ ruby = "3.4.8"
@@ -0,0 +1,31 @@
1
+ ---
2
+ detectors:
3
+ IrresponsibleModule:
4
+ enabled: false
5
+ TooManyStatements:
6
+ max_statements: 10
7
+ TooManyInstanceVariables:
8
+ max_instance_variables: 6
9
+ TooManyMethods:
10
+ max_methods: 15
11
+ UtilityFunction:
12
+ public_methods_only: true
13
+ FeatureEnvy:
14
+ enabled: true
15
+ LongParameterList:
16
+ max_params: 4
17
+
18
+ directories:
19
+ 'app/controllers':
20
+ InstanceVariableAssumption:
21
+ enabled: false
22
+ TooManyInstanceVariables:
23
+ enabled: false
24
+ 'app/helpers':
25
+ UtilityFunction:
26
+ enabled: false
27
+ 'db/migrate':
28
+ IrresponsibleModule:
29
+ enabled: false
30
+ FeatureEnvy:
31
+ enabled: false
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,9 @@
1
+ # Project-specific RuboCop overrides.
2
+ # This file is NOT managed by Lisa — edit freely.
3
+ # Add or override any RuboCop cops below.
4
+
5
+ # Example:
6
+ # Metrics/MethodLength:
7
+ # Max: 25
8
+ # Exclude:
9
+ # - 'app/controllers/api/v1/**/*'
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ SimpleCov.start 'rails' do
4
+ enable_coverage :branch
5
+
6
+ minimum_coverage line: 80, branch: 70
7
+
8
+ add_group 'Models', 'app/models'
9
+ add_group 'Controllers', 'app/controllers'
10
+ add_group 'Services', 'app/services'
11
+ add_group 'Jobs', 'app/jobs'
12
+ add_group 'Mailers', 'app/mailers'
13
+ add_group 'Serializers', 'app/serializers'
14
+ add_group 'Libraries', 'lib'
15
+
16
+ add_filter '/spec/'
17
+ add_filter '/config/'
18
+ add_filter '/db/'
19
+ add_filter '/vendor/'
20
+ end
@@ -0,0 +1,15 @@
1
+ # SonarQube / SonarCloud configuration
2
+ # Update sonar.projectKey and sonar.organization for your project
3
+
4
+ sonar.projectKey=your-org_your-project
5
+ sonar.organization=your-org
6
+
7
+ sonar.sources=app,lib
8
+ sonar.tests=spec
9
+ sonar.exclusions=vendor/**/*,db/schema.rb,db/migrate/**/*,tmp/**/*,log/**/*,node_modules/**/*
10
+
11
+ sonar.ruby.coverage.reportPaths=coverage/.resultset.json
12
+ sonar.ruby.rubocop.reportPaths=rubocop-report.json
13
+
14
+ sonar.language=ruby
15
+ sonar.sourceEncoding=UTF-8
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ ENV['RAILS_ENV'] ||= 'test'
6
+
7
+ require_relative '../config/environment'
8
+
9
+ raise 'The Rails environment is running in production mode!' if Rails.env.production?
10
+
11
+ require 'rspec/rails'
12
+
13
+ begin
14
+ ActiveRecord::Migration.maintain_test_schema!
15
+ rescue ActiveRecord::PendingMigrationError => e
16
+ raise e.to_s.strip
17
+ end
18
+
19
+ RSpec.configure do |config|
20
+ config.fixture_paths = [Rails.root.join('spec/fixtures')]
21
+ config.use_transactional_fixtures = true
22
+ config.infer_spec_type_from_file_location!
23
+ config.filter_rails_from_backtrace!
24
+
25
+ config.include FactoryBot::Syntax::Methods
26
+ end
27
+
28
+ Shoulda::Matchers.configure do |config|
29
+ config.integrate do |with|
30
+ with.test_framework :rspec
31
+ with.library :rails
32
+ end
33
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'simplecov'
4
+
5
+ RSpec.configure do |config|
6
+ config.expect_with :rspec do |expectations|
7
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
8
+ end
9
+
10
+ config.mock_with :rspec do |mocks|
11
+ mocks.verify_partial_doubles = true
12
+ end
13
+
14
+ config.shared_context_metadata_behavior = :apply_to_host_groups
15
+ config.filter_run_when_matching :focus
16
+ config.example_status_persistence_file_path = 'spec/examples.txt'
17
+ config.disable_monkey_patching!
18
+ config.order = :random
19
+
20
+ Kernel.srand config.seed
21
+ end
@@ -0,0 +1,3 @@
1
+ {
2
+ "paths": [".overcommit.yml"]
3
+ }
@@ -27,6 +27,19 @@ GITLEAKS_VERSION="8.18.4"
27
27
  curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" | tar -xz -C /usr/local/bin gitleaks
28
28
  echo "Gitleaks installed: $(gitleaks version)"
29
29
 
30
+ # Install jira-cli for JIRA integration
31
+ # The tarball nests the binary at jira_VERSION_linux_x86_64/bin/jira,
32
+ # so we extract to a temp dir and copy the binary out.
33
+ echo "Installing jira-cli for JIRA integration..."
34
+ JIRA_CLI_VERSION="1.7.0"
35
+ JIRA_TMPDIR=$(mktemp -d)
36
+ curl -sSfL "https://github.com/ankitpokhrel/jira-cli/releases/download/v${JIRA_CLI_VERSION}/jira_${JIRA_CLI_VERSION}_linux_x86_64.tar.gz" \
37
+ | tar -xz -C "${JIRA_TMPDIR}"
38
+ cp "${JIRA_TMPDIR}/jira_${JIRA_CLI_VERSION}_linux_x86_64/bin/jira" /usr/local/bin/jira
39
+ chmod +x /usr/local/bin/jira
40
+ rm -rf "${JIRA_TMPDIR}"
41
+ echo "jira-cli installed: $(jira version)"
42
+
30
43
  # Install Chromium for Lighthouse CI (pre-push hook)
31
44
  # Playwright's bundled Chromium works with @lhci/cli
32
45
  echo "Installing Chromium for Lighthouse CI..."
@@ -43,6 +43,16 @@
43
43
  }
44
44
  ]
45
45
  },
46
+ {
47
+ "matcher": "",
48
+ "hooks": [
49
+ {
50
+ "type": "command",
51
+ "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/setup-jira-cli.sh",
52
+ "timeout": 5
53
+ }
54
+ ]
55
+ },
46
56
  {
47
57
  "matcher": "",
48
58
  "hooks": [