@shreyassp002/pinionos-emulator 0.2.0 → 0.2.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/README.md +29 -3
- package/dist/src/ui/dashboard.js +5 -4
- package/dist/src/ui/panels/header.js +38 -28
- package/dist/src/version.js +53 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
<img src="assets/logo.jpg" alt="PinionOS Emulator Logo" width="220" />
|
|
3
|
+
<img src="https://github.com/Shreyassp002/pinionos-emulator/blob/main/assets/logo.jpg" alt="PinionOS Emulator Logo" width="220" />
|
|
4
4
|
|
|
5
5
|
# PinionOS Emulator
|
|
6
6
|
|
|
@@ -79,9 +79,16 @@ Your emulator MCP server currently exposes:
|
|
|
79
79
|
|
|
80
80
|
## Quick Start
|
|
81
81
|
|
|
82
|
+
Install in your project:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npm install @shreyassp002/pinionos-emulator
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Start emulator (local install):
|
|
89
|
+
|
|
82
90
|
```bash
|
|
83
|
-
|
|
84
|
-
npm start
|
|
91
|
+
npx pinionos-emulator
|
|
85
92
|
```
|
|
86
93
|
|
|
87
94
|
Health check:
|
|
@@ -96,14 +103,33 @@ Headless mode:
|
|
|
96
103
|
npx pinionos-emulator --no-dashboard
|
|
97
104
|
```
|
|
98
105
|
|
|
106
|
+
Optional global install:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
npm install -g @shreyassp002/pinionos-emulator
|
|
110
|
+
pinionos-emulator
|
|
111
|
+
```
|
|
112
|
+
|
|
99
113
|
## CLI Commands
|
|
100
114
|
|
|
115
|
+
Local install (recommended):
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
npx pinionos-emulator start
|
|
119
|
+
npx pinionos-emulator mcp
|
|
120
|
+
npx pinionos-emulator init
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Global install:
|
|
124
|
+
|
|
101
125
|
```bash
|
|
102
126
|
pinionos-emulator start
|
|
103
127
|
pinionos-emulator mcp
|
|
104
128
|
pinionos-emulator init
|
|
105
129
|
```
|
|
106
130
|
|
|
131
|
+
`start` is the default command, so `npx pinionos-emulator` and `pinionos-emulator` are equivalent to `... start`.
|
|
132
|
+
|
|
107
133
|
Useful options:
|
|
108
134
|
- `--port <n>`
|
|
109
135
|
- `--x402`
|
package/dist/src/ui/dashboard.js
CHANGED
|
@@ -174,12 +174,13 @@ function buildDashboard(port) {
|
|
|
174
174
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
175
175
|
const contrib = require('blessed-contrib');
|
|
176
176
|
const screen = blessed.screen({ smartCSR: true, title: 'PinionOS Emulator', fullUnicode: true });
|
|
177
|
-
const grid = new contrib.grid({ rows: 24, cols: 12, screen });
|
|
177
|
+
const grid = new contrib.grid({ rows: 24, cols: 12, screen, hideBorder: true });
|
|
178
178
|
const header = asContentWidget(grid.set(0, 0, 8, 12, blessed.box, {
|
|
179
179
|
tags: true,
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
180
|
+
align: 'center',
|
|
181
|
+
valign: 'middle',
|
|
182
|
+
wrap: false,
|
|
183
|
+
style: { fg: 'cyan' }
|
|
183
184
|
}));
|
|
184
185
|
const prices = asContentWidget(grid.set(8, 0, 5, 5, blessed.box, {
|
|
185
186
|
border: { type: 'line' },
|
|
@@ -3,51 +3,61 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.buildHeaderText = buildHeaderText;
|
|
4
4
|
exports.printHeader = printHeader;
|
|
5
5
|
const colors_1 = require("../colors");
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
const version_1 = require("../../version");
|
|
7
|
+
function terminalWidth() {
|
|
8
|
+
return process.stdout.columns ?? 100;
|
|
8
9
|
}
|
|
9
|
-
function
|
|
10
|
-
const top = `╔${line(width)}╗`;
|
|
11
|
-
const bottom = `╚${line(width)}╝`;
|
|
12
|
-
const lines = contentLines.map((lineText) => {
|
|
13
|
-
const clean = lineText.slice(0, width);
|
|
14
|
-
return `║${clean.padEnd(width, ' ')}║`;
|
|
15
|
-
});
|
|
16
|
-
return [top, ...lines, bottom].join('\n');
|
|
17
|
-
}
|
|
18
|
-
function figletBanner() {
|
|
10
|
+
function figletBanner(columns) {
|
|
19
11
|
try {
|
|
20
12
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
21
13
|
const figlet = require('figlet');
|
|
22
|
-
|
|
14
|
+
const font = columns >= 118 ? 'ANSI Shadow' : 'Small';
|
|
15
|
+
return figlet.textSync('PINION OS', { font }).split('\n').filter((line) => line.trim().length > 0);
|
|
23
16
|
}
|
|
24
17
|
catch {
|
|
18
|
+
if (columns >= 118) {
|
|
19
|
+
return [
|
|
20
|
+
'██████╗ ██╗███╗ ██╗██╗ ██████╗ ███╗ ██╗ ██████╗ ███████╗',
|
|
21
|
+
'██╔══██╗██║████╗ ██║██║██╔═══██╗████╗ ██║██╔═══██╗██╔════╝',
|
|
22
|
+
'██████╔╝██║██╔██╗ ██║██║██║ ██║██╔██╗ ██║██║ ██║███████╗',
|
|
23
|
+
'██╔═══╝ ██║██║╚██╗██║██║██║ ██║██║╚██╗██║██║ ██║╚════██║',
|
|
24
|
+
'██║ ██║██║ ╚████║██║╚██████╔╝██║ ╚████║╚██████╔╝███████║',
|
|
25
|
+
'╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚══════╝'
|
|
26
|
+
];
|
|
27
|
+
}
|
|
25
28
|
return [
|
|
26
|
-
'
|
|
27
|
-
'
|
|
28
|
-
'
|
|
29
|
-
'
|
|
30
|
-
|
|
31
|
-
'╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚══════╝'
|
|
32
|
-
].join('\n');
|
|
29
|
+
' ___ ___ _ _ ___ ___ _ _ ___ ___ ',
|
|
30
|
+
' | _ \\_ _| \\| |_ _/ _ \\| \\| | / _ \\/ __|',
|
|
31
|
+
' | _/| || .` || | (_) | .` | | (_) \\__ \\',
|
|
32
|
+
' |_| |___|_|\\_|___\\___/|_|\\_| \\___/|___/'
|
|
33
|
+
];
|
|
33
34
|
}
|
|
34
35
|
}
|
|
36
|
+
function fit(text, maxLen = 68) {
|
|
37
|
+
if (text.length <= maxLen)
|
|
38
|
+
return text;
|
|
39
|
+
if (maxLen <= 3)
|
|
40
|
+
return '.'.repeat(maxLen);
|
|
41
|
+
return `${text.slice(0, maxLen - 3)}...`;
|
|
42
|
+
}
|
|
35
43
|
function buildHeaderText(port, totalCalls = 0, errorCount = 0, uptimeStr = '00:00:00', x402Payments = 0, opts) {
|
|
36
|
-
const
|
|
44
|
+
const cols = terminalWidth();
|
|
45
|
+
const maxLen = Math.max(42, Math.min(104, cols - 12));
|
|
46
|
+
const bannerLines = figletBanner(cols);
|
|
47
|
+
const version = (0, version_1.getAppVersion)();
|
|
37
48
|
const networkName = opts?.network ?? 'base';
|
|
38
49
|
const chainId = opts?.chainId ?? 8453;
|
|
39
|
-
const subtitle1 = `E M U L A T O R
|
|
50
|
+
const subtitle1 = fit(`E M U L A T O R v${version} | http://localhost:${port}`, maxLen);
|
|
40
51
|
const features = [];
|
|
41
52
|
if (opts?.x402Mode)
|
|
42
53
|
features.push('x402: ON');
|
|
43
54
|
if (opts?.recording)
|
|
44
55
|
features.push('REC');
|
|
45
|
-
const featureTag = features.length > 0 ? `
|
|
46
|
-
const subtitle2 = `Zero-cost local simulator for PinionOS skills & agents
|
|
47
|
-
const x402Tag = x402Payments > 0 ? `
|
|
48
|
-
const subtitle3 = `Calls: ${totalCalls}
|
|
49
|
-
|
|
50
|
-
return `${colors_1.COLORS.cyan}${boxWrap(all)}${colors_1.COLORS.reset}`;
|
|
56
|
+
const featureTag = features.length > 0 ? ` | ${features.join(' | ')}` : '';
|
|
57
|
+
const subtitle2 = fit(`Zero-cost local simulator for PinionOS skills & agents | Network: ${networkName} (${chainId})${featureTag}`, maxLen);
|
|
58
|
+
const x402Tag = x402Payments > 0 ? ` | x402:${x402Payments}` : '';
|
|
59
|
+
const subtitle3 = fit(`Calls: ${totalCalls} | Errors: ${errorCount}${x402Tag} | Uptime: ${uptimeStr} | Press q to quit`, maxLen);
|
|
60
|
+
return `${colors_1.COLORS.cyan}${[...bannerLines, '', subtitle1, subtitle2, subtitle3].join('\n')}${colors_1.COLORS.reset}`;
|
|
51
61
|
}
|
|
52
62
|
function printHeader(port = 4020) {
|
|
53
63
|
process.stdout.write('\x1Bc');
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getAppVersion = getAppVersion;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
let cachedVersion = null;
|
|
10
|
+
function normalizeVersion(value) {
|
|
11
|
+
if (typeof value !== 'string')
|
|
12
|
+
return null;
|
|
13
|
+
const trimmed = value.trim();
|
|
14
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
15
|
+
}
|
|
16
|
+
function findNearestPackageJson(startDir) {
|
|
17
|
+
let dir = node_path_1.default.resolve(startDir);
|
|
18
|
+
while (true) {
|
|
19
|
+
const candidate = node_path_1.default.join(dir, 'package.json');
|
|
20
|
+
if (node_fs_1.default.existsSync(candidate))
|
|
21
|
+
return candidate;
|
|
22
|
+
const parent = node_path_1.default.dirname(dir);
|
|
23
|
+
if (parent === dir)
|
|
24
|
+
return null;
|
|
25
|
+
dir = parent;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function getAppVersion() {
|
|
29
|
+
if (cachedVersion)
|
|
30
|
+
return cachedVersion;
|
|
31
|
+
const fromEnv = normalizeVersion(process.env.npm_package_version);
|
|
32
|
+
if (fromEnv) {
|
|
33
|
+
cachedVersion = fromEnv;
|
|
34
|
+
return cachedVersion;
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
const packagePath = findNearestPackageJson(__dirname);
|
|
38
|
+
if (packagePath) {
|
|
39
|
+
const raw = node_fs_1.default.readFileSync(packagePath, 'utf8');
|
|
40
|
+
const parsed = JSON.parse(raw);
|
|
41
|
+
const fromPkg = normalizeVersion(parsed.version);
|
|
42
|
+
if (fromPkg) {
|
|
43
|
+
cachedVersion = fromPkg;
|
|
44
|
+
return cachedVersion;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// fallback below
|
|
50
|
+
}
|
|
51
|
+
cachedVersion = '0.0.0';
|
|
52
|
+
return cachedVersion;
|
|
53
|
+
}
|