@shiva-fw/cli 1.0.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 (71) hide show
  1. package/.editorconfig +38 -0
  2. package/.gitattributes +18 -0
  3. package/.nvmrc +1 -0
  4. package/README.md +179 -0
  5. package/bin/shiva.js +4 -0
  6. package/package.json +44 -0
  7. package/recipes/full-rp.json +77 -0
  8. package/recipes/minimal.json +30 -0
  9. package/recipes/standard.json +46 -0
  10. package/src/commands/ai/context.js +89 -0
  11. package/src/commands/ai/link.js +38 -0
  12. package/src/commands/ai/mcp.js +39 -0
  13. package/src/commands/config/validate.js +65 -0
  14. package/src/commands/docs/api.js +81 -0
  15. package/src/commands/docs/build.js +14 -0
  16. package/src/commands/docs/deploy.js +14 -0
  17. package/src/commands/docs/serve.js +14 -0
  18. package/src/commands/init.js +167 -0
  19. package/src/commands/install.js +108 -0
  20. package/src/commands/locale/missing.js +83 -0
  21. package/src/commands/make/contract.js +45 -0
  22. package/src/commands/make/migration.js +69 -0
  23. package/src/commands/make/model.js +63 -0
  24. package/src/commands/make/module.js +115 -0
  25. package/src/commands/make/seed.js +51 -0
  26. package/src/commands/make/service.js +60 -0
  27. package/src/commands/make/test.js +53 -0
  28. package/src/commands/mcp.js +26 -0
  29. package/src/commands/migrate/rollback.js +155 -0
  30. package/src/commands/migrate/run.js +159 -0
  31. package/src/commands/migrate/status.js +137 -0
  32. package/src/commands/module/list.js +46 -0
  33. package/src/commands/module/status.js +64 -0
  34. package/src/commands/outdated.js +59 -0
  35. package/src/commands/remove.js +61 -0
  36. package/src/commands/seed.js +108 -0
  37. package/src/commands/test.js +88 -0
  38. package/src/commands/update.js +90 -0
  39. package/src/generators/index.js +78 -0
  40. package/src/generators/templates/contract.lua.tpl +12 -0
  41. package/src/generators/templates/migration.lua.tpl +15 -0
  42. package/src/generators/templates/model.lua.tpl +14 -0
  43. package/src/generators/templates/module/client/init.lua.tpl +5 -0
  44. package/src/generators/templates/module/config/config.lua.tpl +4 -0
  45. package/src/generators/templates/module/fxmanifest.lua.tpl +41 -0
  46. package/src/generators/templates/module/locales/en.lua.tpl +4 -0
  47. package/src/generators/templates/module/module.lua.tpl +10 -0
  48. package/src/generators/templates/module/server/init.lua.tpl +2 -0
  49. package/src/generators/templates/module/shared/init.lua.tpl +5 -0
  50. package/src/generators/templates/seed.lua.tpl +10 -0
  51. package/src/generators/templates/service.lua.tpl +7 -0
  52. package/src/generators/templates/test.lua.tpl +39 -0
  53. package/src/index.js +113 -0
  54. package/src/mcp/resources/contracts.js +68 -0
  55. package/src/mcp/resources/docs.js +56 -0
  56. package/src/mcp/resources/examples.js +235 -0
  57. package/src/mcp/server.js +121 -0
  58. package/src/mcp/tools/config.js +53 -0
  59. package/src/mcp/tools/contracts.js +37 -0
  60. package/src/mcp/tools/database.js +93 -0
  61. package/src/mcp/tools/docs.js +38 -0
  62. package/src/mcp/tools/events.js +26 -0
  63. package/src/mcp/tools/items.js +280 -0
  64. package/src/mcp/tools/modules.js +25 -0
  65. package/src/packages/lockfile.js +53 -0
  66. package/src/packages/registry.js +99 -0
  67. package/src/packages/resolver.js +83 -0
  68. package/src/utils/config-reader.js +74 -0
  69. package/src/utils/lua-annotations.js +319 -0
  70. package/src/utils/lua-parser.js +119 -0
  71. package/src/utils/server-root.js +66 -0
