@hasna/computer 0.1.8 → 0.1.9

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 (44) hide show
  1. package/LICENSE +4 -2
  2. package/README.md +73 -7
  3. package/dist/apps/ghostty/applescript.d.ts +36 -0
  4. package/dist/apps/ghostty/applescript.d.ts.map +1 -0
  5. package/dist/apps/ghostty/applescript.test.d.ts +2 -0
  6. package/dist/apps/ghostty/applescript.test.d.ts.map +1 -0
  7. package/dist/apps/ghostty/driver.d.ts +10 -0
  8. package/dist/apps/ghostty/driver.d.ts.map +1 -0
  9. package/dist/apps/registry.d.ts +5 -0
  10. package/dist/apps/registry.d.ts.map +1 -0
  11. package/dist/apps/registry.test.d.ts +2 -0
  12. package/dist/apps/registry.test.d.ts.map +1 -0
  13. package/dist/apps/types.d.ts +47 -0
  14. package/dist/apps/types.d.ts.map +1 -0
  15. package/dist/cli/index.js +1055 -91
  16. package/dist/cli/storage.d.ts +3 -0
  17. package/dist/cli/storage.d.ts.map +1 -0
  18. package/dist/cli/storage.test.d.ts +2 -0
  19. package/dist/cli/storage.test.d.ts.map +1 -0
  20. package/dist/db/storage-sync.d.ts +57 -0
  21. package/dist/db/storage-sync.d.ts.map +1 -0
  22. package/dist/db/storage-sync.test.d.ts +2 -0
  23. package/dist/db/storage-sync.test.d.ts.map +1 -0
  24. package/dist/index.d.ts +1 -1
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +84 -26
  27. package/dist/mcp/http.d.ts +16 -0
  28. package/dist/mcp/http.d.ts.map +1 -0
  29. package/dist/mcp/http.test.d.ts +2 -0
  30. package/dist/mcp/http.test.d.ts.map +1 -0
  31. package/dist/mcp/index.d.ts +1 -1
  32. package/dist/mcp/index.d.ts.map +1 -1
  33. package/dist/mcp/index.js +609 -262
  34. package/dist/mcp/server.d.ts +4 -0
  35. package/dist/mcp/server.d.ts.map +1 -0
  36. package/dist/server/index.js +34565 -8747
  37. package/dist/storage.d.ts +5 -0
  38. package/dist/storage.d.ts.map +1 -0
  39. package/dist/storage.js +5519 -0
  40. package/package.json +7 -2
  41. package/dist/cli/cloud.d.ts +0 -3
  42. package/dist/cli/cloud.d.ts.map +0 -1
  43. package/dist/db/cloud-sync.d.ts +0 -33
  44. package/dist/db/cloud-sync.d.ts.map +0 -1
package/LICENSE CHANGED
@@ -1,3 +1,4 @@
1
+
1
2
  Apache License
2
3
  Version 2.0, January 2004
3
4
  http://www.apache.org/licenses/
@@ -34,7 +35,8 @@
34
35
 
35
36
  "Work" shall mean the work of authorship, whether in Source or
36
37
  Object form, made available under the License, as indicated by a
37
- copyright notice that is included in or attached to the work.
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
38
40
 
39
41
  "Derivative Works" shall mean any work, whether in Source or Object
40
42
  form, that is based on (or derived from) the Work and for which the
@@ -174,7 +176,7 @@
174
176
 
175
177
  END OF TERMS AND CONDITIONS
176
178
 
177
- Copyright 2026 Andrei Hasna
179
+ Copyright 2026 Hasna, Inc.
178
180
 
179
181
  Licensed under the Apache License, Version 2.0 (the "License");
180
182
  you may not use this file except in compliance with the License.
package/README.md CHANGED
@@ -47,12 +47,63 @@ bun install -g @hasna/computer
47
47
  computer run <task> # Run a computer use task
48
48
  computer run <task> -p openai # Use OpenAI instead of Anthropic
49
49
  computer run <task> -s 30 # Limit to 30 steps
