@heyditto/cli 2.0.1 → 2.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.
Files changed (46) hide show
  1. package/README.md +167 -1
  2. package/dist/agents/claude.d.ts +11 -0
  3. package/dist/agents/claude.js +48 -0
  4. package/dist/agents/claude.js.map +1 -0
  5. package/dist/agents/codex.d.ts +13 -0
  6. package/dist/agents/codex.js +48 -0
  7. package/dist/agents/codex.js.map +1 -0
  8. package/dist/agents/launch.d.ts +25 -0
  9. package/dist/agents/launch.js +376 -0
  10. package/dist/agents/launch.js.map +1 -0
  11. package/dist/agents/sessions.d.ts +28 -0
  12. package/dist/agents/sessions.js +63 -0
  13. package/dist/agents/sessions.js.map +1 -0
  14. package/dist/agents/types.d.ts +50 -0
  15. package/dist/agents/types.js +44 -0
  16. package/dist/agents/types.js.map +1 -0
  17. package/dist/agents/worktree.d.ts +19 -0
  18. package/dist/agents/worktree.js +72 -0
  19. package/dist/agents/worktree.js.map +1 -0
  20. package/dist/api.d.ts +178 -0
  21. package/dist/api.js +163 -0
  22. package/dist/api.js.map +1 -0
  23. package/dist/browser.d.ts +2 -0
  24. package/dist/browser.js +17 -0
  25. package/dist/browser.js.map +1 -0
  26. package/dist/cli.js +107 -24
  27. package/dist/cli.js.map +1 -1
  28. package/dist/commands.d.ts +77 -0
  29. package/dist/commands.js +638 -0
  30. package/dist/commands.js.map +1 -0
  31. package/dist/config.d.ts +8 -0
  32. package/dist/config.js +18 -1
  33. package/dist/config.js.map +1 -1
  34. package/dist/device-login.d.ts +28 -0
  35. package/dist/device-login.js +43 -0
  36. package/dist/device-login.js.map +1 -0
  37. package/dist/endpoint-format.d.ts +9 -0
  38. package/dist/endpoint-format.js +21 -0
  39. package/dist/endpoint-format.js.map +1 -0
  40. package/dist/mcp-session.d.ts +40 -0
  41. package/dist/mcp-session.js +133 -0
  42. package/dist/mcp-session.js.map +1 -0
  43. package/dist/store.d.ts +26 -0
  44. package/dist/store.js +61 -0
  45. package/dist/store.js.map +1 -1
  46. package/package.json +1 -1
