local-operator-ui 0.1.0-beta.1
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/LICENSE +21 -0
- package/README.md +306 -0
- package/out/main/bytecode-loader.cjs +72 -0
- package/out/main/index.js +3 -0
- package/out/main/index.jsc +0 -0
- package/out/preload/bytecode-loader.cjs +72 -0
- package/out/preload/index.js +3 -0
- package/out/preload/index.jsc +0 -0
- package/out/renderer/assets/RobotoMono-Bold-CA4NrfZm.ttf +0 -0
- package/out/renderer/assets/RobotoMono-Regular-BCiLwUa1.ttf +0 -0
- package/out/renderer/assets/icon-ngVHF_bZ.png +0 -0
- package/out/renderer/assets/index-CasTLPHC.js +115255 -0
- package/out/renderer/assets/index-CueJ1--J.css +815 -0
- package/out/renderer/index.html +18 -0
- package/package.json +96 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Damian Tran
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
<picture>
|
|
2
|
+
<source media="(prefers-color-scheme: dark)" srcset="./resources/local-operator-icon-2-dark-clear.png">
|
|
3
|
+
<source media="(prefers-color-scheme: light)" srcset="./resources/local-operator-icon-2-light-clear.png">
|
|
4
|
+
<img alt="Shows a black Local Operator Logo in light color mode and a white one in dark color mode."
|
|
5
|
+
src="./resources/local-operator-icon-2-light-clear.png">
|
|
6
|
+
</picture>
|
|
7
|
+
|
|
8
|
+
<h1 align="center">Local Operator: AI Agent Assistants On Your Device</h1>
|
|
9
|
+
<div align="center">
|
|
10
|
+
<h2>🤖 Your Personal Assistant that Gets Things Done with Python</h2>
|
|
11
|
+
<p><i>Real-time code execution on your device through natural conversation</i></p>
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
**<span style="color: #38C96A">Local Operator</span>** empowers you to run Python code safely on your own machine through an intuitive chat interface. The AI agent:
|
|
15
|
+
|
|
16
|
+
🎯 **Plans & Executes** - Breaks down complex goals into manageable steps and executes them with precision.
|
|
17
|
+
|
|
18
|
+
🔒 **Prioritizes Security** - Built-in safety checks by independent AI review and user confirmations keep your system protected
|
|
19
|
+
|
|
20
|
+
🌐 **Flexible Deployment** - Run completely locally with Ollama models or leverage cloud providers like OpenAI
|
|
21
|
+
|
|
22
|
+
🔧 **Problem Solving** - Intelligently handles errors and roadblocks by adapting approaches and finding alternative solutions
|
|
23
|
+
|
|
24
|
+
This project is proudly open source under the MIT license. We believe AI tools should be accessible to everyone, given their transformative impact on productivity. Your contributions and feedback help make this vision a reality!
|
|
25
|
+
|
|
26
|
+
> "Democratizing AI-powered productivity, one conversation at a time."
|
|
27
|
+
|
|
28
|
+
<div align="center">
|
|
29
|
+
<a href="https://github.com/damianvtran/local-operator">Agent Backend</a> •
|
|
30
|
+
<a href="https://local-operator.com">Learn More</a> •
|
|
31
|
+
<a href="https://github.com/damianvtran/local-operator/tree/main/examples/notebooks">Examples</a>
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
## 💡 Overview
|
|
35
|
+
|
|
36
|
+
The Local Operator UI is a user interface for managing and interacting with the Local Operator agent environment. It is built using Electron, React, and TypeScript, leveraging modern web technologies for a rich and responsive user experience.
|
|
37
|
+
|
|
38
|
+
👉 For the agent environment CLI and Server backend, see the [Local Operator GitHub repository](https://github.com/damianvtran/local-operator).
|
|
39
|
+
|
|
40
|
+
## 🚀 Getting Started
|
|
41
|
+
|
|
42
|
+
### Prerequisites
|
|
43
|
+
|
|
44
|
+
Before you begin, ensure you have the following installed:
|
|
45
|
+
|
|
46
|
+
- **Node.js**: Version specified in `.nvmrc`. It's recommended to use [nvm](https://github.com/nvm-sh/nvm) for managing Node.js versions.
|
|
47
|
+
- **yarn**: Installable via `npm install -g yarn`.
|
|
48
|
+
- **Local Operator Backend**: The UI connects to the Local Operator backend API. See the [Local Operator GitHub repository](https://github.com/damianvtran/local-operator) for installation instructions.
|
|
49
|
+
|
|
50
|
+
### Installation
|
|
51
|
+
|
|
52
|
+
**Clone the repository:**
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
git clone https://github.com/local-operator/local-operator-ui.git
|
|
56
|
+
cd local-operator-ui
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Install dependencies:**
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
yarn install
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Configure environment variables:**
|
|
66
|
+
|
|
67
|
+
Copy the `.env.template` file to `.env` and update the values as needed:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
cp .env.template .env
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The main environment variable is:
|
|
74
|
+
|
|
75
|
+
- `VITE_LOCAL_OPERATOR_API_URL`: URL of the Local Operator backend API (default: `http://localhost:1111`)
|
|
76
|
+
|
|
77
|
+
### Development
|
|
78
|
+
|
|
79
|
+
For local development, follow these steps:
|
|
80
|
+
|
|
81
|
+
**Start the development server:**
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
yarn dev
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
This command will start the Electron application in development mode, with hot reloading enabled for both the main process and the renderer process.
|
|
88
|
+
|
|
89
|
+
### Production
|
|
90
|
+
|
|
91
|
+
To build and run the application in production mode:
|
|
92
|
+
|
|
93
|
+
**Build and start the application:**
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
yarn start
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
This command will run the pre-build script and then start the Electron application in production mode, loading the compiled assets.
|
|
100
|
+
|
|
101
|
+
## 🏗️ Project Structure
|
|
102
|
+
|
|
103
|
+
The project follows a modular architecture with clear separation of concerns:
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
local-operator-ui/
|
|
107
|
+
├── resources/ # Application resources (icons, images)
|
|
108
|
+
├── src/ # Source code
|
|
109
|
+
│ ├── main/ # Electron main process
|
|
110
|
+
│ │ └── index.ts # Main process entry point
|
|
111
|
+
│ ├── preload/ # Electron preload scripts
|
|
112
|
+
│ │ ├── index.d.ts # Type definitions
|
|
113
|
+
│ │ └── index.ts # Preload script
|
|
114
|
+
│ └── renderer/ # Renderer process (React application)
|
|
115
|
+
│ ├── index.html # HTML template
|
|
116
|
+
│ └── src/ # React application source
|
|
117
|
+
│ ├── api/ # API clients and utilities
|
|
118
|
+
│ │ ├── query-client.ts # React Query client setup
|
|
119
|
+
│ │ └── local-operator/ # Local Operator API client
|
|
120
|
+
│ │ ├── agents-api.ts # Agents API endpoints
|
|
121
|
+
│ │ ├── chat-api.ts # Chat API endpoints
|
|
122
|
+
│ │ ├── config-api.ts # Config API endpoints
|
|
123
|
+
│ │ ├── credentials-api.ts # Credentials API endpoints
|
|
124
|
+
│ │ ├── health-api.ts # Health API endpoints
|
|
125
|
+
│ │ ├── jobs-api.ts # Jobs API endpoints
|
|
126
|
+
│ │ ├── types.ts # API type definitions
|
|
127
|
+
│ │ └── index.ts # API client exports
|
|
128
|
+
│ ├── assets/ # Static assets
|
|
129
|
+
│ ├── components/ # React components
|
|
130
|
+
│ │ ├── agents/ # Agent management components
|
|
131
|
+
│ │ ├── chat/ # Chat interface components
|
|
132
|
+
│ │ ├── common/ # Shared/common components
|
|
133
|
+
│ │ ├── navigation/ # Navigation components
|
|
134
|
+
│ │ └── settings/ # Settings components
|
|
135
|
+
│ ├── hooks/ # Custom React hooks
|
|
136
|
+
│ ├── store/ # State management (Zustand)
|
|
137
|
+
│ ├── app.tsx # Main application component
|
|
138
|
+
│ ├── config.ts # Application configuration
|
|
139
|
+
│ ├── main.tsx # Application entry point
|
|
140
|
+
│ ├── theme.ts # MUI theme configuration
|
|
141
|
+
│ └── vite-env.d.ts # Vite environment type definitions
|
|
142
|
+
├── .env.template # Environment variables template
|
|
143
|
+
├── biome.json # Biome configuration
|
|
144
|
+
├── electron.vite.config.js # Electron Vite configuration
|
|
145
|
+
├── eslint.config.js # ESLint configuration
|
|
146
|
+
├── package.json # Project dependencies and scripts
|
|
147
|
+
├── tsconfig.json # TypeScript configuration
|
|
148
|
+
└── README.md # Project documentation
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Key Directories
|
|
152
|
+
|
|
153
|
+
- **src/main**: Contains the Electron main process code
|
|
154
|
+
- **src/preload**: Contains the Electron preload scripts
|
|
155
|
+
- **src/renderer**: Contains the React application code
|
|
156
|
+
- **api**: API clients for communicating with the Local Operator backend
|
|
157
|
+
- **components**: React components organized by feature
|
|
158
|
+
- **hooks**: Custom React hooks for data fetching and state management
|
|
159
|
+
- **store**: Global state management using Zustand
|
|
160
|
+
|
|
161
|
+
## 🛠️ Technology Stack
|
|
162
|
+
|
|
163
|
+
The Local Operator UI is built with the following technologies:
|
|
164
|
+
|
|
165
|
+
### Core Technologies
|
|
166
|
+
|
|
167
|
+
- **Electron**: Cross-platform desktop application framework
|
|
168
|
+
- **React**: UI library for building component-based interfaces
|
|
169
|
+
- **TypeScript**: Typed superset of JavaScript for improved developer experience
|
|
170
|
+
- **Vite**: Modern frontend build tool
|
|
171
|
+
|
|
172
|
+
### UI Framework and Styling
|
|
173
|
+
|
|
174
|
+
- **Material UI (MUI)**: React component library implementing Google's Material Design
|
|
175
|
+
- **Styled Components**: CSS-in-JS library for component styling
|
|
176
|
+
- **Emotion**: CSS-in-JS library used by MUI
|
|
177
|
+
- **FontAwesome**: Icon library
|
|
178
|
+
|
|
179
|
+
### State Management and Data Fetching
|
|
180
|
+
|
|
181
|
+
- **Zustand**: Lightweight state management library
|
|
182
|
+
- **React Query**: Data fetching and caching library
|
|
183
|
+
- **Zod**: TypeScript-first schema validation
|
|
184
|
+
|
|
185
|
+
### Development Tools
|
|
186
|
+
|
|
187
|
+
- **Biome**: Fast linter and formatter for JavaScript and TypeScript
|
|
188
|
+
- **ESLint**: JavaScript and TypeScript linter
|
|
189
|
+
- **TypeScript**: Static type checking
|
|
190
|
+
|
|
191
|
+
## ✨ Features
|
|
192
|
+
|
|
193
|
+
The Local Operator UI provides a comprehensive interface for interacting with AI agents:
|
|
194
|
+
|
|
195
|
+
### Chat Interface
|
|
196
|
+
|
|
197
|
+
- Real-time chat with AI agents
|
|
198
|
+
- Markdown rendering for code blocks and formatted text
|
|
199
|
+
- Syntax highlighting for code snippets
|
|
200
|
+
- Message history and conversation management
|
|
201
|
+
|
|
202
|
+
### Agent Management
|
|
203
|
+
|
|
204
|
+
- Create, update, and delete AI agents
|
|
205
|
+
- Configure agent settings:
|
|
206
|
+
- General settings (name, description, model)
|
|
207
|
+
- Chat settings (temperature, top_p, etc.)
|
|
208
|
+
- Security settings (security prompt, execution permissions)
|
|
209
|
+
|
|
210
|
+
### Settings
|
|
211
|
+
|
|
212
|
+
- System prompt configuration
|
|
213
|
+
- API credentials management
|
|
214
|
+
- Application configuration
|
|
215
|
+
|
|
216
|
+
### API Integration
|
|
217
|
+
|
|
218
|
+
- Seamless integration with the Local Operator backend API
|
|
219
|
+
- Real-time status updates for long-running operations
|
|
220
|
+
- Error handling and retry mechanisms
|
|
221
|
+
|
|
222
|
+
## 🧪 Testing
|
|
223
|
+
|
|
224
|
+
The project uses Jest for testing. To run tests:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
yarn test
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## 🔧 Linting and Formatting
|
|
231
|
+
|
|
232
|
+
The project uses Biome for linting and formatting. To lint and format the code:
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
# Check for linting issues
|
|
236
|
+
yarn lint
|
|
237
|
+
|
|
238
|
+
# Fix linting issues
|
|
239
|
+
yarn lint:fix
|
|
240
|
+
|
|
241
|
+
# Format code
|
|
242
|
+
yarn format
|
|
243
|
+
|
|
244
|
+
# Fix formatting issues
|
|
245
|
+
yarn format:fix
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## 🤝 Contributing
|
|
249
|
+
|
|
250
|
+
Contributions are welcome! Here's how you can contribute:
|
|
251
|
+
|
|
252
|
+
1. Fork the repository
|
|
253
|
+
2. Create a new branch (`git checkout -b feature/your-feature-name`)
|
|
254
|
+
3. Make your changes
|
|
255
|
+
4. Run tests and linting (`yarn test && yarn lint`)
|
|
256
|
+
5. Commit your changes (`git commit -m 'Add some feature'`)
|
|
257
|
+
6. Push to the branch (`git push origin feature/your-feature-name`)
|
|
258
|
+
7. Open a Pull Request
|
|
259
|
+
|
|
260
|
+
Please ensure your code follows the project's coding standards:
|
|
261
|
+
|
|
262
|
+
- Use TypeScript for all new code
|
|
263
|
+
- Follow the existing code style and patterns
|
|
264
|
+
- Write tests for new features
|
|
265
|
+
- Update documentation as needed
|
|
266
|
+
|
|
267
|
+
### Code Style Guidelines
|
|
268
|
+
|
|
269
|
+
- Use `type` instead of `interface` for type definitions
|
|
270
|
+
- Use kebab-case for file names and PascalCase for component names
|
|
271
|
+
- Use named exports instead of default exports
|
|
272
|
+
- Include JSDoc documentation where appropriate
|
|
273
|
+
- Follow Biome linting conventions
|
|
274
|
+
|
|
275
|
+
## 🐛 Troubleshooting
|
|
276
|
+
|
|
277
|
+
### Common Issues
|
|
278
|
+
|
|
279
|
+
#### Application fails to connect to the backend
|
|
280
|
+
|
|
281
|
+
- Ensure the Local Operator backend is running
|
|
282
|
+
- Check that the `VITE_LOCAL_OPERATOR_API_URL` environment variable is set correctly
|
|
283
|
+
- Verify network connectivity between the UI and the backend
|
|
284
|
+
|
|
285
|
+
#### Development server crashes
|
|
286
|
+
|
|
287
|
+
- Check the console for error messages
|
|
288
|
+
- Ensure all dependencies are installed correctly
|
|
289
|
+
- Try clearing the node_modules folder and reinstalling dependencies
|
|
290
|
+
|
|
291
|
+
#### UI rendering issues
|
|
292
|
+
|
|
293
|
+
- Check for console errors in the developer tools
|
|
294
|
+
- Ensure you're using a compatible version of Node.js
|
|
295
|
+
- Try restarting the development server
|
|
296
|
+
|
|
297
|
+
### Getting Help
|
|
298
|
+
|
|
299
|
+
If you encounter issues not covered here, please:
|
|
300
|
+
|
|
301
|
+
1. Check the [GitHub Issues](https://github.com/local-operator/local-operator-ui/issues) for similar problems
|
|
302
|
+
2. Open a new issue if your problem hasn't been reported
|
|
303
|
+
|
|
304
|
+
## 📄 License
|
|
305
|
+
|
|
306
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const vm = require("vm");
|
|
5
|
+
const v8 = require("v8");
|
|
6
|
+
const Module = require("module");
|
|
7
|
+
v8.setFlagsFromString("--no-lazy");
|
|
8
|
+
v8.setFlagsFromString("--no-flush-bytecode");
|
|
9
|
+
const FLAG_HASH_OFFSET = 12;
|
|
10
|
+
const SOURCE_HASH_OFFSET = 8;
|
|
11
|
+
let dummyBytecode;
|
|
12
|
+
function setFlagHashHeader(bytecodeBuffer) {
|
|
13
|
+
if (!dummyBytecode) {
|
|
14
|
+
const script = new vm.Script("", {
|
|
15
|
+
produceCachedData: true
|
|
16
|
+
});
|
|
17
|
+
dummyBytecode = script.createCachedData();
|
|
18
|
+
}
|
|
19
|
+
dummyBytecode.slice(FLAG_HASH_OFFSET, FLAG_HASH_OFFSET + 4).copy(bytecodeBuffer, FLAG_HASH_OFFSET);
|
|
20
|
+
};
|
|
21
|
+
function getSourceHashHeader(bytecodeBuffer) {
|
|
22
|
+
return bytecodeBuffer.slice(SOURCE_HASH_OFFSET, SOURCE_HASH_OFFSET + 4);
|
|
23
|
+
};
|
|
24
|
+
function buffer2Number(buffer) {
|
|
25
|
+
let ret = 0;
|
|
26
|
+
ret |= buffer[3] << 24;
|
|
27
|
+
ret |= buffer[2] << 16;
|
|
28
|
+
ret |= buffer[1] << 8;
|
|
29
|
+
ret |= buffer[0];
|
|
30
|
+
return ret;
|
|
31
|
+
};
|
|
32
|
+
Module._extensions[".jsc"] = Module._extensions[".cjsc"] = function (module, filename) {
|
|
33
|
+
const bytecodeBuffer = fs.readFileSync(filename);
|
|
34
|
+
if (!Buffer.isBuffer(bytecodeBuffer)) {
|
|
35
|
+
throw new Error("BytecodeBuffer must be a buffer object.");
|
|
36
|
+
}
|
|
37
|
+
setFlagHashHeader(bytecodeBuffer);
|
|
38
|
+
const length = buffer2Number(getSourceHashHeader(bytecodeBuffer));
|
|
39
|
+
let dummyCode = "";
|
|
40
|
+
if (length > 1) {
|
|
41
|
+
dummyCode = "\"" + "\u200b".repeat(length - 2) + "\"";
|
|
42
|
+
}
|
|
43
|
+
const script = new vm.Script(dummyCode, {
|
|
44
|
+
filename: filename,
|
|
45
|
+
lineOffset: 0,
|
|
46
|
+
displayErrors: true,
|
|
47
|
+
cachedData: bytecodeBuffer
|
|
48
|
+
});
|
|
49
|
+
if (script.cachedDataRejected) {
|
|
50
|
+
throw new Error("Invalid or incompatible cached data (cachedDataRejected)");
|
|
51
|
+
}
|
|
52
|
+
const require = function (id) {
|
|
53
|
+
return module.require(id);
|
|
54
|
+
};
|
|
55
|
+
require.resolve = function (request, options) {
|
|
56
|
+
return Module._resolveFilename(request, module, false, options);
|
|
57
|
+
};
|
|
58
|
+
if (process.mainModule) {
|
|
59
|
+
require.main = process.mainModule;
|
|
60
|
+
}
|
|
61
|
+
require.extensions = Module._extensions;
|
|
62
|
+
require.cache = Module._cache;
|
|
63
|
+
const compiledWrapper = script.runInThisContext({
|
|
64
|
+
filename: filename,
|
|
65
|
+
lineOffset: 0,
|
|
66
|
+
columnOffset: 0,
|
|
67
|
+
displayErrors: true
|
|
68
|
+
});
|
|
69
|
+
const dirname = path.dirname(filename);
|
|
70
|
+
const args = [module.exports, require, module, filename, dirname, process, global];
|
|
71
|
+
return compiledWrapper.apply(module.exports, args);
|
|
72
|
+
};
|
|
Binary file
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const vm = require("vm");
|
|
5
|
+
const v8 = require("v8");
|
|
6
|
+
const Module = require("module");
|
|
7
|
+
v8.setFlagsFromString("--no-lazy");
|
|
8
|
+
v8.setFlagsFromString("--no-flush-bytecode");
|
|
9
|
+
const FLAG_HASH_OFFSET = 12;
|
|
10
|
+
const SOURCE_HASH_OFFSET = 8;
|
|
11
|
+
let dummyBytecode;
|
|
12
|
+
function setFlagHashHeader(bytecodeBuffer) {
|
|
13
|
+
if (!dummyBytecode) {
|
|
14
|
+
const script = new vm.Script("", {
|
|
15
|
+
produceCachedData: true
|
|
16
|
+
});
|
|
17
|
+
dummyBytecode = script.createCachedData();
|
|
18
|
+
}
|
|
19
|
+
dummyBytecode.slice(FLAG_HASH_OFFSET, FLAG_HASH_OFFSET + 4).copy(bytecodeBuffer, FLAG_HASH_OFFSET);
|
|
20
|
+
};
|
|
21
|
+
function getSourceHashHeader(bytecodeBuffer) {
|
|
22
|
+
return bytecodeBuffer.slice(SOURCE_HASH_OFFSET, SOURCE_HASH_OFFSET + 4);
|
|
23
|
+
};
|
|
24
|
+
function buffer2Number(buffer) {
|
|
25
|
+
let ret = 0;
|
|
26
|
+
ret |= buffer[3] << 24;
|
|
27
|
+
ret |= buffer[2] << 16;
|
|
28
|
+
ret |= buffer[1] << 8;
|
|
29
|
+
ret |= buffer[0];
|
|
30
|
+
return ret;
|
|
31
|
+
};
|
|
32
|
+
Module._extensions[".jsc"] = Module._extensions[".cjsc"] = function (module, filename) {
|
|
33
|
+
const bytecodeBuffer = fs.readFileSync(filename);
|
|
34
|
+
if (!Buffer.isBuffer(bytecodeBuffer)) {
|
|
35
|
+
throw new Error("BytecodeBuffer must be a buffer object.");
|
|
36
|
+
}
|
|
37
|
+
setFlagHashHeader(bytecodeBuffer);
|
|
38
|
+
const length = buffer2Number(getSourceHashHeader(bytecodeBuffer));
|
|
39
|
+
let dummyCode = "";
|
|
40
|
+
if (length > 1) {
|
|
41
|
+
dummyCode = "\"" + "\u200b".repeat(length - 2) + "\"";
|
|
42
|
+
}
|
|
43
|
+
const script = new vm.Script(dummyCode, {
|
|
44
|
+
filename: filename,
|
|
45
|
+
lineOffset: 0,
|
|
46
|
+
displayErrors: true,
|
|
47
|
+
cachedData: bytecodeBuffer
|
|
48
|
+
});
|
|
49
|
+
if (script.cachedDataRejected) {
|
|
50
|
+
throw new Error("Invalid or incompatible cached data (cachedDataRejected)");
|
|
51
|
+
}
|
|
52
|
+
const require = function (id) {
|
|
53
|
+
return module.require(id);
|
|
54
|
+
};
|
|
55
|
+
require.resolve = function (request, options) {
|
|
56
|
+
return Module._resolveFilename(request, module, false, options);
|
|
57
|
+
};
|
|
58
|
+
if (process.mainModule) {
|
|
59
|
+
require.main = process.mainModule;
|
|
60
|
+
}
|
|
61
|
+
require.extensions = Module._extensions;
|
|
62
|
+
require.cache = Module._cache;
|
|
63
|
+
const compiledWrapper = script.runInThisContext({
|
|
64
|
+
filename: filename,
|
|
65
|
+
lineOffset: 0,
|
|
66
|
+
columnOffset: 0,
|
|
67
|
+
displayErrors: true
|
|
68
|
+
});
|
|
69
|
+
const dirname = path.dirname(filename);
|
|
70
|
+
const args = [module.exports, require, module, filename, dirname, process, global];
|
|
71
|
+
return compiledWrapper.apply(module.exports, args);
|
|
72
|
+
};
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|