capyai 0.2.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/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "capyai",
3
+ "version": "0.2.0",
4
+ "type": "module",
5
+ "description": "Unofficial Capy.ai CLI for agent orchestration with quality gates",
6
+ "bin": {
7
+ "capy": "./bin/capy.js"
8
+ },
9
+ "scripts": {
10
+ "build": "bun build bin/capy.ts --outdir dist --target node",
11
+ "prepublishOnly": "bun run build"
12
+ },
13
+ "files": [
14
+ "bin/",
15
+ "src/",
16
+ "dist/"
17
+ ],
18
+ "engines": {
19
+ "node": ">=18"
20
+ },
21
+ "devDependencies": {
22
+ "@types/bun": "latest"
23
+ },
24
+ "license": "MIT",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/PlawIO/capy-cli"
28
+ },
29
+ "keywords": [
30
+ "capy",
31
+ "ai",
32
+ "coding-agent",
33
+ "orchestration",
34
+ "cli"
35
+ ]
36
+ }
package/src/api.ts ADDED
@@ -0,0 +1,125 @@
1
+ import * as config from "./config.js";
2
+ import type { Task, Thread, ThreadMessage, DiffData, Model, ListResponse, PullRequestRef } from "./types.js";
3
+
4
+ async function request(method: string, path: string, body?: unknown): Promise<any> {
5
+ const cfg = config.load();
6
+ if (!cfg.apiKey) {
7
+ console.error("capy: API key not configured. Run: capy init");
8
+ process.exit(1);
9
+ }
10
+ const url = `${cfg.server}${path}`;
11
+ const headers: Record<string, string> = {
12
+ "Authorization": `Bearer ${cfg.apiKey}`,
13
+ "Accept": "application/json",
14
+ };
15
+ const init: RequestInit = { method, headers };
16
+ if (body) {
17
+ headers["Content-Type"] = "application/json";
18
+ init.body = JSON.stringify(body);
19
+ }
20
+
21
+ let res: Response;
22
+ try {
23
+ res = await fetch(url, init);
24
+ } catch (e: unknown) {
25
+ console.error(`capy: request failed — ${(e as Error).message}`);
26
+ process.exit(1);
27
+ }
28
+
29
+ const text = await res.text();
30
+ try {
31
+ const data = JSON.parse(text);
32
+ if (data.error) {
33
+ console.error(`capy: API error — ${data.error.message || data.error.code}`);
34
+ process.exit(1);
35
+ }
36
+ return data;
37
+ } catch {
38
+ console.error("capy: bad API response:", text.slice(0, 200));
39
+ process.exit(1);
40
+ }
41
+ }
42
+
43
+ // --- Threads ---
44
+ export async function createThread(prompt: string, model?: string, repos?: unknown[]): Promise<Thread> {
45
+ const cfg = config.load();
46
+ return request("POST", "/threads", {
47
+ projectId: cfg.projectId,
48
+ prompt,
49
+ model: model || cfg.defaultModel,
50
+ repos: repos || cfg.repos,
51
+ });
52
+ }
53
+
54
+ export async function listThreads(opts: { limit?: number; status?: string } = {}): Promise<ListResponse<Thread>> {
55
+ const cfg = config.load();
56
+ const p = new URLSearchParams({ projectId: cfg.projectId, limit: String(opts.limit || 10) });
57
+ if (opts.status) p.set("status", opts.status);
58
+ return request("GET", `/threads?${p}`);
59
+ }
60
+
61
+ export async function getThread(id: string): Promise<Thread> {
62
+ return request("GET", `/threads/${id}`);
63
+ }
64
+
65
+ export async function messageThread(id: string, msg: string): Promise<unknown> {
66
+ return request("POST", `/threads/${id}/message`, { message: msg });
67
+ }
68
+
69
+ export async function stopThread(id: string): Promise<unknown> {
70
+ return request("POST", `/threads/${id}/stop`);
71
+ }
72
+
73
+ export async function getThreadMessages(id: string, opts: { limit?: number } = {}): Promise<ListResponse<ThreadMessage>> {
74
+ const p = new URLSearchParams({ limit: String(opts.limit || 50) });
75
+ return request("GET", `/threads/${id}/messages?${p}`);
76
+ }
77
+
78
+ // --- Tasks ---
79
+ export async function createTask(prompt: string, model?: string, opts: { title?: string; start?: boolean; labels?: string[] } = {}): Promise<Task> {
80
+ const cfg = config.load();
81
+ return request("POST", "/tasks", {
82
+ projectId: cfg.projectId,
83
+ prompt,
84
+ title: (opts.title || prompt).slice(0, 80),
85
+ repos: cfg.repos,
86
+ model: model || cfg.defaultModel,
87
+ start: opts.start !== false,
88
+ ...(opts.labels ? { labels: opts.labels } : {}),
89
+ });
90
+ }
91
+
92
+ export async function listTasks(opts: { limit?: number; status?: string } = {}): Promise<ListResponse<Task>> {
93
+ const cfg = config.load();
94
+ const p = new URLSearchParams({ projectId: cfg.projectId, limit: String(opts.limit || 30) });
95
+ if (opts.status) p.set("status", opts.status);
96
+ return request("GET", `/tasks?${p}`);
97
+ }
98
+
99
+ export async function getTask(id: string): Promise<Task> {
100
+ return request("GET", `/tasks/${id}`);
101
+ }
102
+
103
+ export async function startTask(id: string, model?: string): Promise<Task> {
104
+ return request("POST", `/tasks/${id}/start`, { model: model || config.load().defaultModel });
105
+ }
106
+
107
+ export async function stopTask(id: string, reason?: string): Promise<Task> {
108
+ return request("POST", `/tasks/${id}/stop`, reason ? { reason } : {});
109
+ }
110
+
111
+ export async function messageTask(id: string, msg: string): Promise<unknown> {
112
+ return request("POST", `/tasks/${id}/message`, { message: msg });
113
+ }
114
+
115
+ export async function createPR(id: string, opts: Record<string, unknown> = {}): Promise<PullRequestRef & { url?: string; number?: number; title?: string; headRef?: string; baseRef?: string }> {
116
+ return request("POST", `/tasks/${id}/pr`, opts);
117
+ }
118
+
119
+ export async function getDiff(id: string, mode = "run"): Promise<DiffData> {
120
+ return request("GET", `/tasks/${id}/diff?mode=${mode}`);
121
+ }
122
+
123
+ export async function listModels(): Promise<{ models?: Model[] }> {
124
+ return request("GET", "/models");
125
+ }