@@ -0,0 +1,72 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { appendFile, mkdir, readFile } from "node:fs/promises";
3
+ import path from "node:path";
4
+ /** Folder inside the repository that holds the CLI's worktrees (kept out of git). */
5
+ export const WORKTREES_DIR = ".worktrees";
6
+ function pad(n) {
7
+ return String(n).padStart(2, "0");
8
+ }
9
+ /** `<harness>-<yyyymmdd-hhmm>`, e.g. `claude-20260904-1530`. */
10
+ export function defaultWorktreeName(harness, now = new Date()) {
11
+ const stamp = `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}` +
12
+ `-${pad(now.getHours())}${pad(now.getMinutes())}`;
13
+ return `${harness}-${stamp}`;
14
+ }
15
+ export function validWorktreeName(name) {
16
+ return /^[A-Za-z0-9][A-Za-z0-9._\/-]{0,80}$/.test(name) && !name.includes("..");
17
+ }
18
+ function git(args, cwd) {
19
+ const res = spawnSync("git", args, { cwd, encoding: "utf8" });
20
+ return { ok: res.status === 0, out: (res.stdout ?? "").trim(), err: (res.stderr ?? "").trim() };
21
+ }
22
+ export function repoRoot(cwd) {
23
+ const res = git(["rev-parse", "--show-toplevel"], cwd);
24
+ return res.ok && res.out ? res.out : undefined;
25
+ }
26
+ /** Adds `.worktrees/` to the repo root .gitignore when it is not already listed. */
27
+ export async function ensureGitignore(root) {
28
+ const file = path.join(root, ".gitignore");
29
+ let current = "";
30
+ try {
31
+ current = await readFile(file, "utf8");
32
+ }
33
+ catch (err) {
34
+ if (err.code !== "ENOENT")
35
+ throw err;
36
+ }
37
+ const listed = current
38
+ .split(/\r?\n/)
39
+ .map((l) => l.trim())
40
+ .some((l) => l === WORKTREES_DIR || l === `${WORKTREES_DIR}/` || l === `/${WORKTREES_DIR}` || l === `/${WORKTREES_DIR}/`);
41
+ if (listed)
42
+ return false;
43
+ const prefix = current.length > 0 && !current.endsWith("\n") ? "\n" : "";
44
+ await appendFile(file, `${prefix}# Coding-agent worktrees created by heyditto\n${WORKTREES_DIR}/\n`);
45
+ return true;
46
+ }
47
+ /**
48
+ * Creates (or reuses) `<repo>/.worktrees/<name>` on a branch of the same
49
+ * name, mirroring how Claude Code keeps worktrees inside the repository.
50
+ */
51
+ export async function ensureWorktree(cwd, name) {
52
+ const root = repoRoot(cwd);
53
+ if (!root)
54
+ throw new Error(`--worktree needs a git repository (no repo found at ${cwd})`);
55
+ if (!validWorktreeName(name))
56
+ throw new Error(`invalid worktree name: ${name}`);
57
+ await ensureGitignore(root);
58
+ const dir = path.join(root, WORKTREES_DIR, name);
59
+ await mkdir(path.dirname(dir), { recursive: true });
60
+ const existing = git(["worktree", "list", "--porcelain"], root);
61
+ if (existing.ok && existing.out.split("\n").includes(`worktree ${dir}`)) {
62
+ return { path: dir, branch: name, created: false };
63
+ }
64
+ const branchExists = git(["show-ref", "--verify", "--quiet", `refs/heads/${name}`], root).ok;
65
+ const add = branchExists
66
+ ? git(["worktree", "add", dir, name], root)
67
+ : git(["worktree", "add", "-b", name, dir], root);
68
+ if (!add.ok)
69
+ throw new Error(`git worktree add failed: ${add.err || add.out}`);
70
+ return { path: dir, branch: name, created: true };
71
+ }
72
+ //# sourceMappingURL=worktree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.js","sourceRoot":"","sources":["../../src/agents/worktree.ts"],"names":[],"mappings":"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"}
package/dist/api.d.ts ADDED
@@ -0,0 +1,178 @@
1
+ /** Minimal authenticated REST client for the Ditto management API. */
2
+ export declare class ApiError extends Error {
3
+ status: number;
4
+ body: string;
5
+ constructor(message: string, status: number, body: string);
6
+ }
7
+ export declare function apiBase(): string;
8
+ /** Shared "not logged in" message: browser login first, then the alternatives. */
9
+ export declare const NO_KEY_MESSAGE: string;
10
+ export declare function apiFetch<T>(path: string, init?: {
11
+ method?: string;
12
+ body?: unknown;
13
+ auth?: boolean;
14
+ }): Promise<T>;
15
+ export type EndpointStatus = "active" | "pending_plan";
16
+ /** Backend-controlled copy explaining why an endpoint cannot serve requests yet. */
17
+ export interface EndpointActivation {
18
+ state: string;
19
+ reason: "agent_unclaimed" | "plan_required" | string;
20
+ requiredTier?: number;
21
+ requiredTierName?: string;
22
+ priceHint?: string;
23
+ message: string;
24
+ /** Link to hand to the user; for agent accounts the CLI adds the claim token (see mergeActivationURL). */
25
+ url?: string;
26
+ }
27
+ export interface InferenceEndpoint {
28
+ id: string;
29
+ slug: string;
30
+ name: string;
31
+ model: string;
32
+ systemPrompt?: string;
33
+ spendPeriod?: string;
34
+ spendLimitTokens?: number | null;
35
+ spentTokens?: number;
36
+ memoryDepth?: number;
37
+ maxToolRounds?: number;
38
+ recordTrace?: boolean;
39
+ recordAttachments?: boolean;
40
+ recallEnabled?: boolean;
41
+ recordEnabled?: boolean;
42
+ tools?: string[];
43
+ modelMode?: string;
44
+ billingMode?: string;
45
+ status?: EndpointStatus | string;
46
+ activation?: EndpointActivation;
47
+ createdAt?: string;
48
+ updatedAt?: string;
49
+ }
50
+ /** Partial body for POST / PATCH /api/v5/inference/endpoints. */
51
+ export interface EndpointInput {
52
+ name?: string;
53
+ slug?: string;
54
+ model?: string;
55
+ systemPrompt?: string;
56
+ spendLimitTokens?: number | null;
57
+ spendPeriod?: string;
58
+ recordTrace?: boolean;
59
+ recallEnabled?: boolean;
60
+ recordEnabled?: boolean;
61
+ memoryDepth?: number;
62
+ }
63
+ export declare function isEndpointPending(e: InferenceEndpoint): boolean;
64
+ export interface InferenceEndpointsResponse {
65
+ baseUrl: string;
66
+ endpoints: InferenceEndpoint[];
67
+ limit?: number;
68
+ used?: number;
69
+ }
70
+ export declare function listEndpoints(): Promise<InferenceEndpointsResponse>;
71
+ export declare function createEndpoint(input?: EndpointInput): Promise<InferenceEndpoint>;
72
+ export declare function updateEndpoint(id: string, patch: EndpointInput): Promise<InferenceEndpoint>;
73
+ export declare function deleteEndpoint(id: string): Promise<void>;
74
+ /** Finds one endpoint by slug or id from the catalog (there is no GET-by-id route). */
75
+ export declare function findEndpoint(endpoints: InferenceEndpoint[], ref: string): InferenceEndpoint | undefined;
76
+ export declare function getEndpoint(ref: string): Promise<{
77
+ endpoint: InferenceEndpoint;
78
+ catalog: InferenceEndpointsResponse;
79
+ }>;
80
+ export declare function listKeys(endpointId: string): Promise<InferenceKey[]>;
81
+ export interface InferenceKey {
82
+ id: string;
83
+ endpointId: string;
84
+ name: string;
85
+ keyHint: string;
86
+ key?: string;
87
+ expiresAt?: string | null;
88
+ spendLimitTokens?: number | null;
89
+ spendPeriod?: string;
90
+ spentTokens?: number;
91
+ createdAt?: string;
92
+ lastUsedAt?: string | null;
93
+ revokedAt?: string | null;
94
+ }
95
+ export interface CreateKeyInput {
96
+ name: string;
97
+ expiresIn: string;
98
+ spendLimitTokens?: number;
99
+ spendPeriod?: string;
100
+ }
101
+ export declare function createKey(endpointId: string, input: CreateKeyInput): Promise<InferenceKey>;
102
+ export declare function revokeKey(endpointId: string, keyId: string): Promise<void>;
103
+ export interface InferenceSession {
104
+ id: string;
105
+ endpointId: string;
106
+ sessionKey: string;
107
+ threadId?: string;
108
+ harness?: string;
109
+ model?: string;
110
+ turnCount?: number;
111
+ firstSeenAt?: string;
112
+ lastSeenAt?: string;
113
+ }
114
+ export declare function listRemoteSessions(endpointId: string): Promise<InferenceSession[]>;
115
+ /** What the CLI was asked to do; the web page specializes its onboarding on it. */
116
+ export type DeviceIntent = "login" | "claude" | "codex";
117
+ export declare const DEVICE_CLIENT = "heyditto-cli";
118
+ export interface DeviceCode {
119
+ device_code: string;
120
+ user_code: string;
121
+ verification_url: string;
122
+ /** Backend-built URL carrying the code and the intent (RFC 8628 §3.3.1). */
123
+ verification_uri_complete?: string;
124
+ expires_in: number;
125
+ interval: number;
126
+ }
127
+ export declare function requestDeviceCode(input: {
128
+ intent: DeviceIntent;
129
+ }): Promise<DeviceCode>;
130
+ /** Endpoint the browser picked for the CLI during the device flow. */
131
+ export interface SelectedEndpoint {
132
+ id: string;
133
+ slug: string;
134
+ name?: string;
135
+ model?: string;
136
+ }
137
+ export type DeviceTokenResult = {
138
+ status: "ok";
139
+ accessToken: string;
140
+ endpoint?: SelectedEndpoint;
141
+ setDefault?: boolean;
142
+ } | {
143
+ status: "pending";
144
+ } | {
145
+ status: "slow_down";
146
+ } | {
147
+ status: "denied";
148
+ } | {
149
+ status: "expired";
150
+ };
151
+ export declare function pollDeviceToken(deviceCode: string): Promise<DeviceTokenResult>;
152
+ export interface AgentConnection {
153
+ id: string;
154
+ agentId: string;
155
+ kind: string;
156
+ refId: string;
157
+ name: string;
158
+ sessionCooldownSeconds?: number;
159
+ createdAt: string;
160
+ lastUsedAt?: string | null;
161
+ expiresAt?: string | null;
162
+ revokedAt?: string | null;
163
+ }
164
+ export interface ChatAgent {
165
+ id: string;
166
+ kind: string;
167
+ name: string;
168
+ mainThreadId: string;
169
+ kgId?: string;
170
+ status: string;
171
+ pinned?: boolean;
172
+ threadCount?: number;
173
+ lastActivityAt?: string | null;
174
+ createdAt: string;
175
+ updatedAt: string;
176
+ connections?: AgentConnection[];
177
+ }
178
+ export declare function listChatAgents(): Promise<ChatAgent[]>;
package/dist/api.js ADDED
@@ -0,0 +1,163 @@
1
+ import os from "node:os";
2
+ import { packageName, packageVersion, resolveApiKey } from "./config.js";
3
+ /** Minimal authenticated REST client for the Ditto management API. */
4
+ export class ApiError extends Error {
5
+ status;
6
+ body;
7
+ constructor(message, status, body) {
8
+ super(message);
9
+ this.name = "ApiError";
10
+ this.status = status;
11
+ this.body = body;
12
+ }
13
+ }
14
+ export function apiBase() {
15
+ return (process.env.DITTO_API_BASE || "https://api.heyditto.ai").replace(/\/+$/, "");
16
+ }
17
+ function userAgent() {
18
+ return `${packageName}/${packageVersion}`;
19
+ }
20
+ /** Shared "not logged in" message: browser login first, then the alternatives. */
21
+ export const NO_KEY_MESSAGE = "no Ditto API key configured.\n\n" +
22
+ " Run: heyditto login (opens your browser)\n" +
23
+ " Or: heyditto login <key> (save an existing key)\n" +
24
+ " Or: heyditto init --json (create a claimable agent account, no browser)\n";
25
+ async function requireKey() {
26
+ const { key } = await resolveApiKey();
27
+ if (!key)
28
+ throw new Error(NO_KEY_MESSAGE);
29
+ return key;
30
+ }
31
+ export async function apiFetch(path, init = {}) {
32
+ const headers = {
33
+ Accept: "application/json",
34
+ "User-Agent": userAgent(),
35
+ };
36
+ if (init.body !== undefined)
37
+ headers["Content-Type"] = "application/json";
38
+ if (init.auth !== false)
39
+ headers.Authorization = `Bearer ${await requireKey()}`;
40
+ const response = await fetch(`${apiBase()}${path}`, {
41
+ method: init.method ?? "GET",
42
+ headers,
43
+ body: init.body === undefined ? undefined : JSON.stringify(init.body),
44
+ });
45
+ if (!response.ok) {
46
+ const text = await response.text().catch(() => "");
47
+ let detail = text;
48
+ try {
49
+ const parsed = JSON.parse(text);
50
+ detail = parsed.message || parsed.error || text;
51
+ }
52
+ catch {
53
+ /* raw body */
54
+ }
55
+ const hint = response.status === 401
56
+ ? " (is the saved key valid? run `heyditto login`)"
57
+ : response.status === 403
58
+ ? " (the key is not allowed to manage inference endpoints)"
59
+ : "";
60
+ throw new ApiError(`${init.method ?? "GET"} ${path} failed: HTTP ${response.status}${detail ? ` - ${detail.slice(0, 300)}` : ""}${hint}`, response.status, text);
61
+ }
62
+ if (response.status === 204)
63
+ return undefined;
64
+ return (await response.json());
65
+ }
66
+ export function isEndpointPending(e) {
67
+ return e.status === "pending_plan" || (e.status !== undefined && e.status !== "active");
68
+ }
69
+ export async function listEndpoints() {
70
+ const res = await apiFetch("/api/v5/inference/endpoints");
71
+ return {
72
+ baseUrl: (res.baseUrl || `${apiBase()}/v1`).replace(/\/+$/, ""),
73
+ endpoints: res.endpoints ?? [],
74
+ limit: res.limit,
75
+ used: res.used,
76
+ };
77
+ }
78
+ const endpointsPath = "/api/v5/inference/endpoints";
79
+ function endpointPath(id) {
80
+ return `${endpointsPath}/${encodeURIComponent(id)}`;
81
+ }
82
+ export async function createEndpoint(input = {}) {
83
+ return apiFetch(endpointsPath, { method: "POST", body: input });
84
+ }
85
+ export async function updateEndpoint(id, patch) {
86
+ return apiFetch(endpointPath(id), { method: "PATCH", body: patch });
87
+ }
88
+ export async function deleteEndpoint(id) {
89
+ await apiFetch(endpointPath(id), { method: "DELETE" });
90
+ }
91
+ /** Finds one endpoint by slug or id from the catalog (there is no GET-by-id route). */
92
+ export function findEndpoint(endpoints, ref) {
93
+ const wanted = ref.trim();
94
+ return endpoints.find((e) => e.slug === wanted || e.id === wanted);
95
+ }
96
+ export async function getEndpoint(ref) {
97
+ const catalog = await listEndpoints();
98
+ const endpoint = findEndpoint(catalog.endpoints, ref);
99
+ if (!endpoint) {
100
+ throw new Error(`no endpoint named "${ref.trim()}". Available: ${catalog.endpoints.map((e) => e.slug).join(", ") || "(none — create one with `heyditto endpoints create`)"}`);
101
+ }
102
+ return { endpoint, catalog };
103
+ }
104
+ export async function listKeys(endpointId) {
105
+ const res = await apiFetch(`${endpointPath(endpointId)}/keys`);
106
+ return Array.isArray(res) ? res : (res.keys ?? []);
107
+ }
108
+ export async function createKey(endpointId, input) {
109
+ const key = await apiFetch(`/api/v5/inference/endpoints/${encodeURIComponent(endpointId)}/keys`, { method: "POST", body: input });
110
+ if (!key.key)
111
+ throw new Error("key creation succeeded but no plaintext key was returned");
112
+ return key;
113
+ }
114
+ export async function revokeKey(endpointId, keyId) {
115
+ await apiFetch(`/api/v5/inference/endpoints/${encodeURIComponent(endpointId)}/keys/${encodeURIComponent(keyId)}`, { method: "DELETE" });
116
+ }
117
+ export async function listRemoteSessions(endpointId) {
118
+ const res = await apiFetch(`/api/v5/inference/endpoints/${encodeURIComponent(endpointId)}/sessions`);
119
+ return res.sessions ?? [];
120
+ }
121
+ export const DEVICE_CLIENT = "heyditto-cli";
122
+ export async function requestDeviceCode(input) {
123
+ const res = await apiFetch("/api/v2/mcp/device-code", {
124
+ method: "POST",
125
+ body: {
126
+ client: DEVICE_CLIENT,
127
+ client_version: packageVersion,
128
+ intent: input.intent,
129
+ hostname: os.hostname().slice(0, 128),
130
+ },
131
+ auth: false,
132
+ });
133
+ if (!res.device_code || !res.user_code || !res.verification_url) {
134
+ throw new Error("device login is not available on this API (malformed device-code response)");
135
+ }
136
+ return res;
137
+ }
138
+ export async function pollDeviceToken(deviceCode) {
139
+ const res = await apiFetch("/api/v2/mcp/device-token", {
140
+ method: "POST",
141
+ auth: false,
142
+ body: { device_code: deviceCode, grant_type: "urn:ietf:params:oauth:grant-type:device_code" },
143
+ });
144
+ if (res.access_token) {
145
+ const endpoint = res.endpoint && res.endpoint.id && res.endpoint.slug ? res.endpoint : undefined;
146
+ return { status: "ok", accessToken: res.access_token, endpoint, setDefault: Boolean(res.set_default) };
147
+ }
148
+ switch (res.error) {
149
+ case "authorization_pending":
150
+ return { status: "pending" };
151
+ case "slow_down":
152
+ return { status: "slow_down" };
153
+ case "access_denied":
154
+ return { status: "denied" };
155
+ default:
156
+ return { status: "expired" };
157
+ }
158
+ }
159
+ export async function listChatAgents() {
160
+ const out = await apiFetch("/api/v5/chat-agents");
161
+ return out.agents ?? [];
162
+ }
163
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ /** Best-effort: open a URL in the user's default browser without blocking. */
2
+ export declare function openInBrowser(url: string): void;
@@ -0,0 +1,17 @@
1
+ import { spawn } from "node:child_process";
2
+ /** Best-effort: open a URL in the user's default browser without blocking. */
3
+ export function openInBrowser(url) {
4
+ const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
5
+ const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
6
+ try {
7
+ const child = spawn(cmd, args, { stdio: "ignore", detached: true });
8
+ child.on("error", () => {
9
+ /* swallow: best-effort */
10
+ });
11
+ child.unref();
12
+ }
13
+ catch {
14
+ /* swallow: best-effort */
15
+ }
16
+ }
17
+ //# sourceMappingURL=browser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,8EAA8E;AAC9E,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,MAAM,GAAG,GACP,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC;IAC7F,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC7E,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QACpE,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACrB,0BAA0B;QAC5B,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,KAAK,EAAE,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,0BAA0B;IAC5B,CAAC;AACH,CAAC"}