@autofictional/cli 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,56 @@
1
+ # @autofictional/cli
2
+
3
+ CLI tool to install Autofictional autonomous sidebar adaptation into your React app.
4
+
5
+ ## Installation
6
+
7
+ From your project directory (frontend or root):
8
+
9
+ ```bash
10
+ node path/to/packages/cli/dist/index.js install
11
+ ```
12
+
13
+ Or if published to npm:
14
+
15
+ ```bash
16
+ npx autofictional
17
+ ```
18
+
19
+ ## Requirements
20
+
21
+ - React 18+
22
+ - Tailwind CSS
23
+ - shadcn Sidebar component (must be installed first)
24
+
25
+ ## What it does
26
+
27
+ 1. Detects your project setup (React, Tailwind, shadcn Sidebar)
28
+ 2. Installs `@autofictional/runtime` package
29
+ 3. Generates a unique app ID
30
+ 4. Patches your main entry file to wrap your app with `<AutofictionalProvider>`
31
+
32
+ ## Safety
33
+
34
+ - Creates a backup of your main file (`.backup` extension)
35
+ - Exits safely if patching fails
36
+ - Will not install if already installed
37
+
38
+ ## Verification
39
+
40
+ After installation:
41
+
42
+ 1. Start your dev server: `npm run dev`
43
+ 2. Visit `/autofictional-test` to verify the installation
44
+ 3. Check for no console errors
45
+ 4. Verify `AutofictionalProvider` is mounted
46
+
47
+ ## NIGHT 1 Status
48
+
49
+ ✅ Runtime skeleton installed
50
+ ✅ Provider renders children without behavior
51
+ ✅ No UI changes yet
52
+ ✅ No backend yet
53
+ ✅ No sidebar changes yet
54
+
55
+ This is NIGHT 1 of the MVP - the foundation is in place for autonomous sidebar adaptation.
56
+
@@ -0,0 +1 @@
1
+ export declare function install(): Promise<void>;
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.install = install;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const child_process_1 = require("child_process");
43
+ const chalk_1 = __importDefault(require("chalk"));
44
+ const detect_1 = require("../utils/detect");
45
+ const patch_1 = require("../utils/patch");
46
+ const generate_id_1 = require("../utils/generate-id");
47
+ async function install() {
48
+ console.log(chalk_1.default.bold.blue('\n🚀 Autofictional Installer\n'));
49
+ const cwd = process.cwd();
50
+ // Step 1: Detect React + Tailwind
51
+ console.log(chalk_1.default.dim('→ Detecting project setup...'));
52
+ const detection = (0, detect_1.detectProject)(cwd);
53
+ if (!detection.hasReact) {
54
+ console.error(chalk_1.default.red('✗ React not detected. Autofictional requires React.'));
55
+ process.exit(1);
56
+ }
57
+ if (!detection.hasTailwind) {
58
+ console.error(chalk_1.default.red('✗ Tailwind CSS not detected. Autofictional requires Tailwind.'));
59
+ process.exit(1);
60
+ }
61
+ if (!detection.hasShadcnSidebar) {
62
+ console.error(chalk_1.default.red('✗ shadcn Sidebar not detected. Please install it first.'));
63
+ console.log(chalk_1.default.dim(' Run: npx shadcn@latest add sidebar'));
64
+ process.exit(1);
65
+ }
66
+ console.log(chalk_1.default.green('✓ React detected'));
67
+ console.log(chalk_1.default.green('✓ Tailwind CSS detected'));
68
+ console.log(chalk_1.default.green('✓ shadcn Sidebar detected'));
69
+ // Step 2: Install @autofictional/runtime
70
+ console.log(chalk_1.default.dim('\n→ Installing @autofictional/runtime...'));
71
+ try {
72
+ // Try local package first (for development)
73
+ const runtimePath = path.resolve(__dirname, '../../../runtime');
74
+ const packageJsonPath = path.join(cwd, 'package.json');
75
+ // Check if we're in a monorepo with local packages
76
+ if (fs.existsSync(runtimePath) && fs.existsSync(packageJsonPath)) {
77
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
78
+ const isMonorepo = packageJson.workspaces || fs.existsSync(path.join(cwd, '..', 'packages'));
79
+ if (isMonorepo) {
80
+ // Use npm link for local development
81
+ console.log(chalk_1.default.dim(' Detected local development - using npm link...'));
82
+ (0, child_process_1.execSync)('npm link', { cwd: runtimePath, stdio: 'ignore' });
83
+ (0, child_process_1.execSync)('npm link @autofictional/runtime', { cwd, stdio: 'ignore' });
84
+ console.log(chalk_1.default.green('✓ Runtime linked (local development)'));
85
+ }
86
+ else {
87
+ // Install from npm
88
+ console.log(chalk_1.default.dim(' Installing from npm...'));
89
+ (0, child_process_1.execSync)('npm install @autofictional/runtime', { cwd, stdio: 'inherit' });
90
+ console.log(chalk_1.default.green('✓ Runtime installed from npm'));
91
+ }
92
+ }
93
+ else {
94
+ // Install from npm
95
+ console.log(chalk_1.default.dim(' Installing from npm...'));
96
+ (0, child_process_1.execSync)('npm install @autofictional/runtime', { cwd, stdio: 'inherit' });
97
+ console.log(chalk_1.default.green('✓ Runtime installed from npm'));
98
+ }
99
+ }
100
+ catch (error) {
101
+ console.error(chalk_1.default.red('✗ Failed to install runtime'));
102
+ console.error(chalk_1.default.dim(' Try: npm install @autofictional/runtime'));
103
+ console.error(error);
104
+ process.exit(1);
105
+ }
106
+ // Step 3: Generate app ID
107
+ const appId = (0, generate_id_1.generateAppId)();
108
+ console.log(chalk_1.default.dim(`\n→ Generated app ID: ${appId}`));
109
+ // Step 4: Patch main file
110
+ console.log(chalk_1.default.dim('\n→ Patching app entry point...'));
111
+ const mainFile = detection.mainFile;
112
+ if (!mainFile) {
113
+ console.error(chalk_1.default.red('✗ Could not find app entry point (main.tsx/main.jsx/index.tsx/index.jsx)'));
114
+ process.exit(1);
115
+ }
116
+ try {
117
+ (0, patch_1.patchMainFile)(mainFile, appId);
118
+ console.log(chalk_1.default.green(`✓ Patched ${path.relative(cwd, mainFile)}`));
119
+ }
120
+ catch (error) {
121
+ console.error(chalk_1.default.red('✗ Failed to patch main file'));
122
+ console.error(error);
123
+ process.exit(1);
124
+ }
125
+ // Success
126
+ console.log(chalk_1.default.bold.green('\n✓ Autofictional installed successfully!\n'));
127
+ console.log(chalk_1.default.dim('Next steps:'));
128
+ console.log(chalk_1.default.dim(' 1. Start your dev server'));
129
+ console.log(chalk_1.default.dim(' 2. Check console for errors'));
130
+ console.log(chalk_1.default.dim(' 3. Verify AutofictionalProvider is mounted\n'));
131
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const commander_1 = require("commander");
5
+ const install_1 = require("./commands/install");
6
+ const program = new commander_1.Command();
7
+ program
8
+ .name('autofictional')
9
+ .description('Install Autofictional autonomous sidebar adaptation')
10
+ .version('0.1.0');
11
+ program
12
+ .command('install')
13
+ .description('Install Autofictional runtime into your app')
14
+ .action(install_1.install);
15
+ // Default to install if no command specified
16
+ if (process.argv.length === 2) {
17
+ (0, install_1.install)();
18
+ }
19
+ else {
20
+ program.parse(process.argv);
21
+ }
@@ -0,0 +1,7 @@
1
+ export interface ProjectDetection {
2
+ hasReact: boolean;
3
+ hasTailwind: boolean;
4
+ hasShadcnSidebar: boolean;
5
+ mainFile: string | null;
6
+ }
7
+ export declare function detectProject(cwd: string): ProjectDetection;
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.detectProject = detectProject;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ function detectProject(cwd) {
40
+ const detection = {
41
+ hasReact: false,
42
+ hasTailwind: false,
43
+ hasShadcnSidebar: false,
44
+ mainFile: null,
45
+ };
46
+ // Check for package.json and dependencies
47
+ const packageJsonPath = path.join(cwd, 'package.json');
48
+ if (fs.existsSync(packageJsonPath)) {
49
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
50
+ const allDeps = {
51
+ ...packageJson.dependencies,
52
+ ...packageJson.devDependencies,
53
+ };
54
+ detection.hasReact = 'react' in allDeps;
55
+ detection.hasTailwind = 'tailwindcss' in allDeps;
56
+ }
57
+ // Check for shadcn sidebar component
58
+ const possibleSidebarPaths = [
59
+ path.join(cwd, 'src/components/ui/sidebar.tsx'),
60
+ path.join(cwd, 'components/ui/sidebar.tsx'),
61
+ path.join(cwd, 'frontend/src/components/ui/sidebar.tsx'),
62
+ ];
63
+ for (const sidebarPath of possibleSidebarPaths) {
64
+ if (fs.existsSync(sidebarPath)) {
65
+ detection.hasShadcnSidebar = true;
66
+ break;
67
+ }
68
+ }
69
+ // Find main entry file
70
+ const possibleMainFiles = [
71
+ path.join(cwd, 'src/main.tsx'),
72
+ path.join(cwd, 'src/main.jsx'),
73
+ path.join(cwd, 'src/index.tsx'),
74
+ path.join(cwd, 'src/index.jsx'),
75
+ path.join(cwd, 'frontend/src/main.tsx'),
76
+ path.join(cwd, 'frontend/src/main.jsx'),
77
+ path.join(cwd, 'frontend/src/index.tsx'),
78
+ path.join(cwd, 'frontend/src/index.jsx'),
79
+ ];
80
+ for (const mainFile of possibleMainFiles) {
81
+ if (fs.existsSync(mainFile)) {
82
+ detection.mainFile = mainFile;
83
+ break;
84
+ }
85
+ }
86
+ return detection;
87
+ }
@@ -0,0 +1 @@
1
+ export declare function generateAppId(): string;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.generateAppId = generateAppId;
37
+ const crypto = __importStar(require("crypto"));
38
+ function generateAppId() {
39
+ return 'app_' + crypto.randomBytes(16).toString('hex');
40
+ }
@@ -0,0 +1 @@
1
+ export declare function patchMainFile(mainFilePath: string, appId: string): void;
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.patchMainFile = patchMainFile;
37
+ const fs = __importStar(require("fs"));
38
+ function patchMainFile(mainFilePath, appId) {
39
+ const content = fs.readFileSync(mainFilePath, 'utf-8');
40
+ // Check if already patched
41
+ if (content.includes('AutofictionalProvider')) {
42
+ throw new Error('AutofictionalProvider already exists in main file. Aborting to avoid duplicate installation.');
43
+ }
44
+ // Parse the file structure
45
+ const lines = content.split('\n');
46
+ // Find import section end
47
+ let lastImportIndex = -1;
48
+ for (let i = 0; i < lines.length; i++) {
49
+ if (lines[i].trim().startsWith('import ')) {
50
+ lastImportIndex = i;
51
+ }
52
+ }
53
+ // Find ReactDOM.createRoot call
54
+ let rootCallIndex = -1;
55
+ let rootCallEndIndex = -1;
56
+ let indentLevel = 0;
57
+ for (let i = 0; i < lines.length; i++) {
58
+ if (lines[i].includes('ReactDOM.createRoot') || lines[i].includes('createRoot')) {
59
+ rootCallIndex = i;
60
+ // Find the closing parenthesis of the render call
61
+ let depth = 0;
62
+ for (let j = i; j < lines.length; j++) {
63
+ const line = lines[j];
64
+ depth += (line.match(/\(/g) || []).length;
65
+ depth -= (line.match(/\)/g) || []).length;
66
+ if (depth === 0 && line.includes(')')) {
67
+ rootCallEndIndex = j;
68
+ break;
69
+ }
70
+ }
71
+ break;
72
+ }
73
+ }
74
+ if (rootCallIndex === -1 || rootCallEndIndex === -1) {
75
+ throw new Error('Could not find ReactDOM.createRoot call. Manual installation required.');
76
+ }
77
+ // Detect indentation
78
+ const rootLine = lines[rootCallIndex];
79
+ const indent = rootLine.match(/^(\s*)/)?.[1] || ' ';
80
+ // Extract the content between <React.StrictMode> tags or the RouterProvider
81
+ let contentStart = -1;
82
+ let contentEnd = -1;
83
+ for (let i = rootCallIndex; i <= rootCallEndIndex; i++) {
84
+ if (lines[i].includes('<React.StrictMode>') || lines[i].includes('<RouterProvider') || lines[i].includes('<App')) {
85
+ contentStart = i;
86
+ break;
87
+ }
88
+ }
89
+ for (let i = rootCallEndIndex; i >= rootCallIndex; i--) {
90
+ if (lines[i].includes('</React.StrictMode>') || lines[i].includes('/>') || lines[i].includes('</App>')) {
91
+ contentEnd = i;
92
+ break;
93
+ }
94
+ }
95
+ if (contentStart === -1 || contentEnd === -1) {
96
+ throw new Error('Could not parse render content. Manual installation required.');
97
+ }
98
+ // Build the new content
99
+ const newLines = [...lines];
100
+ // Add import after last import
101
+ const importLine = `import { AutofictionalProvider } from '@autofictional/runtime';`;
102
+ newLines.splice(lastImportIndex + 1, 0, importLine);
103
+ // Adjust indices after insertion
104
+ contentStart += 1;
105
+ contentEnd += 1;
106
+ // Extract the wrapped content
107
+ const wrappedContent = newLines.slice(contentStart, contentEnd + 1);
108
+ // Indent the wrapped content
109
+ const indentedContent = wrappedContent.map(line => indent + ' ' + line.trimStart());
110
+ // Create the provider wrapper
111
+ const providerStart = `${indent} <AutofictionalProvider appId="${appId}">`;
112
+ const providerEnd = `${indent} </AutofictionalProvider>`;
113
+ // Replace the content
114
+ newLines.splice(contentStart, contentEnd - contentStart + 1, providerStart, ...indentedContent, providerEnd);
115
+ // Write back
116
+ const newContent = newLines.join('\n');
117
+ // Create backup
118
+ const backupPath = mainFilePath + '.backup';
119
+ fs.writeFileSync(backupPath, content);
120
+ // Write new content
121
+ fs.writeFileSync(mainFilePath, newContent);
122
+ }
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@autofictional/cli",
3
+ "version": "0.1.0",
4
+ "description": "CLI tool to install Autofictional runtime",
5
+ "author": "",
6
+ "license": "UNLICENSED",
7
+ "bin": {
8
+ "autofictional": "./dist/index.js"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/andreamorales/autofictional.git",
13
+ "directory": "packages/cli"
14
+ },
15
+ "homepage": "https://github.com/andreamorales/autofictional#readme",
16
+ "bugs": {
17
+ "url": "https://github.com/andreamorales/autofictional/issues"
18
+ },
19
+ "scripts": {
20
+ "build": "tsc",
21
+ "dev": "tsc --watch",
22
+ "prepublishOnly": "npm run build"
23
+ },
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "dependencies": {
28
+ "chalk": "^4.1.2",
29
+ "commander": "^11.0.0",
30
+ "prompts": "^2.4.2"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "^20.0.0",
34
+ "@types/prompts": "^2.4.4",
35
+ "typescript": "^5.0.0"
36
+ },
37
+ "files": [
38
+ "dist"
39
+ ]
40
+ }
41
+