auto-harness-client 0.1.0
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/LICENSE +9 -0
- package/README.md +21 -0
- package/package.json +33 -0
- package/src/index.d.ts +54 -0
- package/src/index.js +71 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Auto Harness contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
package/README.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# `auto-harness-client`
|
|
2
|
+
|
|
3
|
+
Dependency-free Node client for Auto Harness automation. Calls return after the control plane
|
|
4
|
+
accepts work; they do not wait for the agent session to finish.
|
|
5
|
+
|
|
6
|
+
```js
|
|
7
|
+
import { AutoHarnessClient } from "auto-harness-client";
|
|
8
|
+
|
|
9
|
+
const harness = new AutoHarnessClient({
|
|
10
|
+
baseUrl: process.env.AUTO_HARNESS_URL,
|
|
11
|
+
apiKey: process.env.AUTO_HARNESS_API_KEY,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const session = await harness.createSession({
|
|
15
|
+
repositoryId: "repo-1",
|
|
16
|
+
prompt: "Review the latest changes",
|
|
17
|
+
target: { providerId: "codex" },
|
|
18
|
+
concurrencyId: `github-${process.env.GITHUB_RUN_ID}`,
|
|
19
|
+
});
|
|
20
|
+
console.log(session.url);
|
|
21
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "auto-harness-client",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Dependency-free client for the Auto Harness automation API",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/jonathanong/auto-harness.git",
|
|
8
|
+
"directory": "modules/client"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"LICENSE",
|
|
12
|
+
"README.md",
|
|
13
|
+
"src"
|
|
14
|
+
],
|
|
15
|
+
"type": "module",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./src/index.d.ts",
|
|
19
|
+
"import": "./src/index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public",
|
|
24
|
+
"provenance": true
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"test": "node --test test/*.test.js",
|
|
28
|
+
"typecheck": "tsc -p tsconfig.json"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=20"
|
|
32
|
+
}
|
|
33
|
+
}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export type TargetRef =
|
|
2
|
+
| { commandId: string; providerId?: never }
|
|
3
|
+
| { providerId: string; commandId?: never };
|
|
4
|
+
|
|
5
|
+
export type CreateSessionInput = {
|
|
6
|
+
repositoryId: string;
|
|
7
|
+
prompt: string;
|
|
8
|
+
target: TargetRef;
|
|
9
|
+
fallbacks?: TargetRef[];
|
|
10
|
+
ref?: string;
|
|
11
|
+
concurrencyId?: string;
|
|
12
|
+
queueTtlSeconds?: number;
|
|
13
|
+
timeout?: number;
|
|
14
|
+
priority?: number;
|
|
15
|
+
requiredLabels?: string[];
|
|
16
|
+
metadata?: Record<string, unknown>;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type Session = CreateSessionInput & {
|
|
20
|
+
id: string;
|
|
21
|
+
status: string;
|
|
22
|
+
createdAt: string;
|
|
23
|
+
url: string;
|
|
24
|
+
created?: boolean;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type Repository = {
|
|
28
|
+
id: string;
|
|
29
|
+
name: string;
|
|
30
|
+
url: string;
|
|
31
|
+
defaultBranch: string;
|
|
32
|
+
admissionState?: "active" | "paused" | "draining";
|
|
33
|
+
admissionStateChangedAt?: string;
|
|
34
|
+
drainRequestedAt?: string;
|
|
35
|
+
drainCompletedAt?: string;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export class AutoHarnessError extends Error {
|
|
39
|
+
status: number;
|
|
40
|
+
code: string;
|
|
41
|
+
retryAfter?: string;
|
|
42
|
+
constructor(message: string, options: { status: number; code: string; retryAfter?: string });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class AutoHarnessClient {
|
|
46
|
+
constructor(options: { baseUrl: string; apiKey?: string; fetch?: typeof fetch });
|
|
47
|
+
createSession(input: CreateSessionInput): Promise<Session & { created: boolean }>;
|
|
48
|
+
getSession(id: string): Promise<Session>;
|
|
49
|
+
cancelSession(id: string): Promise<Session>;
|
|
50
|
+
listRepositories(): Promise<{ items: Repository[] }>;
|
|
51
|
+
pauseRepository(id: string): Promise<Repository>;
|
|
52
|
+
drainRepository(id: string): Promise<Repository>;
|
|
53
|
+
activateRepository(id: string): Promise<Repository>;
|
|
54
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export class AutoHarnessError extends Error {
|
|
2
|
+
constructor(message, options) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.name = "AutoHarnessError";
|
|
5
|
+
this.status = options.status;
|
|
6
|
+
this.code = options.code;
|
|
7
|
+
this.retryAfter = options.retryAfter;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class AutoHarnessClient {
|
|
12
|
+
constructor(options) {
|
|
13
|
+
if (!options?.baseUrl) throw new TypeError("baseUrl is required");
|
|
14
|
+
this.baseUrl = options.baseUrl.replace(/\/$/, "").replace(/\/api\/v1$/, "");
|
|
15
|
+
this.apiKey = options.apiKey;
|
|
16
|
+
this.fetch = options.fetch ?? globalThis.fetch;
|
|
17
|
+
if (!this.fetch) throw new TypeError("fetch is required");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async request(path, init = {}) {
|
|
21
|
+
const headers = { accept: "application/json", ...init.headers };
|
|
22
|
+
if (init.body !== undefined) headers["content-type"] = "application/json";
|
|
23
|
+
if (this.apiKey) headers.authorization = `Bearer ${this.apiKey}`;
|
|
24
|
+
const response = await this.fetch(`${this.baseUrl}/api/v1${path}`, { ...init, headers });
|
|
25
|
+
const body = response.status === 204 ? undefined : await response.json().catch(() => undefined);
|
|
26
|
+
if (!response.ok) {
|
|
27
|
+
const error = body?.error;
|
|
28
|
+
throw new AutoHarnessError(
|
|
29
|
+
error?.message ?? `Auto Harness request failed (${response.status})`,
|
|
30
|
+
{
|
|
31
|
+
status: response.status,
|
|
32
|
+
code: error?.code ?? "HTTP_ERROR",
|
|
33
|
+
retryAfter: response.headers.get("retry-after") ?? undefined,
|
|
34
|
+
},
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
return body;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
createSession(input) {
|
|
41
|
+
return this.request("/sessions", { method: "POST", body: JSON.stringify(input) });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
getSession(id) {
|
|
45
|
+
return this.request(`/sessions/${encodeURIComponent(id)}`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
cancelSession(id) {
|
|
49
|
+
return this.request(`/sessions/${encodeURIComponent(id)}/cancel`, { method: "POST" });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
listRepositories() {
|
|
53
|
+
return this.request("/repositories");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
pauseRepository(id) {
|
|
57
|
+
return this.repositoryOperation(id, "pause");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
drainRepository(id) {
|
|
61
|
+
return this.repositoryOperation(id, "drain");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
activateRepository(id) {
|
|
65
|
+
return this.repositoryOperation(id, "activate");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
repositoryOperation(id, operation) {
|
|
69
|
+
return this.request(`/repositories/${encodeURIComponent(id)}/${operation}`, { method: "POST" });
|
|
70
|
+
}
|
|
71
|
+
}
|