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.
Files changed (52) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +33 -13
  3. package/bin.sh +49 -0
  4. package/build.zig +12 -0
  5. package/dist/darwin-arm64/usecomputer +0 -0
  6. package/dist/darwin-arm64/usecomputer.node +0 -0
  7. package/dist/darwin-x64/usecomputer +0 -0
  8. package/dist/darwin-x64/usecomputer.node +0 -0
  9. package/dist/index.d.ts +0 -2
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +1 -3
  12. package/dist/linux-x64/usecomputer +0 -0
  13. package/dist/linux-x64/usecomputer.node +0 -0
  14. package/package.json +7 -14
  15. package/src/index.ts +1 -3
  16. package/zig/src/kitty-graphics.zig +151 -0
  17. package/zig/src/lib.zig +121 -0
  18. package/zig/src/main.zig +667 -47
  19. package/zig/src/table.zig +170 -0
  20. package/bin.js +0 -4
  21. package/dist/cli-parsing.test.d.ts +0 -2
  22. package/dist/cli-parsing.test.d.ts.map +0 -1
  23. package/dist/cli-parsing.test.js +0 -53
  24. package/dist/cli.d.ts +0 -6
  25. package/dist/cli.d.ts.map +0 -1
  26. package/dist/cli.js +0 -536
  27. package/dist/command-parsers.d.ts +0 -6
  28. package/dist/command-parsers.d.ts.map +0 -1
  29. package/dist/command-parsers.js +0 -54
  30. package/dist/command-parsers.test.d.ts +0 -2
  31. package/dist/command-parsers.test.d.ts.map +0 -1
  32. package/dist/command-parsers.test.js +0 -44
  33. package/dist/debug-point-image.d.ts +0 -8
  34. package/dist/debug-point-image.d.ts.map +0 -1
  35. package/dist/debug-point-image.js +0 -43
  36. package/dist/debug-point-image.test.d.ts +0 -2
  37. package/dist/debug-point-image.test.d.ts.map +0 -1
  38. package/dist/debug-point-image.test.js +0 -44
  39. package/dist/terminal-table.d.ts +0 -10
  40. package/dist/terminal-table.d.ts.map +0 -1
  41. package/dist/terminal-table.js +0 -55
  42. package/dist/terminal-table.test.d.ts +0 -2
  43. package/dist/terminal-table.test.d.ts.map +0 -1
  44. package/dist/terminal-table.test.js +0 -41
  45. package/src/cli-parsing.test.ts +0 -61
  46. package/src/cli.ts +0 -648
  47. package/src/command-parsers.test.ts +0 -50
  48. package/src/command-parsers.ts +0 -60
  49. package/src/debug-point-image.test.ts +0 -50
  50. package/src/debug-point-image.ts +0 -69
  51. package/src/terminal-table.test.ts +0 -44
  52. package/src/terminal-table.ts +0 -88
