@artyfacts/claude 1.0.0 → 1.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/README.md +159 -78
- package/bin/artyfacts-claude.js +38 -0
- package/dist/chunk-365PEWTO.mjs +567 -0
- package/dist/chunk-QKDOZSBI.mjs +571 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +791 -0
- package/dist/cli.mjs +189 -726
- package/dist/index.d.mts +178 -249
- package/dist/index.d.ts +178 -249
- package/dist/index.js +472 -486
- package/dist/index.mjs +22 -584
- package/package.json +27 -16
- package/src/auth.ts +344 -0
- package/src/cli.ts +344 -0
- package/src/executor.ts +293 -0
- package/src/index.ts +86 -0
- package/src/listener.ts +313 -0
- package/tsconfig.json +20 -0
- package/bin/cli.js +0 -2
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,586 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
async fetch(path2, options = {}) {
|
|
15
|
-
const url = `${this.config.baseUrl}${path2}`;
|
|
16
|
-
const response = await fetch(url, {
|
|
17
|
-
...options,
|
|
18
|
-
headers: {
|
|
19
|
-
"Content-Type": "application/json",
|
|
20
|
-
"Authorization": `Bearer ${this.config.apiKey}`,
|
|
21
|
-
...options.headers
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
if (!response.ok) {
|
|
25
|
-
const error = await response.text();
|
|
26
|
-
throw new Error(`API error (${response.status}): ${error}`);
|
|
27
|
-
}
|
|
28
|
-
return response.json();
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Get claimable tasks from the queue
|
|
32
|
-
*/
|
|
33
|
-
async getTaskQueue(options) {
|
|
34
|
-
const params = new URLSearchParams();
|
|
35
|
-
if (options?.limit) params.set("limit", options.limit.toString());
|
|
36
|
-
const result = await this.fetch(`/tasks/queue?${params}`);
|
|
37
|
-
return result.tasks;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Claim a task
|
|
41
|
-
*/
|
|
42
|
-
async claimTask(taskId) {
|
|
43
|
-
return this.fetch(`/tasks/${taskId}/claim`, {
|
|
44
|
-
method: "POST",
|
|
45
|
-
body: JSON.stringify({ agent_id: this.config.agentId })
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Complete a task
|
|
50
|
-
*/
|
|
51
|
-
async completeTask(taskId, options) {
|
|
52
|
-
return this.fetch(`/tasks/${taskId}/complete`, {
|
|
53
|
-
method: "POST",
|
|
54
|
-
body: JSON.stringify({
|
|
55
|
-
agent_id: this.config.agentId,
|
|
56
|
-
output_url: options?.outputUrl,
|
|
57
|
-
summary: options?.summary
|
|
58
|
-
})
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Report task as blocked
|
|
63
|
-
*/
|
|
64
|
-
async blockTask(taskId, reason) {
|
|
65
|
-
await this.fetch(`/tasks/${taskId}/block`, {
|
|
66
|
-
method: "POST",
|
|
67
|
-
body: JSON.stringify({
|
|
68
|
-
agent_id: this.config.agentId,
|
|
69
|
-
reason
|
|
70
|
-
})
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Get current user/org info
|
|
75
|
-
*/
|
|
76
|
-
async getMe() {
|
|
77
|
-
return this.fetch("/me");
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
// src/claude-runner.ts
|
|
82
|
-
import { spawn } from "child_process";
|
|
83
|
-
import { EventEmitter } from "events";
|
|
84
|
-
var ClaudeRunner = class extends EventEmitter {
|
|
85
|
-
config;
|
|
86
|
-
runningTasks = /* @__PURE__ */ new Map();
|
|
87
|
-
constructor(config = {}) {
|
|
88
|
-
super();
|
|
89
|
-
this.config = {
|
|
90
|
-
claudePath: config.claudePath ?? "claude",
|
|
91
|
-
model: config.model ?? "sonnet",
|
|
92
|
-
cwd: config.cwd ?? process.cwd(),
|
|
93
|
-
timeoutMs: config.timeoutMs ?? 5 * 60 * 1e3
|
|
94
|
-
// 5 minutes
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Check if Claude Code is installed and authenticated
|
|
99
|
-
*/
|
|
100
|
-
async checkInstalled() {
|
|
101
|
-
try {
|
|
102
|
-
const result = await this.runCommand(["--version"]);
|
|
103
|
-
const version = result.output.trim();
|
|
104
|
-
const authCheck = await this.runCommand(["-p", 'Say "ok"', "--print", "--max-turns", "1"]);
|
|
105
|
-
const authenticated = authCheck.success && !authCheck.output.includes("not authenticated");
|
|
106
|
-
return { installed: true, authenticated, version };
|
|
107
|
-
} catch (error) {
|
|
108
|
-
return {
|
|
109
|
-
installed: false,
|
|
110
|
-
authenticated: false,
|
|
111
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Run a task with Claude Code
|
|
117
|
-
*/
|
|
118
|
-
async runTask(taskId, prompt, options) {
|
|
119
|
-
const startedAt = /* @__PURE__ */ new Date();
|
|
120
|
-
const model = options?.model ?? this.config.model;
|
|
121
|
-
const cwd = options?.cwd ?? this.config.cwd;
|
|
122
|
-
const timeoutMs = options?.timeoutMs ?? this.config.timeoutMs;
|
|
123
|
-
const args = [
|
|
124
|
-
"-p",
|
|
125
|
-
prompt,
|
|
126
|
-
"--print",
|
|
127
|
-
"--output-format",
|
|
128
|
-
"text",
|
|
129
|
-
"--model",
|
|
130
|
-
model
|
|
131
|
-
];
|
|
132
|
-
this.emit("task:start", { taskId, prompt, model });
|
|
133
|
-
const promise = new Promise((resolve) => {
|
|
134
|
-
let output = "";
|
|
135
|
-
let error = "";
|
|
136
|
-
const proc = spawn(this.config.claudePath, args, {
|
|
137
|
-
cwd,
|
|
138
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
139
|
-
env: { ...process.env }
|
|
140
|
-
});
|
|
141
|
-
const timeout = setTimeout(() => {
|
|
142
|
-
proc.kill("SIGTERM");
|
|
143
|
-
resolve({
|
|
144
|
-
success: false,
|
|
145
|
-
output,
|
|
146
|
-
error: "Task timed out",
|
|
147
|
-
exitCode: null,
|
|
148
|
-
durationMs: Date.now() - startedAt.getTime()
|
|
149
|
-
});
|
|
150
|
-
}, timeoutMs);
|
|
151
|
-
proc.stdout?.on("data", (data) => {
|
|
152
|
-
output += data.toString();
|
|
153
|
-
this.emit("task:output", { taskId, chunk: data.toString() });
|
|
154
|
-
});
|
|
155
|
-
proc.stderr?.on("data", (data) => {
|
|
156
|
-
error += data.toString();
|
|
157
|
-
});
|
|
158
|
-
proc.on("close", (code) => {
|
|
159
|
-
clearTimeout(timeout);
|
|
160
|
-
this.runningTasks.delete(taskId);
|
|
161
|
-
const result = {
|
|
162
|
-
success: code === 0,
|
|
163
|
-
output: output.trim(),
|
|
164
|
-
error: error.trim() || void 0,
|
|
165
|
-
exitCode: code,
|
|
166
|
-
durationMs: Date.now() - startedAt.getTime()
|
|
167
|
-
};
|
|
168
|
-
this.emit("task:complete", { taskId, result });
|
|
169
|
-
resolve(result);
|
|
170
|
-
});
|
|
171
|
-
proc.on("error", (err) => {
|
|
172
|
-
clearTimeout(timeout);
|
|
173
|
-
this.runningTasks.delete(taskId);
|
|
174
|
-
resolve({
|
|
175
|
-
success: false,
|
|
176
|
-
output: "",
|
|
177
|
-
error: err.message,
|
|
178
|
-
exitCode: null,
|
|
179
|
-
durationMs: Date.now() - startedAt.getTime()
|
|
180
|
-
});
|
|
181
|
-
});
|
|
182
|
-
this.runningTasks.set(taskId, {
|
|
183
|
-
taskId,
|
|
184
|
-
process: proc,
|
|
185
|
-
startedAt,
|
|
186
|
-
promise
|
|
187
|
-
});
|
|
188
|
-
});
|
|
189
|
-
return promise;
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Run a raw claude command
|
|
193
|
-
*/
|
|
194
|
-
runCommand(args) {
|
|
195
|
-
return new Promise((resolve) => {
|
|
196
|
-
const startedAt = Date.now();
|
|
197
|
-
let output = "";
|
|
198
|
-
let error = "";
|
|
199
|
-
const proc = spawn(this.config.claudePath, args, {
|
|
200
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
201
|
-
});
|
|
202
|
-
proc.stdout?.on("data", (data) => {
|
|
203
|
-
output += data.toString();
|
|
204
|
-
});
|
|
205
|
-
proc.stderr?.on("data", (data) => {
|
|
206
|
-
error += data.toString();
|
|
207
|
-
});
|
|
208
|
-
proc.on("close", (code) => {
|
|
209
|
-
resolve({
|
|
210
|
-
success: code === 0,
|
|
211
|
-
output: output.trim(),
|
|
212
|
-
error: error.trim() || void 0,
|
|
213
|
-
exitCode: code,
|
|
214
|
-
durationMs: Date.now() - startedAt
|
|
215
|
-
});
|
|
216
|
-
});
|
|
217
|
-
proc.on("error", (err) => {
|
|
218
|
-
resolve({
|
|
219
|
-
success: false,
|
|
220
|
-
output: "",
|
|
221
|
-
error: err.message,
|
|
222
|
-
exitCode: null,
|
|
223
|
-
durationMs: Date.now() - startedAt
|
|
224
|
-
});
|
|
225
|
-
});
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
/**
|
|
229
|
-
* Cancel a running task
|
|
230
|
-
*/
|
|
231
|
-
cancelTask(taskId) {
|
|
232
|
-
const task = this.runningTasks.get(taskId);
|
|
233
|
-
if (task) {
|
|
234
|
-
task.process.kill("SIGTERM");
|
|
235
|
-
this.runningTasks.delete(taskId);
|
|
236
|
-
this.emit("task:cancelled", { taskId });
|
|
237
|
-
return true;
|
|
238
|
-
}
|
|
239
|
-
return false;
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* Get count of running tasks
|
|
243
|
-
*/
|
|
244
|
-
getRunningCount() {
|
|
245
|
-
return this.runningTasks.size;
|
|
246
|
-
}
|
|
247
|
-
/**
|
|
248
|
-
* Cancel all running tasks
|
|
249
|
-
*/
|
|
250
|
-
cancelAll() {
|
|
251
|
-
for (const [taskId] of this.runningTasks) {
|
|
252
|
-
this.cancelTask(taskId);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
};
|
|
256
|
-
|
|
257
|
-
// src/adapter.ts
|
|
258
|
-
var ClaudeAdapter = class extends EventEmitter2 {
|
|
259
|
-
config;
|
|
260
|
-
client;
|
|
261
|
-
runner;
|
|
262
|
-
running = false;
|
|
263
|
-
pollTimer = null;
|
|
264
|
-
activeTasks = /* @__PURE__ */ new Set();
|
|
265
|
-
constructor(config) {
|
|
266
|
-
super();
|
|
267
|
-
this.config = {
|
|
268
|
-
apiKey: config.apiKey,
|
|
269
|
-
baseUrl: config.baseUrl ?? "https://artyfacts.dev/api/v1",
|
|
270
|
-
agentId: config.agentId ?? "claude-agent",
|
|
271
|
-
pollIntervalMs: config.pollIntervalMs ?? 3e4,
|
|
272
|
-
maxConcurrent: config.maxConcurrent ?? 1,
|
|
273
|
-
model: config.model ?? "sonnet",
|
|
274
|
-
cwd: config.cwd ?? process.cwd()
|
|
275
|
-
};
|
|
276
|
-
this.client = new ArtyfactsClient({
|
|
277
|
-
apiKey: this.config.apiKey,
|
|
278
|
-
baseUrl: this.config.baseUrl,
|
|
279
|
-
agentId: this.config.agentId
|
|
280
|
-
});
|
|
281
|
-
this.runner = new ClaudeRunner({
|
|
282
|
-
model: this.config.model,
|
|
283
|
-
cwd: this.config.cwd
|
|
284
|
-
});
|
|
285
|
-
this.runner.on("task:output", (data) => this.emit("task:output", data));
|
|
286
|
-
}
|
|
287
|
-
/**
|
|
288
|
-
* Check if Claude Code is ready
|
|
289
|
-
*/
|
|
290
|
-
async checkReady() {
|
|
291
|
-
const check = await this.runner.checkInstalled();
|
|
292
|
-
if (!check.installed) {
|
|
293
|
-
return {
|
|
294
|
-
ready: false,
|
|
295
|
-
error: "Claude Code is not installed. Run: npm install -g @anthropic-ai/claude-code"
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
if (!check.authenticated) {
|
|
299
|
-
return {
|
|
300
|
-
ready: false,
|
|
301
|
-
error: "Claude Code is not authenticated. Run: claude login"
|
|
302
|
-
};
|
|
303
|
-
}
|
|
304
|
-
return { ready: true };
|
|
305
|
-
}
|
|
306
|
-
/**
|
|
307
|
-
* Start the adapter
|
|
308
|
-
*/
|
|
309
|
-
async start() {
|
|
310
|
-
if (this.running) return;
|
|
311
|
-
const { ready, error } = await this.checkReady();
|
|
312
|
-
if (!ready) {
|
|
313
|
-
throw new Error(error);
|
|
314
|
-
}
|
|
315
|
-
this.running = true;
|
|
316
|
-
this.emit("started");
|
|
317
|
-
await this.poll();
|
|
318
|
-
this.pollTimer = setInterval(() => {
|
|
319
|
-
this.poll().catch((err) => this.emit("error", err));
|
|
320
|
-
}, this.config.pollIntervalMs);
|
|
321
|
-
}
|
|
322
|
-
/**
|
|
323
|
-
* Stop the adapter
|
|
324
|
-
*/
|
|
325
|
-
async stop() {
|
|
326
|
-
if (!this.running) return;
|
|
327
|
-
this.running = false;
|
|
328
|
-
if (this.pollTimer) {
|
|
329
|
-
clearInterval(this.pollTimer);
|
|
330
|
-
this.pollTimer = null;
|
|
331
|
-
}
|
|
332
|
-
this.runner.cancelAll();
|
|
333
|
-
this.emit("stopped");
|
|
334
|
-
}
|
|
335
|
-
/**
|
|
336
|
-
* Poll for and execute tasks
|
|
337
|
-
*/
|
|
338
|
-
async poll() {
|
|
339
|
-
try {
|
|
340
|
-
const available = this.config.maxConcurrent - this.activeTasks.size;
|
|
341
|
-
if (available <= 0) return;
|
|
342
|
-
const tasks = await this.client.getTaskQueue({ limit: available });
|
|
343
|
-
this.emit("poll", tasks);
|
|
344
|
-
for (const task of tasks) {
|
|
345
|
-
if (this.activeTasks.has(task.id)) continue;
|
|
346
|
-
if (this.activeTasks.size >= this.config.maxConcurrent) break;
|
|
347
|
-
await this.executeTask(task);
|
|
348
|
-
}
|
|
349
|
-
} catch (error) {
|
|
350
|
-
this.emit("error", error instanceof Error ? error : new Error(String(error)));
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
/**
|
|
354
|
-
* Execute a single task
|
|
355
|
-
*/
|
|
356
|
-
async executeTask(task) {
|
|
357
|
-
try {
|
|
358
|
-
const claim = await this.client.claimTask(task.id);
|
|
359
|
-
if (!claim.success) return;
|
|
360
|
-
this.activeTasks.add(task.id);
|
|
361
|
-
this.emit("task:claimed", task);
|
|
362
|
-
const prompt = this.buildPrompt(task);
|
|
363
|
-
this.emit("task:running", task);
|
|
364
|
-
const result = await this.runner.runTask(task.id, prompt, {
|
|
365
|
-
cwd: this.config.cwd
|
|
366
|
-
});
|
|
367
|
-
this.activeTasks.delete(task.id);
|
|
368
|
-
if (result.success) {
|
|
369
|
-
await this.client.completeTask(task.id, {
|
|
370
|
-
summary: this.extractSummary(result.output)
|
|
371
|
-
});
|
|
372
|
-
this.emit("task:completed", task, result);
|
|
373
|
-
} else {
|
|
374
|
-
await this.client.blockTask(task.id, result.error ?? "Task failed");
|
|
375
|
-
this.emit("task:failed", task, result.error ?? "Unknown error");
|
|
376
|
-
}
|
|
377
|
-
} catch (error) {
|
|
378
|
-
this.activeTasks.delete(task.id);
|
|
379
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
380
|
-
this.emit("task:failed", task, message);
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
/**
|
|
384
|
-
* Build a prompt for Claude from the task
|
|
385
|
-
*/
|
|
386
|
-
buildPrompt(task) {
|
|
387
|
-
return `You are working on a task from Artyfacts.
|
|
388
|
-
|
|
389
|
-
## Task: ${task.heading}
|
|
390
|
-
|
|
391
|
-
## Context
|
|
392
|
-
- Artifact: ${task.artifactTitle}
|
|
393
|
-
- URL: ${task.artifactUrl}
|
|
394
|
-
- Priority: ${task.priority === 1 ? "High" : task.priority === 2 ? "Medium" : "Low"}
|
|
395
|
-
|
|
396
|
-
## Details
|
|
397
|
-
${task.content}
|
|
398
|
-
|
|
399
|
-
## Instructions
|
|
400
|
-
Complete this task to the best of your ability. When finished, provide a brief summary of what you accomplished.
|
|
401
|
-
|
|
402
|
-
If you cannot complete the task, explain why clearly.`;
|
|
403
|
-
}
|
|
404
|
-
/**
|
|
405
|
-
* Extract a summary from Claude's output
|
|
406
|
-
*/
|
|
407
|
-
extractSummary(output) {
|
|
408
|
-
const maxLen = 500;
|
|
409
|
-
if (output.length <= maxLen) return output;
|
|
410
|
-
return "..." + output.slice(-maxLen);
|
|
411
|
-
}
|
|
412
|
-
/**
|
|
413
|
-
* Check if running
|
|
414
|
-
*/
|
|
415
|
-
isRunning() {
|
|
416
|
-
return this.running;
|
|
417
|
-
}
|
|
418
|
-
/**
|
|
419
|
-
* Get stats
|
|
420
|
-
*/
|
|
421
|
-
getStats() {
|
|
422
|
-
return {
|
|
423
|
-
running: this.running,
|
|
424
|
-
activeTasks: this.activeTasks.size,
|
|
425
|
-
maxConcurrent: this.config.maxConcurrent
|
|
426
|
-
};
|
|
427
|
-
}
|
|
428
|
-
};
|
|
429
|
-
|
|
430
|
-
// src/auth.ts
|
|
431
|
-
import { execSync } from "child_process";
|
|
432
|
-
import * as fs from "fs";
|
|
433
|
-
import * as path from "path";
|
|
434
|
-
import * as os from "os";
|
|
435
|
-
var DeviceAuth = class {
|
|
436
|
-
baseUrl;
|
|
437
|
-
credentialsPath;
|
|
438
|
-
constructor(options) {
|
|
439
|
-
this.baseUrl = options?.baseUrl ?? "https://artyfacts.dev";
|
|
440
|
-
this.credentialsPath = path.join(os.homedir(), ".artyfacts", "credentials.json");
|
|
441
|
-
}
|
|
442
|
-
/**
|
|
443
|
-
* Check if we have stored credentials
|
|
444
|
-
*/
|
|
445
|
-
hasCredentials() {
|
|
446
|
-
return fs.existsSync(this.credentialsPath);
|
|
447
|
-
}
|
|
448
|
-
/**
|
|
449
|
-
* Get stored credentials
|
|
450
|
-
*/
|
|
451
|
-
getCredentials() {
|
|
452
|
-
if (!this.hasCredentials()) return null;
|
|
453
|
-
try {
|
|
454
|
-
const data = fs.readFileSync(this.credentialsPath, "utf-8");
|
|
455
|
-
const creds = JSON.parse(data);
|
|
456
|
-
if (creds.expiresAt && Date.now() > creds.expiresAt) {
|
|
457
|
-
return null;
|
|
458
|
-
}
|
|
459
|
-
return creds;
|
|
460
|
-
} catch {
|
|
461
|
-
return null;
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
/**
|
|
465
|
-
* Get access token (for API calls)
|
|
466
|
-
*/
|
|
467
|
-
getAccessToken() {
|
|
468
|
-
const creds = this.getCredentials();
|
|
469
|
-
return creds?.accessToken ?? null;
|
|
470
|
-
}
|
|
471
|
-
/**
|
|
472
|
-
* Clear stored credentials (logout)
|
|
473
|
-
*/
|
|
474
|
-
logout() {
|
|
475
|
-
if (fs.existsSync(this.credentialsPath)) {
|
|
476
|
-
fs.unlinkSync(this.credentialsPath);
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
/**
|
|
480
|
-
* Start device authorization flow
|
|
481
|
-
*/
|
|
482
|
-
async startDeviceFlow() {
|
|
483
|
-
const response = await fetch(`${this.baseUrl}/api/v1/auth/device`, {
|
|
484
|
-
method: "POST",
|
|
485
|
-
headers: { "Content-Type": "application/json" }
|
|
486
|
-
});
|
|
487
|
-
if (!response.ok) {
|
|
488
|
-
throw new Error(`Failed to start device flow: ${response.status}`);
|
|
489
|
-
}
|
|
490
|
-
return response.json();
|
|
491
|
-
}
|
|
492
|
-
/**
|
|
493
|
-
* Poll for token after user authorizes
|
|
494
|
-
*/
|
|
495
|
-
async pollForToken(deviceCode, interval, expiresIn) {
|
|
496
|
-
const startTime = Date.now();
|
|
497
|
-
const expiresAt = startTime + expiresIn * 1e3;
|
|
498
|
-
while (Date.now() < expiresAt) {
|
|
499
|
-
await this.sleep(interval * 1e3);
|
|
500
|
-
const response = await fetch(`${this.baseUrl}/api/v1/auth/device/token`, {
|
|
501
|
-
method: "POST",
|
|
502
|
-
headers: { "Content-Type": "application/json" },
|
|
503
|
-
body: JSON.stringify({ deviceCode })
|
|
504
|
-
});
|
|
505
|
-
if (response.ok) {
|
|
506
|
-
return response.json();
|
|
507
|
-
}
|
|
508
|
-
const data = await response.json().catch(() => ({}));
|
|
509
|
-
if (data.error === "authorization_pending") {
|
|
510
|
-
continue;
|
|
511
|
-
}
|
|
512
|
-
if (data.error === "slow_down") {
|
|
513
|
-
interval += 5;
|
|
514
|
-
continue;
|
|
515
|
-
}
|
|
516
|
-
if (data.error === "expired_token") {
|
|
517
|
-
throw new Error("Authorization expired. Please try again.");
|
|
518
|
-
}
|
|
519
|
-
if (data.error === "access_denied") {
|
|
520
|
-
throw new Error("Authorization denied by user.");
|
|
521
|
-
}
|
|
522
|
-
throw new Error(data.error ?? "Unknown error during authorization");
|
|
523
|
-
}
|
|
524
|
-
throw new Error("Authorization timed out. Please try again.");
|
|
525
|
-
}
|
|
526
|
-
/**
|
|
527
|
-
* Save credentials to disk
|
|
528
|
-
*/
|
|
529
|
-
saveCredentials(token) {
|
|
530
|
-
const dir = path.dirname(this.credentialsPath);
|
|
531
|
-
if (!fs.existsSync(dir)) {
|
|
532
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
533
|
-
}
|
|
534
|
-
const creds = {
|
|
535
|
-
...token,
|
|
536
|
-
savedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
537
|
-
};
|
|
538
|
-
fs.writeFileSync(this.credentialsPath, JSON.stringify(creds, null, 2), {
|
|
539
|
-
mode: 384
|
|
540
|
-
// Only user can read/write
|
|
541
|
-
});
|
|
542
|
-
}
|
|
543
|
-
/**
|
|
544
|
-
* Open URL in browser
|
|
545
|
-
*/
|
|
546
|
-
openBrowser(url) {
|
|
547
|
-
const platform = process.platform;
|
|
548
|
-
try {
|
|
549
|
-
if (platform === "darwin") {
|
|
550
|
-
execSync(`open "${url}"`);
|
|
551
|
-
} else if (platform === "win32") {
|
|
552
|
-
execSync(`start "" "${url}"`);
|
|
553
|
-
} else {
|
|
554
|
-
execSync(`xdg-open "${url}"`);
|
|
555
|
-
}
|
|
556
|
-
} catch {
|
|
557
|
-
console.log(`Please open this URL in your browser: ${url}`);
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
/**
|
|
561
|
-
* Full login flow
|
|
562
|
-
*/
|
|
563
|
-
async login(options) {
|
|
564
|
-
const deviceCode = await this.startDeviceFlow();
|
|
565
|
-
options?.onDeviceCode?.(deviceCode);
|
|
566
|
-
this.openBrowser(deviceCode.verificationUri);
|
|
567
|
-
options?.onWaiting?.();
|
|
568
|
-
const token = await this.pollForToken(
|
|
569
|
-
deviceCode.deviceCode,
|
|
570
|
-
deviceCode.interval,
|
|
571
|
-
deviceCode.expiresIn
|
|
572
|
-
);
|
|
573
|
-
this.saveCredentials(token);
|
|
574
|
-
return token;
|
|
575
|
-
}
|
|
576
|
-
sleep(ms) {
|
|
577
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
578
|
-
}
|
|
579
|
-
};
|
|
1
|
+
import {
|
|
2
|
+
ArtyfactsListener,
|
|
3
|
+
ClaudeExecutor,
|
|
4
|
+
clearCredentials,
|
|
5
|
+
createExecutor,
|
|
6
|
+
createListener,
|
|
7
|
+
getCredentials,
|
|
8
|
+
loadCredentials,
|
|
9
|
+
promptForApiKey,
|
|
10
|
+
runDeviceAuth,
|
|
11
|
+
saveCredentials
|
|
12
|
+
} from "./chunk-365PEWTO.mjs";
|
|
580
13
|
export {
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
14
|
+
ArtyfactsListener,
|
|
15
|
+
ClaudeExecutor,
|
|
16
|
+
clearCredentials,
|
|
17
|
+
createExecutor,
|
|
18
|
+
createListener,
|
|
19
|
+
getCredentials,
|
|
20
|
+
loadCredentials,
|
|
21
|
+
promptForApiKey,
|
|
22
|
+
runDeviceAuth,
|
|
23
|
+
saveCredentials
|
|
585
24
|
};
|
|
586
|
-
//# sourceMappingURL=index.mjs.map
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@artyfacts/claude",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Claude
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Claude adapter for Artyfacts - Execute tasks using Claude Code CLI",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"bin": {
|
|
9
|
-
"artyfacts-claude": "bin/
|
|
9
|
+
"artyfacts-claude": "./bin/artyfacts-claude.js"
|
|
10
10
|
},
|
|
11
11
|
"exports": {
|
|
12
12
|
".": {
|
|
@@ -15,33 +15,44 @@
|
|
|
15
15
|
"require": "./dist/index.js"
|
|
16
16
|
}
|
|
17
17
|
},
|
|
18
|
-
"files": ["dist", "bin"],
|
|
19
18
|
"scripts": {
|
|
20
|
-
"build": "tsup",
|
|
21
|
-
"dev": "tsup --watch",
|
|
19
|
+
"build": "tsup src/index.ts src/cli.ts --format cjs,esm --dts",
|
|
20
|
+
"dev": "tsup src/index.ts src/cli.ts --format cjs,esm --dts --watch",
|
|
21
|
+
"start": "node bin/artyfacts-claude.js",
|
|
22
22
|
"test": "vitest",
|
|
23
|
-
"
|
|
24
|
-
"start": "node dist/index.js",
|
|
25
|
-
"prepublishOnly": "npm run build"
|
|
23
|
+
"lint": "eslint src/"
|
|
26
24
|
},
|
|
27
|
-
"keywords": [
|
|
25
|
+
"keywords": [
|
|
26
|
+
"artyfacts",
|
|
27
|
+
"claude",
|
|
28
|
+
"anthropic",
|
|
29
|
+
"ai",
|
|
30
|
+
"agents",
|
|
31
|
+
"llm",
|
|
32
|
+
"adapter"
|
|
33
|
+
],
|
|
28
34
|
"author": "Artygroup",
|
|
29
35
|
"license": "MIT",
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "https://github.com/artygracie/artyfacts.git",
|
|
39
|
+
"directory": "packages/claude"
|
|
40
|
+
},
|
|
30
41
|
"dependencies": {
|
|
31
|
-
"chalk": "^5.3.0",
|
|
32
42
|
"commander": "^12.0.0",
|
|
33
|
-
"
|
|
43
|
+
"eventsource": "^2.0.2"
|
|
44
|
+
},
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
34
47
|
},
|
|
35
48
|
"devDependencies": {
|
|
49
|
+
"@types/eventsource": "^1.1.15",
|
|
36
50
|
"@types/node": "^20.0.0",
|
|
37
51
|
"tsup": "^8.0.0",
|
|
38
52
|
"typescript": "^5.0.0",
|
|
39
53
|
"vitest": "^1.0.0"
|
|
40
54
|
},
|
|
41
55
|
"engines": {
|
|
42
|
-
"node": ">=18"
|
|
43
|
-
},
|
|
44
|
-
"publishConfig": {
|
|
45
|
-
"access": "public"
|
|
56
|
+
"node": ">=18.0.0"
|
|
46
57
|
}
|
|
47
58
|
}
|