@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.
- package/all/copy-overwrite/.claude/hooks/setup-jira-cli.sh +52 -0
- package/all/copy-overwrite/.claude/settings.json +12 -0
- 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/expo/copy-overwrite/.mcp.json +0 -8
- package/package.json +2 -1
- package/rails/copy-contents/Gemfile +3 -0
- package/rails/copy-overwrite/.claude/rules/lisa.md +40 -0
- package/rails/copy-overwrite/.claude/rules/rails-conventions.md +176 -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/CLAUDE.md +55 -0
- package/rails/copy-overwrite/Gemfile.lisa +52 -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 +75 -0
- package/rails/create-only/.mise.toml +2 -0
- package/rails/create-only/.reek.yml +31 -0
- package/rails/create-only/.rspec +3 -0
- package/rails/create-only/.rubocop.local.yml +9 -0
- package/rails/create-only/.simplecov +20 -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
- package/typescript/copy-overwrite/.claude/hooks/install_pkgs.sh +13 -0
- 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)
|
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"}
|
|
@@ -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.
|
|
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,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,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,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,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
|
|
@@ -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..."
|