@@ -1,60 +0,0 @@
1
- // Parser helpers for CLI values such as coordinates, regions, and key modifiers.
2
-
3
- import type { Point, Region, ScrollDirection } from './types.js'
4
-
5
- export function parsePoint(input: string): Error | Point {
6
- const parts = input.split(',').map((value) => {
7
- return value.trim()
8
- })
9
- if (parts.length !== 2) {
10
- return new Error(`Invalid point \"${input}\". Expected x,y`)
11
- }
12
- const x = Number(parts[0])
13
- const y = Number(parts[1])
14
- if (!Number.isFinite(x) || !Number.isFinite(y)) {
15
- return new Error(`Invalid point \"${input}\". Coordinates must be numbers`)
16
- }
17
- return { x, y }
18
- }
19
-
20
- export function parseRegion(input: string): Error | Region {
21
- const parts = input.split(',').map((value) => {
22
- return value.trim()
23
- })
24
- if (parts.length !== 4) {
25
- return new Error(`Invalid region \"${input}\". Expected x,y,width,height`)
26
- }
27
- const x = Number(parts[0])
28
- const y = Number(parts[1])
29
- const width = Number(parts[2])
30
- const height = Number(parts[3])
31
- if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(width) || !Number.isFinite(height)) {
32
- return new Error(`Invalid region \"${input}\". Values must be numbers`)
33
- }
34
- if (width <= 0 || height <= 0) {
35
- return new Error(`Invalid region \"${input}\". Width and height must be greater than 0`)
36
- }
37
- return { x, y, width, height }
38
- }
39
-
40
- export function parseModifiers(input?: string): string[] {
41
- if (!input) {
42
- return []
43
- }
44
- return input
45
- .split(',')
46
- .map((value) => {
47
- return value.trim().toLowerCase()
48
- })
49
- .filter((value) => {
50
- return value.length > 0
51
- })
52
- }
53
-
54
- export function parseDirection(input: string): Error | ScrollDirection {
55
- const normalized = input.trim().toLowerCase()
56
- if (normalized === 'up' || normalized === 'down' || normalized === 'left' || normalized === 'right') {
57
- return normalized
58
- }
59
- return new Error(`Invalid direction \"${input}\". Expected up, down, left, or right`)
60
- }
@@ -1,50 +0,0 @@
1
- // Validates that debug-point image overlays draw a visible red marker.
2
-
3
- import fs from 'node:fs'
4
- import path from 'node:path'
5
- import { describe, expect, test } from 'vitest'
6
- import { drawDebugPointOnImage } from './debug-point-image.js'
7
-
8
- describe('drawDebugPointOnImage', () => {
9
- test('draws a red marker at the requested point', async () => {
10
- const sharpModule = await import('sharp')
11
- const sharp = sharpModule.default
12
- const filePath = path.join(process.cwd(), 'tmp', 'debug-point-image-test.png')
13
-
14
- fs.mkdirSync(path.dirname(filePath), { recursive: true })
15
- const baseImage = await sharp({
16
- create: {
17
- width: 40,
18
- height: 30,
19
- channels: 4,
20
- background: { r: 255, g: 255, b: 255, alpha: 1 },
21
- },
22
- })
23
- .png()
24
- .toBuffer()
25
- fs.writeFileSync(filePath, baseImage)
26
-
27
- await drawDebugPointOnImage({
28
- imagePath: filePath,
29
- point: { x: 20, y: 15 },
30
- imageWidth: 40,
31
- imageHeight: 30,
32
- })
33
-
34
- const result = await sharp(filePath)
35
- .raw()
36
- .toBuffer({ resolveWithObject: true })
37
- const channels = result.info.channels
38
- const index = (15 * result.info.width + 20) * channels
39
- const pixel = Array.from(result.data.slice(index, index + channels))
40
-
41
- expect(pixel).toMatchInlineSnapshot(`
42
- [
43
- 255,
44
- 45,
45
- 45,
46
- 255,
47
- ]
48
- `)
49
- })
50
- })
@@ -1,69 +0,0 @@
1
- // Draws visible debug markers onto screenshots to validate coord-map targeting.
2
-
3
- import fs from 'node:fs'
4
- import path from 'node:path'
5
- import { createRequire } from 'node:module'
6
- import type { Point } from './types.js'
7
-
8
- type SharpModule = typeof import('sharp')
9
- const require = createRequire(import.meta.url)
10
-
11
- async function loadSharp(): Promise<SharpModule> {
12
- try {
13
- return require('sharp') as SharpModule
14
- } catch (error) {
15
- throw new Error('Optional dependency `sharp` is required for `debug-point`. Install it with `pnpm add sharp --save-optional`.', {
16
- cause: error,
17
- })
18
- }
19
- }
20
-
21
- function createMarkerSvg({
22
- point,
23
- imageWidth,
24
- imageHeight,
25
- }: {
26
- point: Point
27
- imageWidth: number
28
- imageHeight: number
29
- }): string {
30
- const radius = 10
31
- const crosshairRadius = 22
32
- const ringRadius = 18
33
-
34
- return [
35
- `<svg width="${String(imageWidth)}" height="${String(imageHeight)}" xmlns="http://www.w3.org/2000/svg">`,
36
- ' <g>',
37
- ` <circle cx="${String(point.x)}" cy="${String(point.y)}" r="${String(ringRadius)}" fill="none" stroke="white" stroke-width="4" opacity="0.95" />`,
38
- ` <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" />`,
39
- ` <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" />`,
40
- ` <circle cx="${String(point.x)}" cy="${String(point.y)}" r="${String(ringRadius)}" fill="none" stroke="#ff2d2d" stroke-width="2" />`,
41
- ` <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" />`,
42
- ` <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" />`,
43
- ` <circle cx="${String(point.x)}" cy="${String(point.y)}" r="${String(radius)}" fill="#ff2d2d" stroke="white" stroke-width="3" />`,
44
- ' </g>',
45
- '</svg>',
46
- ].join('\n')
47
- }
48
-
49
- export async function drawDebugPointOnImage({
50
- imagePath,
51
- point,
52
- imageWidth,
53
- imageHeight,
54
- }: {
55
- imagePath: string
56
- point: Point
57
- imageWidth: number
58
- imageHeight: number
59
- }): Promise<void> {
60
- const sharpModule = await loadSharp()
61
- const markerSvg = createMarkerSvg({ point, imageWidth, imageHeight })
62
- const output = await sharpModule(imagePath)
63
- .composite([{ input: Buffer.from(markerSvg) }])
64
- .png()
65
- .toBuffer()
66
-
67
- fs.mkdirSync(path.dirname(imagePath), { recursive: true })
68
- fs.writeFileSync(imagePath, output)
69
- }
@@ -1,44 +0,0 @@
1
- // Tests aligned terminal table formatting for deterministic CLI rendering.
2
-
3
- import { describe, expect, test } from 'vitest'
4
- import { renderAlignedTable } from './terminal-table.js'
5
-
6
- describe('terminal table', () => {
7
- test('renders aligned columns for mixed widths', () => {
8
- const lines = renderAlignedTable({
9
- rows: [
10
- { id: 2, app: 'Zed', size: '1720x1440' },
11
- { id: 102, app: 'Google Chrome', size: '3440x1440' },
12
- ],
13
- columns: [
14
- {
15
- header: 'id',
16
- align: 'right',
17
- value: (row) => {
18
- return String(row.id)
19
- },
20
- },
21
- {
22
- header: 'app',
23
- value: (row) => {
24
- return row.app
25
- },
26
- },
27
- {
28
- header: 'size',
29
- align: 'right',
30
- value: (row) => {
31
- return row.size
32
- },
33
- },
34
- ],
35
- })
36
-
37
- expect(lines.join('\n')).toMatchInlineSnapshot(`
38
- " id app size
39
- --- ------------- ---------
40
- 2 Zed 1720x1440
41
- 102 Google Chrome 3440x1440"
42
- `)
43
- })
44
- })
@@ -1,88 +0,0 @@
1
- // Generic aligned terminal table renderer for CLI command output.
2
-
3
- export type TableColumn<Row> = {
4
- header: string
5
- align?: 'left' | 'right'
6
- value: (row: Row) => string
7
- }
8
-
9
- export function renderAlignedTable<Row>({
10
- rows,
11
- columns,
12
- }: {
13
- rows: Row[]
14
- columns: TableColumn<Row>[]
15
- }): string[] {
16
- if (columns.length === 0) {
17
- return []
18
- }
19
-
20
- const widthByColumn = columns.map((column) => {
21
- const rowWidth = rows.reduce((maxWidth, row) => {
22
- const width = printableWidth(column.value(row))
23
- return Math.max(maxWidth, width)
24
- }, 0)
25
- return Math.max(printableWidth(column.header), rowWidth)
26
- })
27
-
28
- const formatCell = ({
29
- value,
30
- width,
31
- align,
32
- }: {
33
- value: string
34
- width: number
35
- align: 'left' | 'right'
36
- }): string => {
37
- const currentWidth = printableWidth(value)
38
- const padSize = Math.max(0, width - currentWidth)
39
- const padding = ' '.repeat(padSize)
40
- if (align === 'right') {
41
- return `${padding}${value}`
42
- }
43
- return `${value}${padding}`
44
- }
45
-
46
- const renderRow = ({
47
- values,
48
- }: {
49
- values: string[]
50
- }): string => {
51
- return values.map((value, index) => {
52
- const column = columns[index]
53
- if (!column) {
54
- return value
55
- }
56
- return formatCell({
57
- value,
58
- width: widthByColumn[index] ?? value.length,
59
- align: column.align ?? 'left',
60
- })
61
- }).join(' ')
62
- }
63
-
64
- const header = renderRow({
65
- values: columns.map((column) => {
66
- return column.header
67
- }),
68
- })
69
-
70
- const divider = widthByColumn.map((width) => {
71
- return '-'.repeat(width)
72
- }).join(' ')
73
-
74
- const lines = rows.map((row) => {
75
- return renderRow({
76
- values: columns.map((column) => {
77
- return column.value(row)
78
- }),
79
- })
80
- })
81
-
82
- return [header, divider, ...lines]
83
- }
84
-
85
- function printableWidth(value: string): number {
86
- const ansiStripped = value.replace(/\u001b\[[0-9;]*m/g, '')
87
- return ansiStripped.length
88
- }