50
+ computer open <app> [options] # Open an app deterministically via its driver
51
+ computer apps # List app drivers + availability
50
52
  computer screenshot # Capture current screen
51
53
  computer sessions # List past sessions
52
54
  computer session <id> # Show session details + action log
53
55
  computer stats # Usage statistics
54
56
  ```
55
57
 
58
+ ## Apps
59
+
60
+ Beyond AI-driven tasks (`computer run`), `computer` ships deterministic **app
61
+ drivers** that open and arrange desktop apps with zero AI in the loop — windows,
62
+ tabs, pane grids, and a command per pane.
63
+
64
+ ```bash
65
+ computer apps # List registered drivers and availability
66
+ computer open <app> [options] # Open/orchestrate an app via its driver
67
+ ```
68
+
69
+ Options for `computer open`:
70
+
71
+ | Option | Description |
72
+ |--------|-------------|
73
+ | `--grid RxC` | Split the window into R rows x C cols (panes fill row-major: left-to-right, top-to-bottom) |
74
+ | `--tabs "spec1,spec2,..."` | Multiple tabs in one window, each with its own grid (e.g. `"2x2,1x2,1x2"`) |
75
+ | `--run <cmd>` | Command for the next pane in order (repeatable); with `--tabs`, commands flow across tabs |
76
+ | `--all` | Run the single `--run` command in every pane |
77
+ | `--dir <path>` | Working directory — every pane `cd`s there first |
78
+ | `--max` | Maximize the new window (not native fullscreen) |
79
+
80
+ Examples:
81
+
82
+ ```bash
83
+ # 2x2 grid, run codewith in all four panes, maximized
84
+ computer open ghostty --grid 2x2 --run "codewith" --all --max
85
+
86
+ # 2x2 grid with a different command per pane
87
+ computer open ghostty --grid 2x2 --run "htop" --run "btop" --run "vim" --run "bun dev"
88
+
89
+ # Three tabs (2x2, then two 1x2), every pane cd'd into the project
90
+ computer open ghostty --tabs "2x2,1x2,1x2" --dir ~/Workspace/myproject
91
+ ```
92
+
93
+ **Drivers:**
94
+
95
+ - **ghostty** — Ghostty terminal (macOS, Ghostty 1.3+). Uses Ghostty's native
96
+ AppleScript dictionary for windows, tabs, and splits. Requires
97
+ `/Applications/Ghostty.app` (or `ghostty` on PATH).
98
+
99
+ Drivers are app-generic: each implements `available()` (with a reason when
100
+ unavailable, e.g. on Linux) and `open(spec)`. New drivers register in
101
+ `src/apps/registry.ts`.
102
+
103
+ The same surface is exposed over MCP via `computer_open_app`
104
+ (params: `app`, `grid`, `tabs`, `run[]`, `all`, `dir`, `max` — falls back to a
105
+ plain macOS app launch for apps without a driver) and `computer_list_apps`.
106
+
56
107
  ## MCP Server
57
108
 
58
109
  Add to your Claude Code config:
@@ -67,6 +118,19 @@ Add to your Claude Code config:
67
118
  }
68
119
  ```
69
120
 
121
+ ## HTTP mode
122
+
123
+ Shared Streamable HTTP transport for multi-agent sessions (stdio remains the default):
124
+
125
+ ```bash
126
+ computer-mcp --http # http://127.0.0.1:8806/mcp
127
+ MCP_HTTP=1 computer-mcp # same via env
128
+ computer-mcp --http --port 9000 # override port
129
+ ```
130
+
131
+ - Health: `GET http://127.0.0.1:8806/health` → `{"status":"ok","name":"computer"}`
132
+ - MCP endpoint is also mounted on `computer-serve` at `/mcp`.
133
+
70
134
  **Available tools:**
71
135
  - `computer_run_task` — Run a full computer use task
72
136
  - `computer_screenshot` — Capture the screen
