usecomputer 0.1.2 → 0.1.4
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/CHANGELOG.md +41 -0
- package/README.md +33 -13
- package/bin.sh +49 -0
- package/build.zig +12 -0
- package/dist/darwin-arm64/usecomputer +0 -0
- package/dist/darwin-arm64/usecomputer.node +0 -0
- package/dist/darwin-x64/usecomputer +0 -0
- package/dist/darwin-x64/usecomputer.node +0 -0
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -3
- package/dist/linux-x64/usecomputer +0 -0
- package/dist/linux-x64/usecomputer.node +0 -0
- package/package.json +7 -14
- package/src/index.ts +1 -3
- package/zig/src/kitty-graphics.zig +151 -0
- package/zig/src/lib.zig +121 -0
- package/zig/src/main.zig +667 -47
- package/zig/src/table.zig +170 -0
- package/bin.js +0 -4
- package/dist/cli-parsing.test.d.ts +0 -2
- package/dist/cli-parsing.test.d.ts.map +0 -1
- package/dist/cli-parsing.test.js +0 -53
- package/dist/cli.d.ts +0 -6
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -536
- package/dist/command-parsers.d.ts +0 -6
- package/dist/command-parsers.d.ts.map +0 -1
- package/dist/command-parsers.js +0 -54
- package/dist/command-parsers.test.d.ts +0 -2
- package/dist/command-parsers.test.d.ts.map +0 -1
- package/dist/command-parsers.test.js +0 -44
- package/dist/debug-point-image.d.ts +0 -8
- package/dist/debug-point-image.d.ts.map +0 -1
- package/dist/debug-point-image.js +0 -43
- package/dist/debug-point-image.test.d.ts +0 -2
- package/dist/debug-point-image.test.d.ts.map +0 -1
- package/dist/debug-point-image.test.js +0 -44
- package/dist/terminal-table.d.ts +0 -10
- package/dist/terminal-table.d.ts.map +0 -1
- package/dist/terminal-table.js +0 -55
- package/dist/terminal-table.test.d.ts +0 -2
- package/dist/terminal-table.test.d.ts.map +0 -1
- package/dist/terminal-table.test.js +0 -41
- package/src/cli-parsing.test.ts +0 -61
- package/src/cli.ts +0 -648
- package/src/command-parsers.test.ts +0 -50
- package/src/command-parsers.ts +0 -60
- package/src/debug-point-image.test.ts +0 -50
- package/src/debug-point-image.ts +0 -69
- package/src/terminal-table.test.ts +0 -44
- package/src/terminal-table.ts +0 -88
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
// Draws visible debug markers onto screenshots to validate coord-map targeting.
|
|
2
|
-
import fs from 'node:fs';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import { createRequire } from 'node:module';
|
|
5
|
-
const require = createRequire(import.meta.url);
|
|
6
|
-
async function loadSharp() {
|
|
7
|
-
try {
|
|
8
|
-
return require('sharp');
|
|
9
|
-
}
|
|
10
|
-
catch (error) {
|
|
11
|
-
throw new Error('Optional dependency `sharp` is required for `debug-point`. Install it with `pnpm add sharp --save-optional`.', {
|
|
12
|
-
cause: error,
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
function createMarkerSvg({ point, imageWidth, imageHeight, }) {
|
|
17
|
-
const radius = 10;
|
|
18
|
-
const crosshairRadius = 22;
|
|
19
|
-
const ringRadius = 18;
|
|
20
|
-
return [
|
|
21
|
-
`<svg width="${String(imageWidth)}" height="${String(imageHeight)}" xmlns="http://www.w3.org/2000/svg">`,
|
|
22
|
-
' <g>',
|
|
23
|
-
` <circle cx="${String(point.x)}" cy="${String(point.y)}" r="${String(ringRadius)}" fill="none" stroke="white" stroke-width="4" opacity="0.95" />`,
|
|
24
|
-
` <line x1="${String(point.x - crosshairRadius)}" y1="${String(point.y)}" x2="${String(point.x + crosshairRadius)}" y2="${String(point.y)}" stroke="white" stroke-width="5" stroke-linecap="round" opacity="0.95" />`,
|
|
25
|
-
` <line x1="${String(point.x)}" y1="${String(point.y - crosshairRadius)}" x2="${String(point.x)}" y2="${String(point.y + crosshairRadius)}" stroke="white" stroke-width="5" stroke-linecap="round" opacity="0.95" />`,
|
|
26
|
-
` <circle cx="${String(point.x)}" cy="${String(point.y)}" r="${String(ringRadius)}" fill="none" stroke="#ff2d2d" stroke-width="2" />`,
|
|
27
|
-
` <line x1="${String(point.x - crosshairRadius)}" y1="${String(point.y)}" x2="${String(point.x + crosshairRadius)}" y2="${String(point.y)}" stroke="#ff2d2d" stroke-width="3" stroke-linecap="round" />`,
|
|
28
|
-
` <line x1="${String(point.x)}" y1="${String(point.y - crosshairRadius)}" x2="${String(point.x)}" y2="${String(point.y + crosshairRadius)}" stroke="#ff2d2d" stroke-width="3" stroke-linecap="round" />`,
|
|
29
|
-
` <circle cx="${String(point.x)}" cy="${String(point.y)}" r="${String(radius)}" fill="#ff2d2d" stroke="white" stroke-width="3" />`,
|
|
30
|
-
' </g>',
|
|
31
|
-
'</svg>',
|
|
32
|
-
].join('\n');
|
|
33
|
-
}
|
|
34
|
-
export async function drawDebugPointOnImage({ imagePath, point, imageWidth, imageHeight, }) {
|
|
35
|
-
const sharpModule = await loadSharp();
|
|
36
|
-
const markerSvg = createMarkerSvg({ point, imageWidth, imageHeight });
|
|
37
|
-
const output = await sharpModule(imagePath)
|
|
38
|
-
.composite([{ input: Buffer.from(markerSvg) }])
|
|
39
|
-
.png()
|
|
40
|
-
.toBuffer();
|
|
41
|
-
fs.mkdirSync(path.dirname(imagePath), { recursive: true });
|
|
42
|
-
fs.writeFileSync(imagePath, output);
|
|
43
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"debug-point-image.test.d.ts","sourceRoot":"","sources":["../src/debug-point-image.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
// Validates that debug-point image overlays draw a visible red marker.
|
|
2
|
-
import fs from 'node:fs';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import { describe, expect, test } from 'vitest';
|
|
5
|
-
import { drawDebugPointOnImage } from './debug-point-image.js';
|
|
6
|
-
describe('drawDebugPointOnImage', () => {
|
|
7
|
-
test('draws a red marker at the requested point', async () => {
|
|
8
|
-
const sharpModule = await import('sharp');
|
|
9
|
-
const sharp = sharpModule.default;
|
|
10
|
-
const filePath = path.join(process.cwd(), 'tmp', 'debug-point-image-test.png');
|
|
11
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
12
|
-
const baseImage = await sharp({
|
|
13
|
-
create: {
|
|
14
|
-
width: 40,
|
|
15
|
-
height: 30,
|
|
16
|
-
channels: 4,
|
|
17
|
-
background: { r: 255, g: 255, b: 255, alpha: 1 },
|
|
18
|
-
},
|
|
19
|
-
})
|
|
20
|
-
.png()
|
|
21
|
-
.toBuffer();
|
|
22
|
-
fs.writeFileSync(filePath, baseImage);
|
|
23
|
-
await drawDebugPointOnImage({
|
|
24
|
-
imagePath: filePath,
|
|
25
|
-
point: { x: 20, y: 15 },
|
|
26
|
-
imageWidth: 40,
|
|
27
|
-
imageHeight: 30,
|
|
28
|
-
});
|
|
29
|
-
const result = await sharp(filePath)
|
|
30
|
-
.raw()
|
|
31
|
-
.toBuffer({ resolveWithObject: true });
|
|
32
|
-
const channels = result.info.channels;
|
|
33
|
-
const index = (15 * result.info.width + 20) * channels;
|
|
34
|
-
const pixel = Array.from(result.data.slice(index, index + channels));
|
|
35
|
-
expect(pixel).toMatchInlineSnapshot(`
|
|
36
|
-
[
|
|
37
|
-
255,
|
|
38
|
-
45,
|
|
39
|
-
45,
|
|
40
|
-
255,
|
|
41
|
-
]
|
|
42
|
-
`);
|
|
43
|
-
});
|
|
44
|
-
});
|
package/dist/terminal-table.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export type TableColumn<Row> = {
|
|
2
|
-
header: string;
|
|
3
|
-
align?: 'left' | 'right';
|
|
4
|
-
value: (row: Row) => string;
|
|
5
|
-
};
|
|
6
|
-
export declare function renderAlignedTable<Row>({ rows, columns, }: {
|
|
7
|
-
rows: Row[];
|
|
8
|
-
columns: TableColumn<Row>[];
|
|
9
|
-
}): string[];
|
|
10
|
-
//# sourceMappingURL=terminal-table.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"terminal-table.d.ts","sourceRoot":"","sources":["../src/terminal-table.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,WAAW,CAAC,GAAG,IAAI;IAC7B,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IACxB,KAAK,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM,CAAA;CAC5B,CAAA;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,EACtC,IAAI,EACJ,OAAO,GACR,EAAE;IACD,IAAI,EAAE,GAAG,EAAE,CAAA;IACX,OAAO,EAAE,WAAW,CAAC,GAAG,CAAC,EAAE,CAAA;CAC5B,GAAG,MAAM,EAAE,CAoEX"}
|
package/dist/terminal-table.js
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
// Generic aligned terminal table renderer for CLI command output.
|
|
2
|
-
export function renderAlignedTable({ rows, columns, }) {
|
|
3
|
-
if (columns.length === 0) {
|
|
4
|
-
return [];
|
|
5
|
-
}
|
|
6
|
-
const widthByColumn = columns.map((column) => {
|
|
7
|
-
const rowWidth = rows.reduce((maxWidth, row) => {
|
|
8
|
-
const width = printableWidth(column.value(row));
|
|
9
|
-
return Math.max(maxWidth, width);
|
|
10
|
-
}, 0);
|
|
11
|
-
return Math.max(printableWidth(column.header), rowWidth);
|
|
12
|
-
});
|
|
13
|
-
const formatCell = ({ value, width, align, }) => {
|
|
14
|
-
const currentWidth = printableWidth(value);
|
|
15
|
-
const padSize = Math.max(0, width - currentWidth);
|
|
16
|
-
const padding = ' '.repeat(padSize);
|
|
17
|
-
if (align === 'right') {
|
|
18
|
-
return `${padding}${value}`;
|
|
19
|
-
}
|
|
20
|
-
return `${value}${padding}`;
|
|
21
|
-
};
|
|
22
|
-
const renderRow = ({ values, }) => {
|
|
23
|
-
return values.map((value, index) => {
|
|
24
|
-
const column = columns[index];
|
|
25
|
-
if (!column) {
|
|
26
|
-
return value;
|
|
27
|
-
}
|
|
28
|
-
return formatCell({
|
|
29
|
-
value,
|
|
30
|
-
width: widthByColumn[index] ?? value.length,
|
|
31
|
-
align: column.align ?? 'left',
|
|
32
|
-
});
|
|
33
|
-
}).join(' ');
|
|
34
|
-
};
|
|
35
|
-
const header = renderRow({
|
|
36
|
-
values: columns.map((column) => {
|
|
37
|
-
return column.header;
|
|
38
|
-
}),
|
|
39
|
-
});
|
|
40
|
-
const divider = widthByColumn.map((width) => {
|
|
41
|
-
return '-'.repeat(width);
|
|
42
|
-
}).join(' ');
|
|
43
|
-
const lines = rows.map((row) => {
|
|
44
|
-
return renderRow({
|
|
45
|
-
values: columns.map((column) => {
|
|
46
|
-
return column.value(row);
|
|
47
|
-
}),
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
return [header, divider, ...lines];
|
|
51
|
-
}
|
|
52
|
-
function printableWidth(value) {
|
|
53
|
-
const ansiStripped = value.replace(/\u001b\[[0-9;]*m/g, '');
|
|
54
|
-
return ansiStripped.length;
|
|
55
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"terminal-table.test.d.ts","sourceRoot":"","sources":["../src/terminal-table.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
// Tests aligned terminal table formatting for deterministic CLI rendering.
|
|
2
|
-
import { describe, expect, test } from 'vitest';
|
|
3
|
-
import { renderAlignedTable } from './terminal-table.js';
|
|
4
|
-
describe('terminal table', () => {
|
|
5
|
-
test('renders aligned columns for mixed widths', () => {
|
|
6
|
-
const lines = renderAlignedTable({
|
|
7
|
-
rows: [
|
|
8
|
-
{ id: 2, app: 'Zed', size: '1720x1440' },
|
|
9
|
-
{ id: 102, app: 'Google Chrome', size: '3440x1440' },
|
|
10
|
-
],
|
|
11
|
-
columns: [
|
|
12
|
-
{
|
|
13
|
-
header: 'id',
|
|
14
|
-
align: 'right',
|
|
15
|
-
value: (row) => {
|
|
16
|
-
return String(row.id);
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
header: 'app',
|
|
21
|
-
value: (row) => {
|
|
22
|
-
return row.app;
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
header: 'size',
|
|
27
|
-
align: 'right',
|
|
28
|
-
value: (row) => {
|
|
29
|
-
return row.size;
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
],
|
|
33
|
-
});
|
|
34
|
-
expect(lines.join('\n')).toMatchInlineSnapshot(`
|
|
35
|
-
" id app size
|
|
36
|
-
--- ------------- ---------
|
|
37
|
-
2 Zed 1720x1440
|
|
38
|
-
102 Google Chrome 3440x1440"
|
|
39
|
-
`);
|
|
40
|
-
});
|
|
41
|
-
});
|
package/src/cli-parsing.test.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
// Parser tests for goke CLI options and flags.
|
|
2
|
-
|
|
3
|
-
import { describe, expect, test } from 'vitest'
|
|
4
|
-
import { createCli } from './cli.js'
|
|
5
|
-
|
|
6
|
-
describe('usecomputer cli parsing', () => {
|
|
7
|
-
test('parses click options with typed defaults', () => {
|
|
8
|
-
const cli = createCli()
|
|
9
|
-
const parsed = cli.parse(['node', 'usecomputer', 'click', '100,200', '--count', '2'], { run: false })
|
|
10
|
-
expect(parsed.args[0]).toBe('100,200')
|
|
11
|
-
expect(parsed.options.count).toBe(2)
|
|
12
|
-
expect(parsed.options.button).toBe('left')
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
test('parses screenshot options', () => {
|
|
16
|
-
const cli = createCli()
|
|
17
|
-
const parsed = cli.parse(['node', 'usecomputer', 'screenshot', './shot.png', '--display', '2', '--region', '0,0,120,80'], {
|
|
18
|
-
run: false,
|
|
19
|
-
})
|
|
20
|
-
expect(parsed.args[0]).toBe('./shot.png')
|
|
21
|
-
expect(parsed.options.display).toBe(2)
|
|
22
|
-
expect(parsed.options.region).toBe('0,0,120,80')
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
test('parses coord-map option for click and mouse move', () => {
|
|
26
|
-
const clickCli = createCli()
|
|
27
|
-
const clickParsed = clickCli.parse(['node', 'usecomputer', 'click', '-x', '100', '-y', '200', '--coord-map', '0,0,1600,900,1568,882'], {
|
|
28
|
-
run: false,
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
const moveCli = createCli()
|
|
32
|
-
const moveParsed = moveCli.parse(['node', 'usecomputer', 'mouse', 'move', '-x', '100', '-y', '200', '--coord-map', '0,0,1600,900,1568,882'], {
|
|
33
|
-
run: false,
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
expect(clickParsed.options.coordMap).toBe('0,0,1600,900,1568,882')
|
|
37
|
-
expect(moveParsed.options.coordMap).toBe('0,0,1600,900,1568,882')
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
test('parses debug-point options', () => {
|
|
41
|
-
const cli = createCli()
|
|
42
|
-
const parsed = cli.parse([
|
|
43
|
-
'node',
|
|
44
|
-
'usecomputer',
|
|
45
|
-
'debug-point',
|
|
46
|
-
'-x',
|
|
47
|
-
'210',
|
|
48
|
-
'-y',
|
|
49
|
-
'560',
|
|
50
|
-
'--coord-map',
|
|
51
|
-
'0,0,1720,1440,1568,1313',
|
|
52
|
-
'--output',
|
|
53
|
-
'./tmp/debug-point.png',
|
|
54
|
-
], { run: false })
|
|
55
|
-
|
|
56
|
-
expect(parsed.options.coordMap).toBe('0,0,1720,1440,1568,1313')
|
|
57
|
-
expect(parsed.options.output).toBe('./tmp/debug-point.png')
|
|
58
|
-
expect(parsed.options.x).toBe(210)
|
|
59
|
-
expect(parsed.options.y).toBe(560)
|
|
60
|
-
})
|
|
61
|
-
})
|