Skip to content

Commit 20129a0

Browse files
committed
feat(sdk): add typed TypeScript client
1 parent 9930304 commit 20129a0

29 files changed

Lines changed: 6760 additions & 52 deletions

.github/workflows/ci.yml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ jobs:
8080
- uses: pnpm/action-setup@v6
8181
- uses: actions/setup-node@v7
8282
with:
83-
node-version: 24
83+
node-version: 22
8484
cache: pnpm
8585
- run: pnpm install --frozen-lockfile --filter @lockintime/headless
8686
- run: pnpm --filter @lockintime/headless test
@@ -144,10 +144,23 @@ jobs:
144144
timeout-minutes: 45
145145
steps:
146146
- uses: actions/checkout@v7
147+
- uses: pnpm/action-setup@v6
148+
- uses: actions/setup-node@v7
149+
with:
150+
node-version: 22
151+
cache: pnpm
152+
- run: pnpm install --frozen-lockfile --filter @lockintime/headless
147153
- name: Build app
148154
run: ./apps/headless/build.sh
149155
- name: Protocol and security tests
150156
run: ./apps/headless/test.sh
157+
- name: Build TypeScript SDK
158+
run: pnpm --filter @lockintime/headless build
159+
- name: Swift CLI to TypeScript SDK integration
160+
env:
161+
HEADLESS_TEST_CLI: ${{ github.workspace }}/apps/headless/Headless.app/Contents/Resources/bin/headless
162+
HEADLESS_TEST_HOST: ${{ github.workspace }}/apps/headless/Headless.app/Contents/MacOS/Headless
163+
run: node packages/headless-npm/test/macos-swift-integration.mjs
151164

152165
macos-e2e:
153166
name: macOS E2E (WKWebView)

.github/workflows/release.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ jobs:
103103
- uses: pnpm/action-setup@v6
104104
- uses: actions/setup-node@v7
105105
with:
106-
node-version: 24
106+
node-version: 22
107107
cache: pnpm
108108
- run: pnpm install --frozen-lockfile --filter @lockintime/headless
109109
- run: pnpm --filter @lockintime/headless test
@@ -416,10 +416,13 @@ jobs:
416416
id-token: write
417417
steps:
418418
- uses: actions/checkout@v7
419+
- uses: pnpm/action-setup@v6
419420
- uses: actions/setup-node@v7
420421
with:
421-
node-version: 24
422+
node-version: 22
422423
registry-url: https://registry.npmjs.org
424+
cache: pnpm
425+
- run: pnpm install --frozen-lockfile --filter @lockintime/headless
423426
- name: Publish verified launcher
424427
working-directory: packages/headless-npm
425428
env:

packages/headless-npm/LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
MIT License
2+
3+
Copyright (c) 2026 LockInTime
4+
Copyright (c) 2026 Antiwork, Inc. (original chromeless foundation)
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in all
14+
copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
SOFTWARE.

packages/headless-npm/README.md

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
# `@lockintime/headless`
22

3-
Verified npm launcher for the [Headless agent browser](https://github.com/LockInTime/headless).
3+
Typed Node.js SDK and verified npm launcher for the
4+
[Headless agent browser](https://github.com/LockInTime/headless). Node.js 22 or
5+
newer is required. The SDK has no runtime dependencies and talks directly to
6+
Headless over its private per-user Unix socket. It does not start a network
7+
service or use MCP as an internal transport.
8+
9+
## CLI launcher
410

511
```sh
612
npx @lockintime/headless help
@@ -15,3 +21,70 @@ plus Linux x86_64 and arm64. Windows users should use the published GHCR image.
1521

1622
Set `HEADLESS_NPM_CACHE` to an absolute directory to move the verified cache.
1723
The release download origin is fixed and cannot be overridden.
24+
25+
Because this package distributes both the SDK and verified product launcher,
26+
its version follows Headless product tags. The supported wire and schema
27+
versions remain independent and are pinned in the generated SDK contract.
28+
29+
## Connect to a shared host
30+
31+
Replace repeated CLI calls with typed methods. Closing this client closes only
32+
its active socket requests. It never stops a shared Headless host.
33+
34+
```ts
35+
import { connect } from "@lockintime/headless";
36+
37+
// CLI: headless status
38+
await using headless = await connect();
39+
40+
// CLI: headless visit https://example.com
41+
const page = await headless.visit({ url: "https://example.com" });
42+
if (page.untrustedContent) {
43+
console.log(page.value.title);
44+
}
45+
```
46+
47+
Every page-derived result is returned as `Untrusted<T>`. Callers must preserve
48+
that trust marker when sending page content to an agent or another system.
49+
50+
## Supervised host
51+
52+
Use `launch()` when this process must own a new host. It invokes the installed
53+
CLI with `headless start --background --supervised`, keeps the ownership pipe
54+
open, verifies that the startup response and socket report the same host PID,
55+
and reaps only that launcher during disposal. It fails rather than claiming an
56+
already-running shared host.
57+
58+
```ts
59+
import { launch } from "@lockintime/headless";
60+
61+
await using host = await launch({
62+
allow: ["example.com"],
63+
installationTimeoutMs: 300_000,
64+
startupTimeoutMs: 10_000,
65+
});
66+
67+
const session = await host.client.openSession("research", { isolated: true });
68+
await using scoped = session;
69+
const snapshot = await scoped.inspect({ context: "actions" });
70+
```
71+
72+
Session helpers expose only session-scoped commands. Host lifecycle and session
73+
creation remain on `HeadlessClient`.
74+
75+
## Cancellation and authentication
76+
77+
Methods accept `{ signal, timeoutMs }` as their final argument. Cancellation or
78+
timeout before any request byte is written is retry-safe. After a write,
79+
`OperationOutcomeUnknown` means the SDK cannot know whether the browser action
80+
completed. Never retry it automatically; inspect browser state first.
81+
82+
Saved-login methods accept only a challenge ID and account alias. There is no
83+
password parameter in the authentication API:
84+
85+
```ts
86+
await scoped.authLogin({
87+
challenge: "11111111-1111-4111-8111-111111111111",
88+
account: "work",
89+
});
90+
```
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
export interface InstalledRelease {
2+
readonly directory: string;
3+
readonly release: {
4+
readonly executable: string;
5+
};
6+
}
7+
8+
export interface InstallOptions {
9+
readonly cacheRoot?: string;
10+
readonly signal?: AbortSignal;
11+
}
12+
13+
export function defaultCacheRoot(
14+
platform?: NodeJS.Platform,
15+
environment?: NodeJS.ProcessEnv,
16+
): string;
17+
18+
export function ensureInstalled(options?: InstallOptions): Promise<InstalledRelease>;

0 commit comments

Comments
 (0)