@@ -146,19 +210,21 @@ const result = await driver.execute({
146
210
 
147
211
  Sessions and action logs are stored in `~/.hasna/computer/computer.db` (SQLite).
148
212
 
149
- ## Cloud Sync
213
+ ## Storage Sync
150
214
 
151
215
  Optional Postgres sync is available through package-local commands:
152
216
 
153
217
  ```bash
154
- export HASNA_COMPUTER_CLOUD_DATABASE_URL=postgres://...
155
- computer cloud status
156
- computer cloud push
157
- computer cloud pull
158
- computer cloud sync
218
+ export HASNA_COMPUTER_DATABASE_URL=postgres://...
219
+ computer storage status
220
+ computer storage push
221
+ computer storage pull
222
+ computer storage sync
159
223
  ```
160
224
 
161
- The MCP server also exposes `cloud_status`, `cloud_push`, `cloud_pull`, and `cloud_sync`.
225
+ The MCP server also exposes `storage_status`, `storage_push`, `storage_pull`, and `storage_sync`.
226
+
227
+ `COMPUTER_DATABASE_URL` is accepted as the non-Hasna fallback database URL.
162
228
 
163
229
  ## License
164
230
 
@@ -0,0 +1,36 @@
1
+ import type { PaneGrid } from "../types.js";
2
+ /** Parse "RxC" (e.g. "2x2", "3x1") into a PaneGrid. Throws on invalid input. */
3
+ export declare function parseGrid(spec: string): PaneGrid;
4
+ /** Parse a comma-separated tabs spec like "2x2,1x2,1x2" into one grid per tab. */
5
+ export declare function parseTabsSpec(spec: string): PaneGrid[];
6
+ /** Escape a string for embedding inside an AppleScript double-quoted literal. */
7
+ export declare function escapeAppleScript(s: string): string;
8
+ /** Single-quote a string for POSIX shells (used for `cd <dir>`). */
9
+ export declare function shellQuote(s: string): string;
10
+ /**
11
+ * Map run commands onto panes (row-major across tabs in order).
12
+ * - `all` fills every pane with the single command (requires exactly one).
13
+ * - Otherwise commands are assigned in order; extra panes get undefined.
14
+ * Throws when there are more commands than panes.
15
+ */
16
+ export declare function assignPaneCommands(totalPanes: number, run: string[], all: boolean): (string | undefined)[];
17
+ export interface GhosttyScriptOptions {
18
+ /** One grid per tab; the first tab reuses the new window's selected tab. */
19
+ tabs: PaneGrid[];
20
+ /** Command per pane, row-major across tabs in order. undefined = empty shell. */
21
+ commands?: (string | undefined)[];
22
+ /** Working directory — every pane cds here before its command. */
23
+ dir?: string;
24
+ /** Maximize the new window (toggle_maximize, not native fullscreen). */
25
+ max?: boolean;
26
+ }
27
+ /**
28
+ * Build the full AppleScript for opening one Ghostty window with the given
29
+ * tabs/grids/commands. Pure — returns the script string.
30
+ *
31
+ * Grid algorithm (per tab): build column 0 downward (split direction down
32
+ * from the previous row), then split each row rightward C-1 times, then
33
+ * equalize once. Commands inject row-major with `input text` + enter key.
34
+ */
35
+ export declare function buildGhosttyScript(opts: GhosttyScriptOptions): string;
36
+ //# sourceMappingURL=applescript.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applescript.d.ts","sourceRoot":"","sources":["../../../src/apps/ghostty/applescript.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,gFAAgF;AAChF,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAShD;AAED,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,EAAE,CAMtD;AAED,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,oEAAoE;AACpE,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,EAAE,EACb,GAAG,EAAE,OAAO,GACX,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,CAWxB;AAED,MAAM,WAAW,oBAAoB;IACnC,4EAA4E;IAC5E,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,iFAAiF;IACjF,QAAQ,CAAC,EAAE,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,CAAC;IAClC,kEAAkE;IAClE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,oBAAoB,GAAG,MAAM,CAiErE"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=applescript.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applescript.test.d.ts","sourceRoot":"","sources":["../../../src/apps/ghostty/applescript.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,10 @@
1
+ import type { AppAvailability, AppDriver } from "../types.js";
2
+ export interface GhosttyEnvironment {
3
+ platform?: NodeJS.Platform | string;
4
+ hasAppBundle?: boolean;
5
+ hasBinary?: boolean;
6
+ }
7
+ /** Availability check, injectable for tests. */
8
+ export declare function ghosttyAvailability(env?: GhosttyEnvironment): AppAvailability;
9
+ export declare const ghosttyDriver: AppDriver;
10
+ //# sourceMappingURL=driver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../../../src/apps/ghostty/driver.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAwC,MAAM,aAAa,CAAC;AAKpG,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC;IACpC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,gDAAgD;AAChD,wBAAgB,mBAAmB,CAAC,GAAG,GAAE,kBAAuB,GAAG,eAAe,CAWjF;AAmBD,eAAO,MAAM,aAAa,EAAE,SAiD3B,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { AppDriver } from "./types.js";
2
+ export declare function registerAppDriver(driver: AppDriver): void;
3
+ export declare function getAppDriver(name: string): AppDriver | undefined;
4
+ export declare function listAppDrivers(): AppDriver[];
5
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/apps/registry.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAK5C,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAEzD;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAEhE;AAED,wBAAgB,cAAc,IAAI,SAAS,EAAE,CAE5C"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=registry.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.test.d.ts","sourceRoot":"","sources":["../../src/apps/registry.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,47 @@
1
+ /** A pane grid: R rows x C cols. Panes are addressed row-major. */
2
+ export interface PaneGrid {
3
+ rows: number;
4
+ cols: number;
5
+ }
6
+ /** Declarative description of how to open/arrange an app. */
7
+ export interface AppOpenSpec {
8
+ /** Split the window into rows x cols panes (single tab). */
9
+ grid?: PaneGrid;
10
+ /** Multiple tabs in one window, each with its own grid. Overrides `grid`. */
11
+ tabs?: PaneGrid[];
12
+ /** Commands per pane, row-major across tabs in order. */
13
+ run?: string[];
14
+ /** Fill every pane with the single `run` command. */
15
+ all?: boolean;
16
+ /** Working directory — every pane cds here before running its command. */
17
+ dir?: string;
18
+ /** Maximize the new window (not native fullscreen). */
19
+ max?: boolean;
20
+ }
21
+ /** Whether a driver can run on this machine, and why not if it can't. */
22
+ export interface AppAvailability {
23
+ available: boolean;
24
+ /** Human-readable reason when unavailable. */
25
+ reason?: string;
26
+ }
27
+ /** Result of an open() call. */
28
+ export interface AppOpenResult {
29
+ ok: boolean;
30
+ message: string;
31
+ /** Total panes created (when applicable). */
32
+ panes?: number;
33
+ /** Tabs created (when applicable). */
34
+ tabs?: number;
35
+ }
36
+ /** A deterministic driver for one desktop application. */
37
+ export interface AppDriver {
38
+ /** Registry key, e.g. "ghostty". Lowercase. */
39
+ name: string;
40
+ /** One-line human description. */
41
+ description: string;
42
+ /** Check availability on this machine. */
43
+ available(): AppAvailability;
44
+ /** Open/orchestrate the app according to spec. */
45
+ open(spec: AppOpenSpec): Promise<AppOpenResult>;
46
+ }
47
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/apps/types.ts"],"names":[],"mappings":"AAOA,mEAAmE;AACnE,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,6DAA6D;AAC7D,MAAM,WAAW,WAAW;IAC1B,4DAA4D;IAC5D,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC;IAClB,yDAAyD;IACzD,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,qDAAqD;IACrD,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,0EAA0E;IAC1E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,yEAAyE;AACzE,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,gCAAgC;AAChC,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,0DAA0D;AAC1D,MAAM,WAAW,SAAS;IACxB,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,0CAA0C;IAC1C,SAAS,IAAI,eAAe,CAAC;IAC7B,kDAAkD;IAClD,IAAI,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CACjD"}