nandi/oripublic Fork 0
f5c963af3c1597c0274ce4a99705dbd92a7d1cba
Commits
Clone
git clone https://git.rickub.com/nandi/ori.git
git clone ssh://git@rickub.com/nandi/ori.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

forked from bots-garden/ori

api.ts · 93 lines · 2.7 KBTypeScript Blame HistoryRaw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/**
 * Client for the backend's workspace file API (see internal/files and the
 * WebSocket/CLI references in docs/). All functions throw an Error carrying
 * the server's message when the request fails.
 *
 * @example
 * const { entries } = await listFiles();          // workspace root
 * const { content } = await readFile(entries[0].path);
 * await writeFile("notes.txt", "hello");
 */

/** One file matched by the recursive search. */
export interface FileHit {
	name: string;
	/** Absolute path, usable in further API calls. */
	path: string;
	/** Path relative to the workspace root, with forward slashes. */
	relPath: string;
}

/** One Claude Code skill discovered on disk. */
export interface Skill {
	name: string;
	description: string;
	path: string;
	source: "project" | "user";
}

/** One child of a listed directory. */
export interface FileEntry {
	name: string;
	path: string;
	isDir: boolean;
	size: number;
}

async function requestJSON<T>(input: string, init?: RequestInit): Promise<T> {
	const response = await fetch(input, init);
	const payload = (await response.json()) as T & { error?: string };
	if (!response.ok) {
		throw new Error(
			payload.error ?? `request failed with status ${response.status}`,
		);
	}
	return payload;
}

/** listFiles returns the entries of a directory (workspace root when omitted). */
export function listFiles(
	path?: string,
): Promise<{ path: string; entries: FileEntry[] }> {
	const query = path ? `?path=${encodeURIComponent(path)}` : "";
	return requestJSON(`/api/files${query}`);
}

/**
 * searchFiles returns the workspace files whose relative path contains the
 * query (case-insensitive), recursively, at most `limit` of them.
 */
export function searchFiles(
	query: string,
	limit = 50,
): Promise<{ root: string; files: FileHit[] }> {
	return requestJSON(
		`/api/files/search?q=${encodeURIComponent(query)}&limit=${limit}`,
	);
}

/** listSkills returns the skills of the project and of the user. */
export function listSkills(): Promise<{ skills: Skill[] }> {
	return requestJSON("/api/skills");
}

/** rawFileUrl is the URL streaming a file's bytes (images, downloads). */
export function rawFileUrl(path: string): string {
	return `/api/raw?path=${encodeURIComponent(path)}`;
}

/** readFile returns a text file's content. */
export function readFile(
	path: string,
): Promise<{ path: string; content: string }> {
	return requestJSON(`/api/file?path=${encodeURIComponent(path)}`);
}

/** writeFile saves content to a file, creating parent directories as needed. */
export async function writeFile(path: string, content: string): Promise<void> {
	await requestJSON(`/api/file?path=${encodeURIComponent(path)}`, {
		method: "PUT",
		headers: { "Content-Type": "application/json" },
		body: JSON.stringify({ content }),
	});
}