aicoding-rules 0.1.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/README.md ADDED
@@ -0,0 +1,95 @@
1
+ # aicoding-rules
2
+
3
+ A CLI tool to download and install AI coding rules for various AI assistants.
4
+
5
+ ## Supported Tools
6
+
7
+ - **Cursor** - IDE-specific rules for Cursor editor
8
+ - **Claude** - Rules for Claude AI assistant
9
+ - **Antigravity** - Antigravity platform rules
10
+ - **Copilot** - GitHub Copilot prompts
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npm install -g aicoding-rules
16
+ ```
17
+
18
+ Or run directly with npx:
19
+
20
+ ```bash
21
+ npx aicoding-rules
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ### Interactive Mode
27
+
28
+ Run without arguments to select rules interactively:
29
+
30
+ ```bash
31
+ npx aicoding-rules
32
+ ```
33
+
34
+ You'll see a checkbox menu:
35
+
36
+ ```
37
+ ? Select rules to install: (Press <space> to select, <a> to toggle all)
38
+ ◯ Cursor rules
39
+ ◯ Claude rules
40
+ ◯ Antigravity rules
41
+ ◯ Copilot prompts
42
+ ```
43
+
44
+ ### Direct Commands
45
+
46
+ Install specific rules directly:
47
+
48
+ ```bash
49
+ npx aicoding-rules cursor
50
+ npx aicoding-rules claude
51
+ npx aicoding-rules antigravity
52
+ npx aicoding-rules copilot
53
+ ```
54
+
55
+ Install all rules at once:
56
+
57
+ ```bash
58
+ npx aicoding-rules all
59
+ ```
60
+
61
+ ## Authentication
62
+
63
+ The tool uses Plus4U OIDC authentication. On first run, a browser window will open for you to log in. The authentication token is cached for the session.
64
+
65
+ ## Configuration
66
+
67
+ Create `~/.aicoding-rules.json` to override default settings:
68
+
69
+ ```json
70
+ {
71
+ "documentOid": "your-document-oid",
72
+ "baseUrl": "https://your-custom-url.com",
73
+ "rules": {
74
+ "cursor": {
75
+ "fileOid": "custom-file-oid",
76
+ "name": "Custom Cursor Rules"
77
+ },
78
+ "custom-tool": {
79
+ "fileOid": "another-file-oid",
80
+ "name": "My Custom Tool"
81
+ }
82
+ }
83
+ }
84
+ ```
85
+
86
+ Custom rules defined in the config file will appear in the interactive menu.
87
+
88
+ ## Output
89
+
90
+ Rules are extracted to the current working directory. Run the command from the root of your project.
91
+
92
+ ## Requirements
93
+
94
+ - Node.js >= 18.0.0
95
+ - Plus4U account with access to the rules repository
package/bin/cli.js ADDED
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from "commander";
4
+ import { loadConfig, getRuleKeys } from "../src/config.js";
5
+ import { downloadAndExtract, downloadMultiple } from "../src/download.js";
6
+ import { selectRules } from "../src/interactive.js";
7
+
8
+ const config = loadConfig();
9
+ const targetDir = process.cwd();
10
+
11
+ const program = new Command();
12
+
13
+ program
14
+ .name("aicoding-rules")
15
+ .description("Download and install AI coding rules for Cursor, Claude, Antigravity, and Copilot")
16
+ .version("1.0.0");
17
+
18
+ program
19
+ .command("cursor")
20
+ .description("Install Cursor rules")
21
+ .action(async () => {
22
+ await downloadAndExtract(config, "cursor", targetDir);
23
+ });
24
+
25
+ program
26
+ .command("claude")
27
+ .description("Install Claude rules")
28
+ .action(async () => {
29
+ await downloadAndExtract(config, "claude", targetDir);
30
+ });
31
+
32
+ program
33
+ .command("antigravity")
34
+ .description("Install Antigravity rules")
35
+ .action(async () => {
36
+ await downloadAndExtract(config, "antigravity", targetDir);
37
+ });
38
+
39
+ program
40
+ .command("copilot")
41
+ .description("Install Copilot prompts")
42
+ .action(async () => {
43
+ await downloadAndExtract(config, "copilot", targetDir);
44
+ });
45
+
46
+ program
47
+ .command("all")
48
+ .description("Install all rules")
49
+ .action(async () => {
50
+ const allKeys = getRuleKeys(config);
51
+ await downloadMultiple(config, allKeys, targetDir);
52
+ });
53
+
54
+ program
55
+ .action(async () => {
56
+ const selectedKeys = await selectRules(config);
57
+ await downloadMultiple(config, selectedKeys, targetDir);
58
+ });
59
+
60
+ program.parse();
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "aicoding-rules",
3
+ "version": "0.1.0",
4
+ "description": "Download and install AI coding rules for Cursor, Claude, Antigravity, and Copilot",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "src/index.js",
8
+ "bin": {
9
+ "aicoding-rules": "bin/cli.js"
10
+ },
11
+ "files": [
12
+ "bin",
13
+ "src"
14
+ ],
15
+ "engines": {
16
+ "node": ">=18.0.0"
17
+ },
18
+ "dependencies": {
19
+ "uu_appg01_devkit-common": "^6.5.0",
20
+ "adm-zip": "^0.5.16",
21
+ "commander": "^12.0.0",
22
+ "inquirer": "^9.0.0"
23
+ }
24
+ }
package/src/auth.js ADDED
@@ -0,0 +1,26 @@
1
+ import { createRequire } from "module";
2
+
3
+ const require = createRequire(import.meta.url);
4
+ const OidcClient = require("uu_appg01_devkit-common/src/scripts/oidc-client");
5
+ const AppClient = require("uu_appg01_devkit-common/src/scripts/misc/app-client");
6
+
7
+ let cachedAppClient = null;
8
+
9
+ export async function getAuthenticatedClient() {
10
+ if (cachedAppClient) {
11
+ return cachedAppClient;
12
+ }
13
+
14
+ console.log("Starting Plus4U authentication...");
15
+
16
+ const token = await OidcClient.interactiveLogin();
17
+
18
+ if (!token) {
19
+ throw new Error("Authentication failed - no token received");
20
+ }
21
+
22
+ cachedAppClient = new AppClient({ get: () => `Bearer ${token}` });
23
+ console.log("Authentication successful!\n");
24
+
25
+ return cachedAppClient;
26
+ }
package/src/config.js ADDED
@@ -0,0 +1,52 @@
1
+ import { readFileSync, existsSync } from "fs";
2
+ import { homedir } from "os";
3
+ import { join } from "path";
4
+
5
+ const CONFIG_FILE = ".aicoding-rules.json";
6
+
7
+ const DEFAULT_CONFIG = {
8
+ documentOid: "67eab558899a1711f6cbf55f",
9
+ baseUrl: "https://uuapp.plus4u.net/uu-managementkit-maing02/9d3f27636f2e439f98529b1e12231924",
10
+ rules: {
11
+ cursor: { fileOid: "67eab7b2899a1711f6cc1580", name: "Cursor rules" },
12
+ claude: { fileOid: "68872b563e3eb464f2214263", name: "Claude rules" },
13
+ antigravity: { fileOid: "69202dcfacf31067955cfc1c", name: "Antigravity rules" },
14
+ copilot: { fileOid: "67eab73e899a1711f6cc106f", name: "Copilot prompts" }
15
+ }
16
+ };
17
+
18
+ function deepMerge(target, source) {
19
+ const result = { ...target };
20
+ for (const key of Object.keys(source)) {
21
+ if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key])) {
22
+ result[key] = deepMerge(target[key] || {}, source[key]);
23
+ } else {
24
+ result[key] = source[key];
25
+ }
26
+ }
27
+ return result;
28
+ }
29
+
30
+ export function loadConfig() {
31
+ const configPath = join(homedir(), CONFIG_FILE);
32
+
33
+ if (!existsSync(configPath)) {
34
+ return DEFAULT_CONFIG;
35
+ }
36
+
37
+ try {
38
+ const userConfig = JSON.parse(readFileSync(configPath, "utf-8"));
39
+ return deepMerge(DEFAULT_CONFIG, userConfig);
40
+ } catch (error) {
41
+ console.warn(`Warning: Failed to parse ${configPath}, using defaults.`);
42
+ return DEFAULT_CONFIG;
43
+ }
44
+ }
45
+
46
+ export function getRuleKeys(config) {
47
+ return Object.keys(config.rules);
48
+ }
49
+
50
+ export function getRule(config, key) {
51
+ return config.rules[key];
52
+ }
@@ -0,0 +1,40 @@
1
+ import AdmZip from "adm-zip";
2
+ import { getAuthenticatedClient } from "./auth.js";
3
+
4
+ function extractZipBuffer(buffer, outputPath) {
5
+ const zip = new AdmZip(buffer);
6
+ zip.extractAllTo(outputPath, true);
7
+ }
8
+
9
+ export async function downloadAndExtract(config, ruleKey, targetDir) {
10
+ const rule = config.rules[ruleKey];
11
+ if (!rule) {
12
+ throw new Error(`Unknown rule: ${ruleKey}`);
13
+ }
14
+
15
+ const appClient = await getAuthenticatedClient();
16
+
17
+ const url = `${config.baseUrl}/document/ebc/file/getDataByOid?oid=${config.documentOid}&uuEbcData.fileOid=${rule.fileOid}`;
18
+
19
+ console.log(`Downloading ${rule.name}...`);
20
+
21
+ const response = await appClient.exchange(
22
+ url,
23
+ "get",
24
+ {},
25
+ {},
26
+ 0,
27
+ { responseType: "buffer" }
28
+ );
29
+
30
+ const attachmentBuffer = response.body;
31
+ extractZipBuffer(attachmentBuffer, targetDir);
32
+
33
+ console.log(`${rule.name} installed to ${targetDir}`);
34
+ }
35
+
36
+ export async function downloadMultiple(config, ruleKeys, targetDir) {
37
+ for (const key of ruleKeys) {
38
+ await downloadAndExtract(config, key, targetDir);
39
+ }
40
+ }
@@ -0,0 +1,28 @@
1
+ import inquirer from "inquirer";
2
+ import { getRuleKeys, getRule } from "./config.js";
3
+
4
+ export async function selectRules(config) {
5
+ const ruleKeys = getRuleKeys(config);
6
+
7
+ const choices = ruleKeys.map(key => ({
8
+ name: getRule(config, key).name,
9
+ value: key
10
+ }));
11
+
12
+ const { selectedRules } = await inquirer.prompt([
13
+ {
14
+ type: "checkbox",
15
+ name: "selectedRules",
16
+ message: "Select rules to install:",
17
+ choices,
18
+ validate: (answer) => {
19
+ if (answer.length === 0) {
20
+ return "You must select at least one rule.";
21
+ }
22
+ return true;
23
+ }
24
+ }
25
+ ]);
26
+
27
+ return selectedRules;
28
+ }