package/.editorconfig ADDED
@@ -0,0 +1,38 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ indent_size = 4
7
+ indent_style = space
8
+ insert_final_newline = true
9
+ trim_trailing_whitespace = true
10
+
11
+ [*.md]
12
+ trim_trailing_whitespace = false
13
+
14
+ [*.{yml,yaml}]
15
+ indent_size = 2
16
+
17
+ [*.{json,xml}]
18
+ indent_size = 2
19
+
20
+ [*.{js,ts,jsx,tsx}]
21
+ indent_size = 2
22
+
23
+ [*.{css,scss}]
24
+ indent_size = 2
25
+
26
+ [*.lua]
27
+ indent_size = 4
28
+
29
+ [*.lua.tpl]
30
+ indent_size = 4
31
+
32
+ [*.{sh,bash}]
33
+ indent_style = tab
34
+ indent_size = 4
35
+
36
+ [{Makefile,**.mk}]
37
+ indent_style = tab
38
+ indent_size = 4
package/.gitattributes ADDED
@@ -0,0 +1,18 @@
1
+ * text=auto eol=lf
2
+
3
+ *.css diff=css
4
+ *.html diff=html
5
+ *.md diff=markdown
6
+ *.lua diff=lua
7
+ *.tsx diff=typescriptreact
8
+ *.ts diff=typescript
9
+ *.yml diff=yaml
10
+ *.sh diff=bash
11
+ *.js diff=javascript
12
+ *.json diff=json
13
+
14
+ # Mark generated files
15
+ package-lock.json linguist-generated=true
16
+
17
+ /.github export-ignore
18
+ CHANGELOG.md export-ignore
package/.nvmrc ADDED
@@ -0,0 +1 @@
1
+ 24
package/README.md ADDED
@@ -0,0 +1,179 @@
1
+ # shiva-cli
2
+
3
+ > Developer CLI for the [Shiva](https://github.com/adrianmejias/shiva-core) FiveM framework — scaffolding, migrations, package management, AI integration, and an MCP server.
4
+
5
+ Think of it as Artisan for FiveM. Generate modules, run database migrations, manage packages with lockfile support, produce AI context files, and expose live framework data to AI tools via the Model Context Protocol.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install -g @shiva-fw/cli
11
+ # or run without installing
12
+ npx @shiva-fw/cli init
13
+ ```
14
+
15
+ After installing, the `shiva` command is available globally.
16
+
17
+ ## Quick Start
18
+
19
+ ```bash
20
+ # Initialise a new server project
21
+ shiva init
22
+
23
+ # Scaffold a module
24
+ shiva make:module fishing
25
+ shiva make:service FishingService --module shiva-fishing
26
+ shiva make:model Fish --module shiva-fishing
27
+ shiva make:migration create_fish_table --module shiva-fishing
28
+
29
+ # Run migrations
30
+ shiva migrate
31
+
32
+ # Start the MCP server (for Claude Code, Cursor, etc.)
33
+ shiva mcp start
34
+ ```
35
+
36
+ ## Commands
37
+
38
+ ### Scaffolding
39
+ ```bash
40
+ shiva init # Interactive setup
41
+ shiva init --recipe full-rp # Use a preset recipe (minimal | standard | full-rp)
42
+
43
+ shiva make:module <name> # Scaffold a new module
44
+ shiva make:service <name> --module <module> # Add a service
45
+ shiva make:model <name> --module <module> # Add a model
46
+ shiva make:migration <name> --module <module> # Add a migration
47
+ shiva make:seed <name> --module <module> # Add a seeder
48
+ shiva make:test <name> --module <module> # Add a test spec
49
+ shiva make:contract <name> # Add a shared contract
50
+ ```
51
+
52
+ ### Database
53
+ ```bash
54
+ shiva migrate # Run all pending migrations
55
+ shiva migrate:rollback # Roll back the last batch
56
+ shiva migrate:rollback --steps=3 # Roll back 3 batches
57
+ shiva migrate:status # Show migration status table
58
+ shiva seed # Run all seeders
59
+ shiva seed --module shiva-economy # Seed a specific module
60
+ ```
61
+
62
+ ### Modules
63
+ ```bash
64
+ shiva module:list # List all installed modules with status
65
+ shiva module:status # Detailed view (version, deps, health)
66
+ ```
67
+
68
+ ### Packages
69
+ ```bash
70
+ shiva install shiva-fishing # Install from registry
71
+ shiva install shiva-fishing@1.2.0 # Install a specific version
72
+ shiva update # Update all modules
73
+ shiva update shiva-economy # Update one module
74
+ shiva outdated # Show available updates
75
+ shiva remove shiva-fishing # Remove a module
76
+ ```
77
+
78
+ ### Testing
79
+ ```bash
80
+ shiva test # Run all module test suites
81
+ shiva test --module shiva-economy # Test a specific module
82
+ shiva test --filter "transfer" # Filter by test name
83
+ ```
84
+
85
+ ### Config & Locale
86
+ ```bash
87
+ shiva config:validate # Validate all module configs
88
+ shiva locale:missing # Find missing translation keys
89
+ ```
90
+
91
+ ### AI Integration
92
+ ```bash
93
+ shiva ai:context # Generate AGENTS.md from installed modules
94
+ shiva ai:context --module economy # For a specific module
95
+ shiva ai:link # Create CLAUDE.md and GEMINI.md symlinks
96
+ shiva ai:mcp # Generate .mcp.json for AI tool connections
97
+ shiva mcp start # Start the MCP server (stdio)
98
+ ```
99
+
100
+ ### Documentation
101
+ ```bash
102
+ shiva docs:api # Generate API reference from LuaLS annotations
103
+ shiva docs:build # Build docs site (delegates to shiva-docs)
104
+ shiva docs:serve # Local dev server (delegates to shiva-docs)
105
+ shiva docs:deploy # Deploy docs (delegates to shiva-docs)
106
+ ```
107
+
108
+ ## Package Management
109
+
110
+ Projects use `shiva.json` (like `package.json`) and `shiva.lock`:
111
+
112
+ ```json
113
+ {
114
+ "name": "my-rp-server",
115
+ "framework": "shiva-core@1.0.0",
116
+ "modules": {
117
+ "shiva-player": "^1.0.0",
118
+ "shiva-economy": "^1.0.0",
119
+ "shiva-police": "^1.0.0",
120
+ "my-fishing": "file:./custom-modules/fishing"
121
+ },
122
+ "database": {
123
+ "host": "127.0.0.1",
124
+ "user": "root",
125
+ "password": "",
126
+ "database": "shiva"
127
+ }
128
+ }
129
+ ```
130
+
131
+ Version constraints follow semver: `^1.0.0` (compatible), `~1.0.0` (patch only), `1.0.0` (exact), `>=1.0.0 <2.0.0` (range).
132
+
133
+ ## MCP Server
134
+
135
+ The MCP server exposes live framework context to AI assistants (Claude Code, Cursor, Windsurf, etc.):
136
+
137
+ ```bash
138
+ shiva mcp start
139
+ # Listening on stdio — add to your editor's MCP config
140
+ ```
141
+
142
+ | Tool | Description |
143
+ |------|-------------|
144
+ | `shiva:getContractMethods` | Methods, args, and return types for a contract |
145
+ | `shiva:getModuleConfig` | Config schema with defaults and current values |
146
+ | `shiva:getRegisteredEvents` | All events across modules with payload shapes |
147
+ | `shiva:getInstalledModules` | Installed modules, versions, dependency tree |
148
+ | `shiva:getServiceMethods` | Service methods including extensions |
149
+ | `shiva:getDatabaseSchema` | All tables, columns, and types |
150
+ | `shiva:getMigrationStatus` | Which migrations have run |
151
+ | `shiva:getAvailableCommands` | Registered commands with args and permissions |
152
+ | `shiva:getItemDefinitions` | All registered inventory items |
153
+ | `shiva:getJobDefinitions` | All jobs, grades, and salaries |
154
+ | `shiva:searchDocs` | Full-text search across framework docs |
155
+
156
+ ## Requirements
157
+
158
+ - Node.js 18+
159
+ - Lua 5.4 (for `shiva test`)
160
+ - MySQL/MariaDB (for migration commands)
161
+
162
+ ## Related Repositories
163
+
164
+ | Repo | Purpose |
165
+ |------|---------|
166
+ | [shiva-core](https://github.com/adrianmejias/shiva-core) | FiveM framework engine |
167
+ | [shiva-fw](https://github.com/adrianmejias/shiva-fw) | Shared Lua foundation |
168
+ | [shiva-modules](https://github.com/adrianmejias/shiva-modules) | 71 default RP modules |
169
+ | [shiva-test](https://github.com/adrianmejias/shiva-test) | Lua testing framework |
170
+ | [shiva-api](https://github.com/adrianmejias/shiva-api) | External REST API server |
171
+ | [shiva-docs](https://github.com/adrianmejias/shiva-docs) | Documentation site |
172
+ | [shiva-panel](https://github.com/adrianmejias/shiva-panel) | Admin panel |
173
+ | [shiva](https://github.com/adrianmejias/shiva) | FiveM Docker boilerplate |
174
+ | [shiva-boot](https://github.com/adrianmejias/shiva-boot) | Server boot scripts |
175
+ | [shiva-db](https://github.com/adrianmejias/shiva-db) | Database utilities |
176
+
177
+ ## License
178
+
179
+ MIT
package/bin/shiva.js ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ require('../src/index');
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@shiva-fw/cli",
3
+ "version": "1.0.0",
4
+ "description": "Developer CLI for the Shiva FiveM framework",
5
+ "main": "src/index.js",
6
+ "bin": {
7
+ "shiva": "bin/shiva.js"
8
+ },
9
+ "scripts": {
10
+ "test": "jest",
11
+ "lint": "eslint src/**/*.js bin/**/*.js"
12
+ },
13
+ "keywords": [
14
+ "fivem",
15
+ "shiva",
16
+ "cli",
17
+ "framework"
18
+ ],
19
+ "author": "Adrian Mejias",
20
+ "license": "MIT",
21
+ "type": "commonjs",
22
+ "engines": {
23
+ "node": ">=18.0.0"
24
+ },
25
+ "dependencies": {
26
+ "@modelcontextprotocol/sdk": "^1.29.0",
27
+ "chalk": "^4.1.2",
28
+ "commander": "^12.1.0",
29
+ "glob": "^8.1.0",
30
+ "inquirer": "^8.2.6",
31
+ "mysql2": "^3.9.7",
32
+ "semver": "^7.6.2"
33
+ },
34
+ "devDependencies": {
35
+ "eslint": "^8.57.1",
36
+ "jest": "^29.7.0"
37
+ },
38
+ "jest": {
39
+ "testMatch": [
40
+ "**/tests/**/*.test.js"
41
+ ],
42
+ "testEnvironment": "node"
43
+ }
44
+ }
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "full-rp",
3
+ "description": "Full RP experience — 71 modules",
4
+ "modules": {
5
+ "shiva-player": "^1.0.0",
6
+ "shiva-identity": "^1.0.0",
7
+ "shiva-jobs": "^1.0.0",
8
+ "shiva-economy": "^1.0.0",
9
+ "shiva-inventory": "^1.0.0",
10
+ "shiva-vehicles": "^1.0.0",
11
+ "shiva-housing": "^1.0.0",
12
+ "shiva-phone": "^1.0.0",
13
+ "shiva-hud": "^1.0.0",
14
+ "shiva-map": "^1.0.0",
15
+ "shiva-chat": "^1.0.0",
16
+ "shiva-permissions": "^1.0.0",
17
+ "shiva-admin": "^1.0.0",
18
+ "shiva-ban": "^1.0.0",
19
+ "shiva-logs": "^1.0.0",
20
+ "shiva-spawn": "^1.0.0",
21
+ "shiva-death": "^1.0.0",
22
+ "shiva-hunger": "^1.0.0",
23
+ "shiva-shops": "^1.0.0",
24
+ "shiva-garage": "^1.0.0",
25
+ "shiva-fuel": "^1.0.0",
26
+ "shiva-atm": "^1.0.0",
27
+ "shiva-crafting": "^1.0.0",
28
+ "shiva-notifications": "^1.0.0",
29
+ "shiva-police": "^1.0.0",
30
+ "shiva-ems": "^1.0.0",
31
+ "shiva-mechanic": "^1.0.0",
32
+ "shiva-trucker": "^1.0.0",
33
+ "shiva-taxi": "^1.0.0",
34
+ "shiva-restaurant": "^1.0.0",
35
+ "shiva-drugs": "^1.0.0",
36
+ "shiva-robbery": "^1.0.0",
37
+ "shiva-casino": "^1.0.0",
38
+ "shiva-racing": "^1.0.0",
39
+ "shiva-fishing": "^1.0.0",
40
+ "shiva-hunting": "^1.0.0",
41
+ "shiva-farming": "^1.0.0",
42
+ "shiva-realtor": "^1.0.0",
43
+ "shiva-tattoo": "^1.0.0",
44
+ "shiva-barbershop": "^1.0.0",
45
+ "shiva-cardealer": "^1.0.0",
46
+ "shiva-weapons": "^1.0.0",
47
+ "shiva-ammo": "^1.0.0",
48
+ "shiva-shooting-range": "^1.0.0",
49
+ "shiva-prison": "^1.0.0",
50
+ "shiva-court": "^1.0.0",
51
+ "shiva-lawyer": "^1.0.0",
52
+ "shiva-judge": "^1.0.0",
53
+ "shiva-bank": "^1.0.0",
54
+ "shiva-loan": "^1.0.0",
55
+ "shiva-insurance": "^1.0.0",
56
+ "shiva-business": "^1.0.0",
57
+ "shiva-billboard": "^1.0.0",
58
+ "shiva-news": "^1.0.0",
59
+ "shiva-radio": "^1.0.0",
60
+ "shiva-mayor": "^1.0.0",
61
+ "shiva-election": "^1.0.0",
62
+ "shiva-gang": "^1.0.0",
63
+ "shiva-turf": "^1.0.0",
64
+ "shiva-black-market": "^1.0.0",
65
+ "shiva-carjack": "^1.0.0",
66
+ "shiva-heist": "^1.0.0",
67
+ "shiva-kidnap": "^1.0.0",
68
+ "shiva-hitman": "^1.0.0",
69
+ "shiva-taxi-dispatch": "^1.0.0",
70
+ "shiva-ambulance-dispatch": "^1.0.0",
71
+ "shiva-police-dispatch": "^1.0.0",
72
+ "shiva-towing": "^1.0.0",
73
+ "shiva-impound": "^1.0.0",
74
+ "shiva-evidence": "^1.0.0",
75
+ "shiva-forensics": "^1.0.0"
76
+ }
77
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "minimal",
3
+ "description": "Essential modules for a minimal FiveM server — 24 modules",
4
+ "modules": {
5
+ "shiva-player": "^1.0.0",
6
+ "shiva-identity": "^1.0.0",
7
+ "shiva-jobs": "^1.0.0",
8
+ "shiva-economy": "^1.0.0",
9
+ "shiva-inventory": "^1.0.0",
10
+ "shiva-vehicles": "^1.0.0",
11
+ "shiva-housing": "^1.0.0",
12
+ "shiva-phone": "^1.0.0",
13
+ "shiva-hud": "^1.0.0",
14
+ "shiva-map": "^1.0.0",
15
+ "shiva-chat": "^1.0.0",
16
+ "shiva-permissions": "^1.0.0",
17
+ "shiva-admin": "^1.0.0",
18
+ "shiva-ban": "^1.0.0",
19
+ "shiva-logs": "^1.0.0",
20
+ "shiva-spawn": "^1.0.0",
21
+ "shiva-death": "^1.0.0",
22
+ "shiva-hunger": "^1.0.0",
23
+ "shiva-shops": "^1.0.0",
24
+ "shiva-garage": "^1.0.0",
25
+ "shiva-fuel": "^1.0.0",
26
+ "shiva-atm": "^1.0.0",
27
+ "shiva-crafting": "^1.0.0",
28
+ "shiva-notifications": "^1.0.0"
29
+ }
30
+ }
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "standard",
3
+ "description": "Standard RP server — 40 modules (recommended starting point)",
4
+ "modules": {
5
+ "shiva-player": "^1.0.0",
6
+ "shiva-identity": "^1.0.0",
7
+ "shiva-jobs": "^1.0.0",
8
+ "shiva-economy": "^1.0.0",
9
+ "shiva-inventory": "^1.0.0",
10
+ "shiva-vehicles": "^1.0.0",
11
+ "shiva-housing": "^1.0.0",
12
+ "shiva-phone": "^1.0.0",
13
+ "shiva-hud": "^1.0.0",
14
+ "shiva-map": "^1.0.0",
15
+ "shiva-chat": "^1.0.0",
16
+ "shiva-permissions": "^1.0.0",
17
+ "shiva-admin": "^1.0.0",
18
+ "shiva-ban": "^1.0.0",
19
+ "shiva-logs": "^1.0.0",
20
+ "shiva-spawn": "^1.0.0",
21
+ "shiva-death": "^1.0.0",
22
+ "shiva-hunger": "^1.0.0",
23
+ "shiva-shops": "^1.0.0",
24
+ "shiva-garage": "^1.0.0",
25
+ "shiva-fuel": "^1.0.0",
26
+ "shiva-atm": "^1.0.0",
27
+ "shiva-crafting": "^1.0.0",
28
+ "shiva-notifications": "^1.0.0",
29
+ "shiva-police": "^1.0.0",
30
+ "shiva-ems": "^1.0.0",
31
+ "shiva-mechanic": "^1.0.0",
32
+ "shiva-trucker": "^1.0.0",
33
+ "shiva-taxi": "^1.0.0",
34
+ "shiva-restaurant": "^1.0.0",
35
+ "shiva-drugs": "^1.0.0",
36
+ "shiva-robbery": "^1.0.0",
37
+ "shiva-casino": "^1.0.0",
38
+ "shiva-racing": "^1.0.0",
39
+ "shiva-fishing": "^1.0.0",
40
+ "shiva-hunting": "^1.0.0",
41
+ "shiva-farming": "^1.0.0",
42
+ "shiva-realtor": "^1.0.0",
43
+ "shiva-tattoo": "^1.0.0",
44
+ "shiva-barbershop": "^1.0.0"
45
+ }
46
+ }
@@ -0,0 +1,89 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const fs = require('fs');
5
+ const chalk = require('chalk');
6
+
7
+ const { requireServerRoot, getResourcesDir } = require('../../utils/server-root');
8
+ const { scanModules } = require('../../utils/lua-parser');
9
+ const { normalizeModuleName } = require('../../generators/index');
10
+
11
+ function aiContextCommand(program) {
12
+ program
13
+ .command('ai:context')
14
+ .description('Generate AGENTS.md from installed modules')
15
+ .option('-m, --module <module>', 'Generate context for a specific module only')
16
+ .option('-o, --output <path>', 'Output file path', 'AGENTS.md')
17
+ .action((options) => { run(options); });
18
+ }
19
+
20
+ function run(options) {
21
+ const serverRoot = requireServerRoot();
22
+ const resourcesDir = getResourcesDir(serverRoot);
23
+ let modules = scanModules(resourcesDir);
24
+
25
+ if (options.module) {
26
+ const name = normalizeModuleName(options.module);
27
+ modules = modules.filter(m => m.name === name);
28
+ if (modules.length === 0) {
29
+ console.error(chalk.red(`✖ Module not found: ${name}`));
30
+ process.exit(1);
31
+ }
32
+ }
33
+
34
+ const lines = [];
35
+ lines.push('# Shiva Server — AI Agent Context');
36
+ lines.push('');
37
+ lines.push('> Auto-generated by `shiva ai:context`. Do not edit manually.');
38
+ lines.push('');
39
+ lines.push(`Generated: ${new Date().toISOString()}`);
40
+ lines.push('');
41
+ lines.push('## Installed Modules');
42
+ lines.push('');
43
+ lines.push(`${modules.length} module(s) installed.`);
44
+ lines.push('');
45
+
46
+ for (const mod of modules) {
47
+ const m = mod.manifest;
48
+ lines.push(`### ${mod.name}`);
49
+ lines.push('');
50
+ if (m.description) lines.push(m.description);
51
+ lines.push('');
52
+ lines.push(`- **Version**: ${m.version || '?'}`);
53
+ if ((m.dependencies || []).length > 0) {
54
+ lines.push(`- **Dependencies**: ${m.dependencies.join(', ')}`);
55
+ }
56
+ if ((m.provides || []).length > 0) {
57
+ lines.push(`- **Provides**: ${m.provides.join(', ')}`);
58
+ }
59
+ if ((m.events || []).length > 0) {
60
+ lines.push('- **Events**:');
61
+ m.events.forEach(e => lines.push(` - \`${e}\``));
62
+ }
63
+ if ((m.migrations || []).length > 0) {
64
+ lines.push(`- **Migrations**: ${m.migrations.length}`);
65
+ }
66
+ lines.push('');
67
+ }
68
+
69
+ const contractsDir = path.join(serverRoot, 'shared', 'contracts');
70
+ if (fs.existsSync(contractsDir)) {
71
+ const contracts = fs.readdirSync(contractsDir).filter(f => f.endsWith('.lua'));
72
+ if (contracts.length > 0) {
73
+ lines.push('## Contracts');
74
+ lines.push('');
75
+ contracts.forEach(f => lines.push(`- \`${f.replace('.lua', '')}\``));
76
+ lines.push('');
77
+ }
78
+ }
79
+
80
+ const outPath = path.resolve(serverRoot, options.output);
81
+ fs.writeFileSync(outPath, lines.join('\n'), 'utf-8');
82
+
83
+ console.log('');
84
+ console.log(chalk.green(`✔ Generated ${path.relative(process.cwd(), outPath)}`));
85
+ console.log(chalk.gray(` ${modules.length} modules documented.`));
86
+ console.log('');
87
+ }
88
+
89
+ module.exports = aiContextCommand;
@@ -0,0 +1,38 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const fs = require('fs');
5
+ const chalk = require('chalk');
6
+ const { requireServerRoot } = require('../../utils/server-root');
7
+
8
+ function aiLinkCommand(program) {
9
+ program
10
+ .command('ai:link')
11
+ .description('Create CLAUDE.md and GEMINI.md symlinks pointing at AGENTS.md')
12
+ .action(() => { run(); });
13
+ }
14
+
15
+ function run() {
16
+ const serverRoot = requireServerRoot();
17
+ const agentsFile = path.join(serverRoot, 'AGENTS.md');
18
+ const targets = ['CLAUDE.md', 'GEMINI.md'];
19
+
20
+ if (!fs.existsSync(agentsFile)) {
21
+ console.error(chalk.red('✖ AGENTS.md not found. Run `shiva ai:context` first.'));
22
+ process.exit(1);
23
+ }
24
+
25
+ console.log('');
26
+ for (const target of targets) {
27
+ const linkPath = path.join(serverRoot, target);
28
+ try {
29
+ const stat = fs.lstatSync(linkPath);
30
+ if (stat) fs.unlinkSync(linkPath);
31
+ } catch {}
32
+ fs.symlinkSync('AGENTS.md', linkPath);
33
+ console.log(chalk.green(`✔ ${target} → AGENTS.md`));
34
+ }
35
+ console.log('');
36
+ }
37
+
38
+ module.exports = aiLinkCommand;
@@ -0,0 +1,39 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const fs = require('fs');
5
+ const chalk = require('chalk');
6
+ const { requireServerRoot } = require('../../utils/server-root');
7
+ const { readShivaConfig } = require('../../utils/config-reader');
8
+
9
+ function aiMcpCommand(program) {
10
+ program
11
+ .command('ai:mcp')
12
+ .description('Generate .mcp.json for AI tool integrations')
13
+ .option('-p, --port <port>', 'MCP server port', '3100')
14
+ .action((options) => { run(options); });
15
+ }
16
+
17
+ function run(options) {
18
+ const serverRoot = requireServerRoot();
19
+ const mcpJson = {
20
+ mcpServers: {
21
+ shiva: {
22
+ command: 'shiva',
23
+ args: ['mcp', 'start'],
24
+ env: {},
25
+ },
26
+ },
27
+ };
28
+
29
+ const outPath = path.join(serverRoot, '.mcp.json');
30
+ fs.writeFileSync(outPath, JSON.stringify(mcpJson, null, 2) + '\n', 'utf-8');
31
+
32
+ console.log('');
33
+ console.log(chalk.green('✔ Created .mcp.json'));
34
+ console.log(chalk.gray(' Add this to your Claude Code / Cursor / Windsurf MCP config.'));
35
+ console.log(chalk.gray(' Start the server with: shiva mcp start'));
36
+ console.log('');
37
+ }
38
+
39
+ module.exports = aiMcpCommand;
@@ -0,0 +1,65 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const fs = require('fs');
5
+ const chalk = require('chalk');
6
+
7
+ const { requireServerRoot, getResourcesDir } = require('../../utils/server-root');
8
+ const { scanModules } = require('../../utils/lua-parser');
9
+
10
+ function configValidateCommand(program) {
11
+ program
12
+ .command('config:validate')
13
+ .description('Validate module configuration files')
14
+ .action(() => { run(); });
15
+ }
16
+
17
+ function run() {
18
+ const serverRoot = requireServerRoot();
19
+ const resourcesDir = getResourcesDir(serverRoot);
20
+ const modules = scanModules(resourcesDir);
21
+
22
+ let passed = 0;
23
+ let warned = 0;
24
+ let failed = 0;
25
+
26
+ console.log('');
27
+ console.log(chalk.bold('Config Validation'));
28
+ console.log(chalk.gray('─'.repeat(60)));
29
+
30
+ for (const mod of modules) {
31
+ const configFile = path.join(mod.path, 'config', 'config.lua');
32
+
33
+ if (!fs.existsSync(configFile)) {
34
+ console.log(chalk.yellow(` ⚠ ${mod.name.padEnd(28)} no config/config.lua`));
35
+ warned++;
36
+ continue;
37
+ }
38
+
39
+ const content = fs.readFileSync(configFile, 'utf-8');
40
+
41
+ if (!content.includes('Config.register(')) {
42
+ console.log(chalk.yellow(` ⚠ ${mod.name.padEnd(28)} Config.register() not found`));
43
+ warned++;
44
+ continue;
45
+ }
46
+
47
+ const hasPlaceholder = /--\s*TODO/.test(content) && !/Config\.register\([^)]+,\s*\{[^}]+\}/.test(content);
48
+ if (hasPlaceholder) {
49
+ console.log(chalk.yellow(` ⚠ ${mod.name.padEnd(28)} config appears to be a stub`));
50
+ warned++;
51
+ continue;
52
+ }
53
+
54
+ console.log(chalk.green(` ✔ ${mod.name}`));
55
+ passed++;
56
+ }
57
+
58
+ console.log(chalk.gray('─'.repeat(60)));
59
+ console.log(` ${chalk.green(passed + ' passed')} · ${chalk.yellow(warned + ' warnings')} · ${chalk.red(failed + ' failed')}`);
60
+ console.log('');
61
+
62
+ if (failed > 0) process.exit(1);
63
+ }
64
+
65
+ module.exports = configValidateCommand;