@artyfacts/claude 1.3.4 → 1.3.6
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/dist/chunk-CNJCMX2D.mjs +787 -0
- package/dist/cli.js +53 -21
- package/dist/cli.mjs +5 -5
- package/dist/index.js +49 -17
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
- package/src/cli.ts +5 -4
- package/src/context.ts +24 -6
- package/src/executor.ts +26 -12
|
@@ -0,0 +1,787 @@
|
|
|
1
|
+
// src/auth.ts
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import * as os from "os";
|
|
5
|
+
import * as readline from "readline";
|
|
6
|
+
var CREDENTIALS_DIR = path.join(os.homedir(), ".artyfacts");
|
|
7
|
+
var CREDENTIALS_FILE = path.join(CREDENTIALS_DIR, "credentials.json");
|
|
8
|
+
var DEFAULT_BASE_URL = "https://artyfacts.dev/api/v1";
|
|
9
|
+
function loadCredentials() {
|
|
10
|
+
try {
|
|
11
|
+
if (!fs.existsSync(CREDENTIALS_FILE)) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
const data = fs.readFileSync(CREDENTIALS_FILE, "utf-8");
|
|
15
|
+
const credentials = JSON.parse(data);
|
|
16
|
+
if (credentials.expiresAt) {
|
|
17
|
+
const expiresAt = new Date(credentials.expiresAt);
|
|
18
|
+
if (expiresAt < /* @__PURE__ */ new Date()) {
|
|
19
|
+
console.log("\u26A0\uFE0F Credentials have expired");
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return credentials;
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.error("Failed to load credentials:", error);
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function saveCredentials(credentials) {
|
|
30
|
+
try {
|
|
31
|
+
if (!fs.existsSync(CREDENTIALS_DIR)) {
|
|
32
|
+
fs.mkdirSync(CREDENTIALS_DIR, { mode: 448, recursive: true });
|
|
33
|
+
}
|
|
34
|
+
fs.writeFileSync(
|
|
35
|
+
CREDENTIALS_FILE,
|
|
36
|
+
JSON.stringify(credentials, null, 2),
|
|
37
|
+
{ mode: 384 }
|
|
38
|
+
);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
throw new Error(`Failed to save credentials: ${error}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function clearCredentials() {
|
|
44
|
+
try {
|
|
45
|
+
if (fs.existsSync(CREDENTIALS_FILE)) {
|
|
46
|
+
fs.unlinkSync(CREDENTIALS_FILE);
|
|
47
|
+
}
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error("Failed to clear credentials:", error);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async function runDeviceAuth(baseUrl = DEFAULT_BASE_URL) {
|
|
53
|
+
console.log("\u{1F510} Starting device authentication...\n");
|
|
54
|
+
const deviceAuth = await requestDeviceCode(baseUrl);
|
|
55
|
+
console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
|
|
56
|
+
console.log("\u{1F4CB} To authenticate, visit:");
|
|
57
|
+
console.log(` ${deviceAuth.verificationUri}`);
|
|
58
|
+
console.log("");
|
|
59
|
+
console.log("\u{1F511} Enter this code:");
|
|
60
|
+
console.log(` ${deviceAuth.userCode}`);
|
|
61
|
+
console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n");
|
|
62
|
+
console.log("\u23F3 Waiting for authentication...\n");
|
|
63
|
+
const credentials = await pollForToken(
|
|
64
|
+
baseUrl,
|
|
65
|
+
deviceAuth.deviceCode,
|
|
66
|
+
deviceAuth.interval,
|
|
67
|
+
deviceAuth.expiresIn
|
|
68
|
+
);
|
|
69
|
+
saveCredentials(credentials);
|
|
70
|
+
console.log("\u2705 Authentication successful!");
|
|
71
|
+
console.log(` Agent ID: ${credentials.agentId}`);
|
|
72
|
+
if (credentials.agentName) {
|
|
73
|
+
console.log(` Agent Name: ${credentials.agentName}`);
|
|
74
|
+
}
|
|
75
|
+
console.log("");
|
|
76
|
+
return credentials;
|
|
77
|
+
}
|
|
78
|
+
async function requestDeviceCode(baseUrl) {
|
|
79
|
+
const response = await fetch(`${baseUrl}/auth/device`, {
|
|
80
|
+
method: "POST",
|
|
81
|
+
headers: {
|
|
82
|
+
"Content-Type": "application/json"
|
|
83
|
+
},
|
|
84
|
+
body: JSON.stringify({
|
|
85
|
+
client_id: "artyfacts-claude",
|
|
86
|
+
scope: "agent:execute"
|
|
87
|
+
})
|
|
88
|
+
});
|
|
89
|
+
if (!response.ok) {
|
|
90
|
+
const error = await response.text();
|
|
91
|
+
throw new Error(`Failed to start device auth: ${error}`);
|
|
92
|
+
}
|
|
93
|
+
const data = await response.json();
|
|
94
|
+
return {
|
|
95
|
+
deviceCode: data.deviceCode || data.device_code || "",
|
|
96
|
+
userCode: data.userCode || data.user_code || "",
|
|
97
|
+
verificationUri: data.verificationUri || data.verification_uri || `https://artyfacts.dev/auth/device`,
|
|
98
|
+
expiresIn: data.expiresIn || data.expires_in || 600,
|
|
99
|
+
interval: data.interval || 5
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
async function pollForToken(baseUrl, deviceCode, interval, expiresIn) {
|
|
103
|
+
const startTime = Date.now();
|
|
104
|
+
const timeoutMs = expiresIn * 1e3;
|
|
105
|
+
while (true) {
|
|
106
|
+
if (Date.now() - startTime > timeoutMs) {
|
|
107
|
+
throw new Error("Device authentication timed out");
|
|
108
|
+
}
|
|
109
|
+
await sleep(interval * 1e3);
|
|
110
|
+
const response = await fetch(`${baseUrl}/auth/device/token`, {
|
|
111
|
+
method: "POST",
|
|
112
|
+
headers: {
|
|
113
|
+
"Content-Type": "application/json"
|
|
114
|
+
},
|
|
115
|
+
body: JSON.stringify({
|
|
116
|
+
device_code: deviceCode,
|
|
117
|
+
client_id: "artyfacts-claude"
|
|
118
|
+
})
|
|
119
|
+
});
|
|
120
|
+
if (response.ok) {
|
|
121
|
+
const data = await response.json();
|
|
122
|
+
return {
|
|
123
|
+
apiKey: data.apiKey,
|
|
124
|
+
agentId: data.agentId,
|
|
125
|
+
agentName: data.agentName,
|
|
126
|
+
expiresAt: data.expiresAt
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
const errorData = await response.json().catch(() => ({}));
|
|
130
|
+
const errorCode = errorData.error || errorData.code;
|
|
131
|
+
if (errorCode === "authorization_pending") {
|
|
132
|
+
process.stdout.write(".");
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (errorCode === "slow_down") {
|
|
136
|
+
interval = Math.min(interval * 2, 30);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (errorCode === "expired_token") {
|
|
140
|
+
throw new Error("Device code expired. Please try again.");
|
|
141
|
+
}
|
|
142
|
+
if (errorCode === "access_denied") {
|
|
143
|
+
throw new Error("Authorization was denied.");
|
|
144
|
+
}
|
|
145
|
+
throw new Error(`Authentication failed: ${errorData.message || errorCode || response.statusText}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
async function promptForApiKey() {
|
|
149
|
+
const rl = readline.createInterface({
|
|
150
|
+
input: process.stdin,
|
|
151
|
+
output: process.stdout
|
|
152
|
+
});
|
|
153
|
+
const question = (prompt) => {
|
|
154
|
+
return new Promise((resolve) => {
|
|
155
|
+
rl.question(prompt, resolve);
|
|
156
|
+
});
|
|
157
|
+
};
|
|
158
|
+
console.log("\u{1F511} Manual Configuration\n");
|
|
159
|
+
console.log("Enter your Artyfacts credentials:\n");
|
|
160
|
+
const apiKey = await question("API Key: ");
|
|
161
|
+
const agentId = await question("Agent ID: ");
|
|
162
|
+
const agentName = await question("Agent Name (optional): ");
|
|
163
|
+
rl.close();
|
|
164
|
+
if (!apiKey || !agentId) {
|
|
165
|
+
throw new Error("API Key and Agent ID are required");
|
|
166
|
+
}
|
|
167
|
+
const credentials = {
|
|
168
|
+
apiKey: apiKey.trim(),
|
|
169
|
+
agentId: agentId.trim(),
|
|
170
|
+
agentName: agentName.trim() || void 0
|
|
171
|
+
};
|
|
172
|
+
saveCredentials(credentials);
|
|
173
|
+
console.log("\n\u2705 Credentials saved!");
|
|
174
|
+
return credentials;
|
|
175
|
+
}
|
|
176
|
+
function sleep(ms) {
|
|
177
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
178
|
+
}
|
|
179
|
+
async function getCredentials(options) {
|
|
180
|
+
if (!options?.forceAuth) {
|
|
181
|
+
const existing = loadCredentials();
|
|
182
|
+
if (existing) {
|
|
183
|
+
return existing;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return runDeviceAuth(options?.baseUrl);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// src/context.ts
|
|
190
|
+
var ContextFetcher = class {
|
|
191
|
+
config;
|
|
192
|
+
constructor(config) {
|
|
193
|
+
this.config = config;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Fetch full context for a task
|
|
197
|
+
*/
|
|
198
|
+
async fetchTaskContext(taskId) {
|
|
199
|
+
const response = await fetch(
|
|
200
|
+
`${this.config.baseUrl}/tasks/${taskId}/context`,
|
|
201
|
+
{
|
|
202
|
+
headers: {
|
|
203
|
+
"Authorization": `Bearer ${this.config.apiKey}`,
|
|
204
|
+
"Accept": "application/json"
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
);
|
|
208
|
+
if (!response.ok) {
|
|
209
|
+
const errorText = await response.text().catch(() => "Unknown error");
|
|
210
|
+
throw new Error(`Failed to fetch task context: ${response.status} - ${errorText}`);
|
|
211
|
+
}
|
|
212
|
+
const data = await response.json();
|
|
213
|
+
return data;
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
function buildPromptWithContext(context) {
|
|
217
|
+
const parts = [];
|
|
218
|
+
parts.push(`You are an AI agent working within the Artyfacts task management system.
|
|
219
|
+
|
|
220
|
+
Your job is to complete the assigned task. You have full context about the organization, project, and related work.
|
|
221
|
+
|
|
222
|
+
## Available Tools
|
|
223
|
+
|
|
224
|
+
You have access to Artyfacts MCP tools. USE THEM to complete your task:
|
|
225
|
+
|
|
226
|
+
- **create_artifact** - Create new artifacts (documents, specs, reports)
|
|
227
|
+
- **create_section** - Add sections to artifacts (content, tasks, decisions)
|
|
228
|
+
- **update_section** - Update existing sections
|
|
229
|
+
- **create_agent** - Create new AI agents with specific roles
|
|
230
|
+
- **list_artifacts** - Query existing artifacts
|
|
231
|
+
- **list_sections** - Query sections within an artifact
|
|
232
|
+
- **complete_task** - Mark a task as complete
|
|
233
|
+
- **block_task** - Block a task with a reason
|
|
234
|
+
- **create_blocker** - Create a decision blocker
|
|
235
|
+
|
|
236
|
+
IMPORTANT: When asked to create agents or update artifacts, USE THE TOOLS. Don't just describe what you would do - actually do it with the tools.
|
|
237
|
+
|
|
238
|
+
## Guidelines
|
|
239
|
+
|
|
240
|
+
- Be thorough but concise
|
|
241
|
+
- USE THE TOOLS to take action, don't just analyze
|
|
242
|
+
- If the task requires creating something, use create_artifact or create_section
|
|
243
|
+
- If the task requires creating agents, use create_agent
|
|
244
|
+
- If you cannot complete the task, explain why
|
|
245
|
+
|
|
246
|
+
Format your response as follows:
|
|
247
|
+
1. First, use the tools to complete the task
|
|
248
|
+
2. Then summarize what you did
|
|
249
|
+
3. End with a brief summary line starting with "SUMMARY:"`);
|
|
250
|
+
parts.push("");
|
|
251
|
+
parts.push("---");
|
|
252
|
+
parts.push("");
|
|
253
|
+
parts.push("## Organization Context");
|
|
254
|
+
parts.push(`**${context.organization.name}**`);
|
|
255
|
+
if (context.organization.context) {
|
|
256
|
+
parts.push("");
|
|
257
|
+
parts.push(formatOrgContext(context.organization.context));
|
|
258
|
+
}
|
|
259
|
+
parts.push("");
|
|
260
|
+
if (context.project) {
|
|
261
|
+
parts.push(`## Project: ${context.project.name}`);
|
|
262
|
+
if (context.project.description) {
|
|
263
|
+
parts.push(context.project.description);
|
|
264
|
+
}
|
|
265
|
+
parts.push("");
|
|
266
|
+
}
|
|
267
|
+
parts.push(`## Artifact: ${context.artifact.title}`);
|
|
268
|
+
if (context.artifact.summary) {
|
|
269
|
+
parts.push(context.artifact.summary);
|
|
270
|
+
}
|
|
271
|
+
if (context.artifact.description) {
|
|
272
|
+
parts.push("");
|
|
273
|
+
parts.push(context.artifact.description);
|
|
274
|
+
}
|
|
275
|
+
parts.push("");
|
|
276
|
+
const relatedSections = context.artifact.sections.filter(
|
|
277
|
+
(s) => s.id !== context.task.id
|
|
278
|
+
);
|
|
279
|
+
if (relatedSections.length > 0) {
|
|
280
|
+
parts.push("### Related Sections:");
|
|
281
|
+
for (const section of relatedSections) {
|
|
282
|
+
const preview = section.content ? section.content.substring(0, 200) + (section.content.length > 200 ? "..." : "") : "No content";
|
|
283
|
+
const statusBadge = section.task_status ? ` [${section.task_status}]` : "";
|
|
284
|
+
parts.push(`- **${section.heading}**${statusBadge}: ${preview}`);
|
|
285
|
+
}
|
|
286
|
+
parts.push("");
|
|
287
|
+
}
|
|
288
|
+
parts.push("---");
|
|
289
|
+
parts.push("");
|
|
290
|
+
parts.push(`## Your Task: ${context.task.heading}`);
|
|
291
|
+
if (context.task.priority) {
|
|
292
|
+
const priorityLabels = ["\u{1F534} High", "\u{1F7E1} Medium", "\u{1F7E2} Low"];
|
|
293
|
+
parts.push(`**Priority:** ${priorityLabels[context.task.priority - 1] || "Medium"}`);
|
|
294
|
+
}
|
|
295
|
+
parts.push("");
|
|
296
|
+
parts.push("### Description");
|
|
297
|
+
parts.push(context.task.content || "No additional description provided.");
|
|
298
|
+
parts.push("");
|
|
299
|
+
if (context.task.expected_output) {
|
|
300
|
+
parts.push("### Expected Output");
|
|
301
|
+
if (context.task.expected_output.format) {
|
|
302
|
+
parts.push(`**Format:** ${context.task.expected_output.format}`);
|
|
303
|
+
}
|
|
304
|
+
if (context.task.expected_output.requirements && context.task.expected_output.requirements.length > 0) {
|
|
305
|
+
parts.push("**Requirements:**");
|
|
306
|
+
for (const req of context.task.expected_output.requirements) {
|
|
307
|
+
parts.push(`- ${req}`);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
parts.push("");
|
|
311
|
+
}
|
|
312
|
+
parts.push("---");
|
|
313
|
+
parts.push("");
|
|
314
|
+
parts.push("Complete this task and provide your output below.");
|
|
315
|
+
return parts.join("\n");
|
|
316
|
+
}
|
|
317
|
+
function formatOrgContext(context) {
|
|
318
|
+
const trimmed = context.trim();
|
|
319
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
320
|
+
try {
|
|
321
|
+
const parsed = JSON.parse(trimmed);
|
|
322
|
+
return formatContextObject(parsed);
|
|
323
|
+
} catch {
|
|
324
|
+
return context;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return context;
|
|
328
|
+
}
|
|
329
|
+
function formatContextObject(obj, indent = "") {
|
|
330
|
+
if (typeof obj !== "object" || obj === null) {
|
|
331
|
+
return String(obj);
|
|
332
|
+
}
|
|
333
|
+
if (Array.isArray(obj)) {
|
|
334
|
+
return obj.map((item) => `${indent}- ${formatContextObject(item, indent + " ")}`).join("\n");
|
|
335
|
+
}
|
|
336
|
+
const lines = [];
|
|
337
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
338
|
+
const label = key.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
339
|
+
if (typeof value === "object" && value !== null) {
|
|
340
|
+
lines.push(`${indent}**${label}:**`);
|
|
341
|
+
lines.push(formatContextObject(value, indent + " "));
|
|
342
|
+
} else {
|
|
343
|
+
lines.push(`${indent}- **${label}:** ${value}`);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return lines.join("\n");
|
|
347
|
+
}
|
|
348
|
+
function createContextFetcher(config) {
|
|
349
|
+
return new ContextFetcher(config);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// src/executor.ts
|
|
353
|
+
import { spawn } from "child_process";
|
|
354
|
+
var DEFAULT_TIMEOUT = 5 * 60 * 1e3;
|
|
355
|
+
var DEFAULT_SYSTEM_PROMPT = `You are an AI agent working within the Artyfacts task management system.
|
|
356
|
+
|
|
357
|
+
Your job is to complete tasks assigned to you using the available tools.
|
|
358
|
+
|
|
359
|
+
## Available Tools
|
|
360
|
+
|
|
361
|
+
You have access to Artyfacts MCP tools. USE THEM to complete your task:
|
|
362
|
+
|
|
363
|
+
- **create_artifact** - Create new artifacts (documents, specs, reports)
|
|
364
|
+
- **create_section** - Add sections to artifacts (content, tasks, decisions)
|
|
365
|
+
- **update_section** - Update existing sections
|
|
366
|
+
- **create_agent** - Create new AI agents with specific roles
|
|
367
|
+
- **list_artifacts** - Query existing artifacts
|
|
368
|
+
- **list_sections** - Query sections within an artifact
|
|
369
|
+
- **complete_task** - Mark a task as complete
|
|
370
|
+
- **block_task** - Block a task with a reason
|
|
371
|
+
- **create_blocker** - Create a decision blocker
|
|
372
|
+
|
|
373
|
+
IMPORTANT: When asked to create agents or update artifacts, USE THE TOOLS. Don't just describe what you would do - actually do it.
|
|
374
|
+
|
|
375
|
+
## Guidelines
|
|
376
|
+
|
|
377
|
+
- USE THE TOOLS to take action
|
|
378
|
+
- If creating something, use create_artifact or create_section
|
|
379
|
+
- If creating agents, use create_agent
|
|
380
|
+
- If you cannot complete the task, explain why
|
|
381
|
+
|
|
382
|
+
Format your response as follows:
|
|
383
|
+
1. First, use the tools to complete the task
|
|
384
|
+
2. Summarize what you accomplished
|
|
385
|
+
3. End with a brief summary line starting with "SUMMARY:"`;
|
|
386
|
+
var ClaudeExecutor = class {
|
|
387
|
+
config;
|
|
388
|
+
contextFetcher = null;
|
|
389
|
+
constructor(config = {}) {
|
|
390
|
+
this.config = {
|
|
391
|
+
...config,
|
|
392
|
+
timeout: config.timeout || DEFAULT_TIMEOUT,
|
|
393
|
+
claudePath: config.claudePath || "claude"
|
|
394
|
+
};
|
|
395
|
+
if (config.baseUrl && config.apiKey) {
|
|
396
|
+
this.contextFetcher = createContextFetcher({
|
|
397
|
+
baseUrl: config.baseUrl,
|
|
398
|
+
apiKey: config.apiKey
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Execute a task using Claude Code CLI
|
|
404
|
+
*
|
|
405
|
+
* If full context is available (baseUrl + apiKey configured), fetches
|
|
406
|
+
* organization, project, artifact, and related sections for a rich prompt.
|
|
407
|
+
*/
|
|
408
|
+
async execute(task) {
|
|
409
|
+
try {
|
|
410
|
+
let prompt;
|
|
411
|
+
let fullContext = null;
|
|
412
|
+
const useFullContext = this.config.useFullContext !== false && this.contextFetcher;
|
|
413
|
+
if (useFullContext) {
|
|
414
|
+
try {
|
|
415
|
+
fullContext = await this.contextFetcher.fetchTaskContext(task.taskId);
|
|
416
|
+
prompt = buildPromptWithContext(fullContext);
|
|
417
|
+
console.log(" \u{1F4DA} Using full context (org, project, artifact, related sections)");
|
|
418
|
+
} catch (contextError) {
|
|
419
|
+
console.warn(" \u26A0\uFE0F Could not fetch full context, using minimal prompt");
|
|
420
|
+
console.warn(` ${contextError instanceof Error ? contextError.message : contextError}`);
|
|
421
|
+
prompt = this.buildTaskPrompt(task);
|
|
422
|
+
}
|
|
423
|
+
} else {
|
|
424
|
+
prompt = this.buildTaskPrompt(task);
|
|
425
|
+
}
|
|
426
|
+
const output = await this.runClaude(prompt);
|
|
427
|
+
const { content, summary } = this.parseResponse(output, task.heading);
|
|
428
|
+
return {
|
|
429
|
+
success: true,
|
|
430
|
+
output: content,
|
|
431
|
+
summary,
|
|
432
|
+
promptUsed: prompt
|
|
433
|
+
};
|
|
434
|
+
} catch (error) {
|
|
435
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
436
|
+
return {
|
|
437
|
+
success: false,
|
|
438
|
+
output: "",
|
|
439
|
+
summary: `Failed: ${errorMessage}`,
|
|
440
|
+
error: errorMessage
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Run Claude Code CLI with the given prompt
|
|
446
|
+
*/
|
|
447
|
+
runClaude(prompt) {
|
|
448
|
+
return new Promise((resolve, reject) => {
|
|
449
|
+
const claudePath = this.config.claudePath || "claude";
|
|
450
|
+
const proc = spawn(claudePath, ["--print"], {
|
|
451
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
452
|
+
timeout: this.config.timeout
|
|
453
|
+
});
|
|
454
|
+
let stdout = "";
|
|
455
|
+
let stderr = "";
|
|
456
|
+
proc.stdout.on("data", (data) => {
|
|
457
|
+
stdout += data.toString();
|
|
458
|
+
});
|
|
459
|
+
proc.stderr.on("data", (data) => {
|
|
460
|
+
stderr += data.toString();
|
|
461
|
+
});
|
|
462
|
+
proc.on("close", (code) => {
|
|
463
|
+
if (code === 0) {
|
|
464
|
+
resolve(stdout.trim());
|
|
465
|
+
} else {
|
|
466
|
+
reject(new Error(stderr || `Claude exited with code ${code}`));
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
proc.on("error", (err) => {
|
|
470
|
+
if (err.code === "ENOENT") {
|
|
471
|
+
reject(new Error(
|
|
472
|
+
"Claude Code CLI not found. Please install it:\n npm install -g @anthropic-ai/claude-code"
|
|
473
|
+
));
|
|
474
|
+
} else {
|
|
475
|
+
reject(err);
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
proc.stdin.write(prompt);
|
|
479
|
+
proc.stdin.end();
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* Build the task prompt
|
|
484
|
+
*/
|
|
485
|
+
buildTaskPrompt(task) {
|
|
486
|
+
const parts = [];
|
|
487
|
+
const systemPrompt = this.config.systemPromptPrefix ? `${this.config.systemPromptPrefix}
|
|
488
|
+
|
|
489
|
+
${DEFAULT_SYSTEM_PROMPT}` : DEFAULT_SYSTEM_PROMPT;
|
|
490
|
+
parts.push(systemPrompt);
|
|
491
|
+
parts.push("");
|
|
492
|
+
parts.push("---");
|
|
493
|
+
parts.push("");
|
|
494
|
+
parts.push(`# Task: ${task.heading}`);
|
|
495
|
+
parts.push("");
|
|
496
|
+
if (task.artifactTitle) {
|
|
497
|
+
parts.push(`**Artifact:** ${task.artifactTitle}`);
|
|
498
|
+
}
|
|
499
|
+
if (task.priority) {
|
|
500
|
+
const priorityLabels = ["High", "Medium", "Low"];
|
|
501
|
+
parts.push(`**Priority:** ${priorityLabels[task.priority - 1] || "Medium"}`);
|
|
502
|
+
}
|
|
503
|
+
parts.push("");
|
|
504
|
+
parts.push("## Description");
|
|
505
|
+
parts.push(task.content || "No additional description provided.");
|
|
506
|
+
parts.push("");
|
|
507
|
+
if (task.context && Object.keys(task.context).length > 0) {
|
|
508
|
+
parts.push("## Additional Context");
|
|
509
|
+
parts.push("```json");
|
|
510
|
+
parts.push(JSON.stringify(task.context, null, 2));
|
|
511
|
+
parts.push("```");
|
|
512
|
+
parts.push("");
|
|
513
|
+
}
|
|
514
|
+
parts.push("## Instructions");
|
|
515
|
+
parts.push("Complete this task and provide your output below.");
|
|
516
|
+
return parts.join("\n");
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Parse the response to extract output and summary
|
|
520
|
+
*/
|
|
521
|
+
parseResponse(fullOutput, taskHeading) {
|
|
522
|
+
const summaryMatch = fullOutput.match(/SUMMARY:\s*(.+?)(?:\n|$)/i);
|
|
523
|
+
if (summaryMatch) {
|
|
524
|
+
const summary2 = summaryMatch[1].trim();
|
|
525
|
+
const content = fullOutput.replace(/SUMMARY:\s*.+?(?:\n|$)/i, "").trim();
|
|
526
|
+
return { content, summary: summary2 };
|
|
527
|
+
}
|
|
528
|
+
const lines = fullOutput.split("\n").filter((l) => l.trim());
|
|
529
|
+
const firstLine = lines[0] || "";
|
|
530
|
+
const summary = firstLine.length > 100 ? `${firstLine.substring(0, 97)}...` : firstLine || `Completed: ${taskHeading}`;
|
|
531
|
+
return { content: fullOutput, summary };
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Test that Claude Code CLI is available and working
|
|
535
|
+
*/
|
|
536
|
+
async testConnection() {
|
|
537
|
+
try {
|
|
538
|
+
const output = await this.runClaude('Say "connected" and nothing else.');
|
|
539
|
+
return output.toLowerCase().includes("connected");
|
|
540
|
+
} catch {
|
|
541
|
+
return false;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* Check if Claude Code CLI is installed
|
|
546
|
+
*/
|
|
547
|
+
async isInstalled() {
|
|
548
|
+
return new Promise((resolve) => {
|
|
549
|
+
const proc = spawn(this.config.claudePath || "claude", ["--version"], {
|
|
550
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
551
|
+
});
|
|
552
|
+
proc.on("close", (code) => {
|
|
553
|
+
resolve(code === 0);
|
|
554
|
+
});
|
|
555
|
+
proc.on("error", () => {
|
|
556
|
+
resolve(false);
|
|
557
|
+
});
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
};
|
|
561
|
+
function createExecutor(config) {
|
|
562
|
+
return new ClaudeExecutor(config);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// src/listener.ts
|
|
566
|
+
import EventSource from "eventsource";
|
|
567
|
+
var DEFAULT_BASE_URL2 = "https://artyfacts.dev/api/v1";
|
|
568
|
+
var EVENT_TYPES = [
|
|
569
|
+
"connected",
|
|
570
|
+
"heartbeat",
|
|
571
|
+
"task_assigned",
|
|
572
|
+
"task_unblocked",
|
|
573
|
+
"blocker_resolved",
|
|
574
|
+
"notification"
|
|
575
|
+
];
|
|
576
|
+
var ArtyfactsListener = class {
|
|
577
|
+
config;
|
|
578
|
+
eventSource = null;
|
|
579
|
+
callbacks = /* @__PURE__ */ new Map();
|
|
580
|
+
allCallbacks = /* @__PURE__ */ new Set();
|
|
581
|
+
state = "disconnected";
|
|
582
|
+
reconnectAttempts = 0;
|
|
583
|
+
maxReconnectAttempts = 10;
|
|
584
|
+
reconnectDelay = 1e3;
|
|
585
|
+
constructor(config) {
|
|
586
|
+
if (!config.apiKey) {
|
|
587
|
+
throw new Error("API key is required");
|
|
588
|
+
}
|
|
589
|
+
if (!config.agentId) {
|
|
590
|
+
throw new Error("Agent ID is required");
|
|
591
|
+
}
|
|
592
|
+
this.config = {
|
|
593
|
+
...config,
|
|
594
|
+
baseUrl: config.baseUrl || DEFAULT_BASE_URL2
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Get current connection state
|
|
599
|
+
*/
|
|
600
|
+
get connectionState() {
|
|
601
|
+
return this.state;
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Check if connected
|
|
605
|
+
*/
|
|
606
|
+
get isConnected() {
|
|
607
|
+
return this.state === "connected";
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Subscribe to all events
|
|
611
|
+
*/
|
|
612
|
+
subscribe(callback) {
|
|
613
|
+
this.allCallbacks.add(callback);
|
|
614
|
+
return () => {
|
|
615
|
+
this.allCallbacks.delete(callback);
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* Subscribe to a specific event type
|
|
620
|
+
*/
|
|
621
|
+
on(type, callback) {
|
|
622
|
+
if (!this.callbacks.has(type)) {
|
|
623
|
+
this.callbacks.set(type, /* @__PURE__ */ new Set());
|
|
624
|
+
}
|
|
625
|
+
this.callbacks.get(type).add(callback);
|
|
626
|
+
return () => {
|
|
627
|
+
const typeCallbacks = this.callbacks.get(type);
|
|
628
|
+
if (typeCallbacks) {
|
|
629
|
+
typeCallbacks.delete(callback);
|
|
630
|
+
if (typeCallbacks.size === 0) {
|
|
631
|
+
this.callbacks.delete(type);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Connect to the SSE stream
|
|
638
|
+
*/
|
|
639
|
+
connect() {
|
|
640
|
+
if (this.eventSource) {
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
this.setState("connecting");
|
|
644
|
+
const url = new URL(`${this.config.baseUrl}/events/stream`);
|
|
645
|
+
url.searchParams.set("apiKey", this.config.apiKey);
|
|
646
|
+
url.searchParams.set("agentId", this.config.agentId);
|
|
647
|
+
this.eventSource = new EventSource(url.toString(), {
|
|
648
|
+
headers: {
|
|
649
|
+
"Authorization": `Bearer ${this.config.apiKey}`
|
|
650
|
+
}
|
|
651
|
+
});
|
|
652
|
+
this.eventSource.onopen = () => {
|
|
653
|
+
this.reconnectAttempts = 0;
|
|
654
|
+
this.reconnectDelay = 1e3;
|
|
655
|
+
this.setState("connected");
|
|
656
|
+
};
|
|
657
|
+
this.eventSource.onmessage = (event) => {
|
|
658
|
+
this.handleMessage(event);
|
|
659
|
+
};
|
|
660
|
+
this.eventSource.onerror = (event) => {
|
|
661
|
+
this.handleError(event);
|
|
662
|
+
};
|
|
663
|
+
for (const eventType of EVENT_TYPES) {
|
|
664
|
+
this.eventSource.addEventListener(eventType, (event) => {
|
|
665
|
+
this.handleMessage(event, eventType);
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
/**
|
|
670
|
+
* Disconnect from the SSE stream
|
|
671
|
+
*/
|
|
672
|
+
disconnect() {
|
|
673
|
+
if (this.eventSource) {
|
|
674
|
+
this.eventSource.close();
|
|
675
|
+
this.eventSource = null;
|
|
676
|
+
}
|
|
677
|
+
this.setState("disconnected");
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Reconnect to the SSE stream
|
|
681
|
+
*/
|
|
682
|
+
reconnect() {
|
|
683
|
+
this.disconnect();
|
|
684
|
+
this.connect();
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* Handle incoming SSE message
|
|
688
|
+
*/
|
|
689
|
+
handleMessage(event, eventType) {
|
|
690
|
+
try {
|
|
691
|
+
const data = JSON.parse(event.data);
|
|
692
|
+
const rawData = data.data || data;
|
|
693
|
+
const normalizedData = rawData.task_id ? {
|
|
694
|
+
taskId: rawData.task_id,
|
|
695
|
+
sectionId: rawData.section_id,
|
|
696
|
+
artifactId: rawData.artifact_id,
|
|
697
|
+
artifactTitle: rawData.artifact_title,
|
|
698
|
+
heading: rawData.heading,
|
|
699
|
+
content: rawData.content,
|
|
700
|
+
assignedTo: rawData.assigned_to,
|
|
701
|
+
assignedAt: rawData.assigned_at,
|
|
702
|
+
priority: rawData.priority,
|
|
703
|
+
...rawData
|
|
704
|
+
// Keep original fields too
|
|
705
|
+
} : rawData;
|
|
706
|
+
const artyfactsEvent = {
|
|
707
|
+
type: eventType || data.type || "unknown",
|
|
708
|
+
timestamp: data.timestamp || (/* @__PURE__ */ new Date()).toISOString(),
|
|
709
|
+
data: normalizedData
|
|
710
|
+
};
|
|
711
|
+
const typeCallbacks = this.callbacks.get(artyfactsEvent.type);
|
|
712
|
+
if (typeCallbacks) {
|
|
713
|
+
for (const callback of typeCallbacks) {
|
|
714
|
+
this.safeCallCallback(callback, artyfactsEvent);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
for (const callback of this.allCallbacks) {
|
|
718
|
+
this.safeCallCallback(callback, artyfactsEvent);
|
|
719
|
+
}
|
|
720
|
+
} catch (err) {
|
|
721
|
+
console.error("[Listener] Failed to parse SSE message:", event.data, err);
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Safely call a callback, handling async and errors
|
|
726
|
+
*/
|
|
727
|
+
async safeCallCallback(callback, event) {
|
|
728
|
+
try {
|
|
729
|
+
await callback(event);
|
|
730
|
+
} catch (err) {
|
|
731
|
+
console.error(`[Listener] Error in event callback for '${event.type}':`, err);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* Handle SSE error
|
|
736
|
+
*/
|
|
737
|
+
handleError(event) {
|
|
738
|
+
if (this.eventSource?.readyState === EventSource.CONNECTING) {
|
|
739
|
+
this.setState("reconnecting");
|
|
740
|
+
} else if (this.eventSource?.readyState === EventSource.CLOSED) {
|
|
741
|
+
this.setState("disconnected");
|
|
742
|
+
if (this.reconnectAttempts < this.maxReconnectAttempts) {
|
|
743
|
+
this.reconnectAttempts++;
|
|
744
|
+
this.reconnectDelay = Math.min(this.reconnectDelay * 2, 3e4);
|
|
745
|
+
console.log(
|
|
746
|
+
`[Listener] Connection lost, reconnecting in ${this.reconnectDelay / 1e3}s (attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts})`
|
|
747
|
+
);
|
|
748
|
+
setTimeout(() => {
|
|
749
|
+
if (this.state === "disconnected") {
|
|
750
|
+
this.connect();
|
|
751
|
+
}
|
|
752
|
+
}, this.reconnectDelay);
|
|
753
|
+
} else {
|
|
754
|
+
const error = new Error("Max reconnection attempts reached");
|
|
755
|
+
this.config.onError?.(error);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* Update connection state
|
|
761
|
+
*/
|
|
762
|
+
setState(state) {
|
|
763
|
+
if (this.state !== state) {
|
|
764
|
+
this.state = state;
|
|
765
|
+
this.config.onStateChange?.(state);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
};
|
|
769
|
+
function createListener(config) {
|
|
770
|
+
return new ArtyfactsListener(config);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
export {
|
|
774
|
+
loadCredentials,
|
|
775
|
+
saveCredentials,
|
|
776
|
+
clearCredentials,
|
|
777
|
+
runDeviceAuth,
|
|
778
|
+
promptForApiKey,
|
|
779
|
+
getCredentials,
|
|
780
|
+
ContextFetcher,
|
|
781
|
+
buildPromptWithContext,
|
|
782
|
+
createContextFetcher,
|
|
783
|
+
ClaudeExecutor,
|
|
784
|
+
createExecutor,
|
|
785
|
+
ArtyfactsListener,
|
|
786
|
+
createListener
|
|
787
|
+
};
|
package/dist/cli.js
CHANGED
|
@@ -251,16 +251,34 @@ function buildPromptWithContext(context) {
|
|
|
251
251
|
|
|
252
252
|
Your job is to complete the assigned task. You have full context about the organization, project, and related work.
|
|
253
253
|
|
|
254
|
-
|
|
254
|
+
## Available Tools
|
|
255
|
+
|
|
256
|
+
You have access to Artyfacts MCP tools. USE THEM to complete your task:
|
|
257
|
+
|
|
258
|
+
- **create_artifact** - Create new artifacts (documents, specs, reports)
|
|
259
|
+
- **create_section** - Add sections to artifacts (content, tasks, decisions)
|
|
260
|
+
- **update_section** - Update existing sections
|
|
261
|
+
- **create_agent** - Create new AI agents with specific roles
|
|
262
|
+
- **list_artifacts** - Query existing artifacts
|
|
263
|
+
- **list_sections** - Query sections within an artifact
|
|
264
|
+
- **complete_task** - Mark a task as complete
|
|
265
|
+
- **block_task** - Block a task with a reason
|
|
266
|
+
- **create_blocker** - Create a decision blocker
|
|
267
|
+
|
|
268
|
+
IMPORTANT: When asked to create agents or update artifacts, USE THE TOOLS. Don't just describe what you would do - actually do it with the tools.
|
|
269
|
+
|
|
270
|
+
## Guidelines
|
|
271
|
+
|
|
255
272
|
- Be thorough but concise
|
|
256
|
-
-
|
|
257
|
-
- If the task requires
|
|
258
|
-
- If the task requires
|
|
273
|
+
- USE THE TOOLS to take action, don't just analyze
|
|
274
|
+
- If the task requires creating something, use create_artifact or create_section
|
|
275
|
+
- If the task requires creating agents, use create_agent
|
|
259
276
|
- If you cannot complete the task, explain why
|
|
260
277
|
|
|
261
278
|
Format your response as follows:
|
|
262
|
-
1. First,
|
|
263
|
-
2.
|
|
279
|
+
1. First, use the tools to complete the task
|
|
280
|
+
2. Then summarize what you did
|
|
281
|
+
3. End with a brief summary line starting with "SUMMARY:"`);
|
|
264
282
|
parts.push("");
|
|
265
283
|
parts.push("---");
|
|
266
284
|
parts.push("");
|
|
@@ -367,21 +385,35 @@ function createContextFetcher(config) {
|
|
|
367
385
|
var DEFAULT_TIMEOUT = 5 * 60 * 1e3;
|
|
368
386
|
var DEFAULT_SYSTEM_PROMPT = `You are an AI agent working within the Artyfacts task management system.
|
|
369
387
|
|
|
370
|
-
Your job is to complete tasks assigned to you
|
|
371
|
-
1. Understand the requirements from the task heading and content
|
|
372
|
-
2. Complete the task to the best of your ability
|
|
373
|
-
3. Provide a clear, actionable output
|
|
388
|
+
Your job is to complete tasks assigned to you using the available tools.
|
|
374
389
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
-
|
|
390
|
+
## Available Tools
|
|
391
|
+
|
|
392
|
+
You have access to Artyfacts MCP tools. USE THEM to complete your task:
|
|
393
|
+
|
|
394
|
+
- **create_artifact** - Create new artifacts (documents, specs, reports)
|
|
395
|
+
- **create_section** - Add sections to artifacts (content, tasks, decisions)
|
|
396
|
+
- **update_section** - Update existing sections
|
|
397
|
+
- **create_agent** - Create new AI agents with specific roles
|
|
398
|
+
- **list_artifacts** - Query existing artifacts
|
|
399
|
+
- **list_sections** - Query sections within an artifact
|
|
400
|
+
- **complete_task** - Mark a task as complete
|
|
401
|
+
- **block_task** - Block a task with a reason
|
|
402
|
+
- **create_blocker** - Create a decision blocker
|
|
403
|
+
|
|
404
|
+
IMPORTANT: When asked to create agents or update artifacts, USE THE TOOLS. Don't just describe what you would do - actually do it.
|
|
405
|
+
|
|
406
|
+
## Guidelines
|
|
407
|
+
|
|
408
|
+
- USE THE TOOLS to take action
|
|
409
|
+
- If creating something, use create_artifact or create_section
|
|
410
|
+
- If creating agents, use create_agent
|
|
380
411
|
- If you cannot complete the task, explain why
|
|
381
412
|
|
|
382
413
|
Format your response as follows:
|
|
383
|
-
1. First,
|
|
384
|
-
2.
|
|
414
|
+
1. First, use the tools to complete the task
|
|
415
|
+
2. Summarize what you accomplished
|
|
416
|
+
3. End with a brief summary line starting with "SUMMARY:"`;
|
|
385
417
|
var ClaudeExecutor = class {
|
|
386
418
|
config;
|
|
387
419
|
contextFetcher = null;
|
|
@@ -897,7 +929,7 @@ async function checkAndClaimTasks(baseUrl, apiKey, agentId, activeTasks, executo
|
|
|
897
929
|
}
|
|
898
930
|
console.log(`\u{1F4EC} Found ${tasks.length} claimable task(s)`);
|
|
899
931
|
for (const task of tasks) {
|
|
900
|
-
if (activeTasks.has(task.
|
|
932
|
+
if (activeTasks.has(task.id)) {
|
|
901
933
|
continue;
|
|
902
934
|
}
|
|
903
935
|
console.log(`
|
|
@@ -920,11 +952,11 @@ async function checkAndClaimTasks(baseUrl, apiKey, agentId, activeTasks, executo
|
|
|
920
952
|
});
|
|
921
953
|
const taskUuid = claimData.task?.id || task.id;
|
|
922
954
|
console.log(` \u{1F4CE} Using task UUID: ${taskUuid} (from queue: ${task.id})`);
|
|
923
|
-
activeTasks.add(task.
|
|
955
|
+
activeTasks.add(task.id);
|
|
924
956
|
console.log(" \u2713 Claimed!");
|
|
925
957
|
if (dryRun) {
|
|
926
958
|
console.log(" \u{1F4CB} Dry run - not executing");
|
|
927
|
-
activeTasks.delete(task.
|
|
959
|
+
activeTasks.delete(task.id);
|
|
928
960
|
continue;
|
|
929
961
|
}
|
|
930
962
|
console.log(" \u2192 Executing with Claude...");
|
|
@@ -961,7 +993,7 @@ async function checkAndClaimTasks(baseUrl, apiKey, agentId, activeTasks, executo
|
|
|
961
993
|
} catch (error) {
|
|
962
994
|
console.error(` \u2192 \u274C Error:`, error instanceof Error ? error.message : error);
|
|
963
995
|
} finally {
|
|
964
|
-
activeTasks.delete(task.
|
|
996
|
+
activeTasks.delete(task.id);
|
|
965
997
|
}
|
|
966
998
|
break;
|
|
967
999
|
}
|
package/dist/cli.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
getCredentials,
|
|
7
7
|
loadCredentials,
|
|
8
8
|
promptForApiKey
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-CNJCMX2D.mjs";
|
|
10
10
|
|
|
11
11
|
// src/cli.ts
|
|
12
12
|
import { Command } from "commander";
|
|
@@ -138,7 +138,7 @@ async function checkAndClaimTasks(baseUrl, apiKey, agentId, activeTasks, executo
|
|
|
138
138
|
}
|
|
139
139
|
console.log(`\u{1F4EC} Found ${tasks.length} claimable task(s)`);
|
|
140
140
|
for (const task of tasks) {
|
|
141
|
-
if (activeTasks.has(task.
|
|
141
|
+
if (activeTasks.has(task.id)) {
|
|
142
142
|
continue;
|
|
143
143
|
}
|
|
144
144
|
console.log(`
|
|
@@ -161,11 +161,11 @@ async function checkAndClaimTasks(baseUrl, apiKey, agentId, activeTasks, executo
|
|
|
161
161
|
});
|
|
162
162
|
const taskUuid = claimData.task?.id || task.id;
|
|
163
163
|
console.log(` \u{1F4CE} Using task UUID: ${taskUuid} (from queue: ${task.id})`);
|
|
164
|
-
activeTasks.add(task.
|
|
164
|
+
activeTasks.add(task.id);
|
|
165
165
|
console.log(" \u2713 Claimed!");
|
|
166
166
|
if (dryRun) {
|
|
167
167
|
console.log(" \u{1F4CB} Dry run - not executing");
|
|
168
|
-
activeTasks.delete(task.
|
|
168
|
+
activeTasks.delete(task.id);
|
|
169
169
|
continue;
|
|
170
170
|
}
|
|
171
171
|
console.log(" \u2192 Executing with Claude...");
|
|
@@ -202,7 +202,7 @@ async function checkAndClaimTasks(baseUrl, apiKey, agentId, activeTasks, executo
|
|
|
202
202
|
} catch (error) {
|
|
203
203
|
console.error(` \u2192 \u274C Error:`, error instanceof Error ? error.message : error);
|
|
204
204
|
} finally {
|
|
205
|
-
activeTasks.delete(task.
|
|
205
|
+
activeTasks.delete(task.id);
|
|
206
206
|
}
|
|
207
207
|
break;
|
|
208
208
|
}
|
package/dist/index.js
CHANGED
|
@@ -281,16 +281,34 @@ function buildPromptWithContext(context) {
|
|
|
281
281
|
|
|
282
282
|
Your job is to complete the assigned task. You have full context about the organization, project, and related work.
|
|
283
283
|
|
|
284
|
-
|
|
284
|
+
## Available Tools
|
|
285
|
+
|
|
286
|
+
You have access to Artyfacts MCP tools. USE THEM to complete your task:
|
|
287
|
+
|
|
288
|
+
- **create_artifact** - Create new artifacts (documents, specs, reports)
|
|
289
|
+
- **create_section** - Add sections to artifacts (content, tasks, decisions)
|
|
290
|
+
- **update_section** - Update existing sections
|
|
291
|
+
- **create_agent** - Create new AI agents with specific roles
|
|
292
|
+
- **list_artifacts** - Query existing artifacts
|
|
293
|
+
- **list_sections** - Query sections within an artifact
|
|
294
|
+
- **complete_task** - Mark a task as complete
|
|
295
|
+
- **block_task** - Block a task with a reason
|
|
296
|
+
- **create_blocker** - Create a decision blocker
|
|
297
|
+
|
|
298
|
+
IMPORTANT: When asked to create agents or update artifacts, USE THE TOOLS. Don't just describe what you would do - actually do it with the tools.
|
|
299
|
+
|
|
300
|
+
## Guidelines
|
|
301
|
+
|
|
285
302
|
- Be thorough but concise
|
|
286
|
-
-
|
|
287
|
-
- If the task requires
|
|
288
|
-
- If the task requires
|
|
303
|
+
- USE THE TOOLS to take action, don't just analyze
|
|
304
|
+
- If the task requires creating something, use create_artifact or create_section
|
|
305
|
+
- If the task requires creating agents, use create_agent
|
|
289
306
|
- If you cannot complete the task, explain why
|
|
290
307
|
|
|
291
308
|
Format your response as follows:
|
|
292
|
-
1. First,
|
|
293
|
-
2.
|
|
309
|
+
1. First, use the tools to complete the task
|
|
310
|
+
2. Then summarize what you did
|
|
311
|
+
3. End with a brief summary line starting with "SUMMARY:"`);
|
|
294
312
|
parts.push("");
|
|
295
313
|
parts.push("---");
|
|
296
314
|
parts.push("");
|
|
@@ -397,21 +415,35 @@ function createContextFetcher(config) {
|
|
|
397
415
|
var DEFAULT_TIMEOUT = 5 * 60 * 1e3;
|
|
398
416
|
var DEFAULT_SYSTEM_PROMPT = `You are an AI agent working within the Artyfacts task management system.
|
|
399
417
|
|
|
400
|
-
Your job is to complete tasks assigned to you
|
|
401
|
-
1. Understand the requirements from the task heading and content
|
|
402
|
-
2. Complete the task to the best of your ability
|
|
403
|
-
3. Provide a clear, actionable output
|
|
418
|
+
Your job is to complete tasks assigned to you using the available tools.
|
|
404
419
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
-
|
|
420
|
+
## Available Tools
|
|
421
|
+
|
|
422
|
+
You have access to Artyfacts MCP tools. USE THEM to complete your task:
|
|
423
|
+
|
|
424
|
+
- **create_artifact** - Create new artifacts (documents, specs, reports)
|
|
425
|
+
- **create_section** - Add sections to artifacts (content, tasks, decisions)
|
|
426
|
+
- **update_section** - Update existing sections
|
|
427
|
+
- **create_agent** - Create new AI agents with specific roles
|
|
428
|
+
- **list_artifacts** - Query existing artifacts
|
|
429
|
+
- **list_sections** - Query sections within an artifact
|
|
430
|
+
- **complete_task** - Mark a task as complete
|
|
431
|
+
- **block_task** - Block a task with a reason
|
|
432
|
+
- **create_blocker** - Create a decision blocker
|
|
433
|
+
|
|
434
|
+
IMPORTANT: When asked to create agents or update artifacts, USE THE TOOLS. Don't just describe what you would do - actually do it.
|
|
435
|
+
|
|
436
|
+
## Guidelines
|
|
437
|
+
|
|
438
|
+
- USE THE TOOLS to take action
|
|
439
|
+
- If creating something, use create_artifact or create_section
|
|
440
|
+
- If creating agents, use create_agent
|
|
410
441
|
- If you cannot complete the task, explain why
|
|
411
442
|
|
|
412
443
|
Format your response as follows:
|
|
413
|
-
1. First,
|
|
414
|
-
2.
|
|
444
|
+
1. First, use the tools to complete the task
|
|
445
|
+
2. Summarize what you accomplished
|
|
446
|
+
3. End with a brief summary line starting with "SUMMARY:"`;
|
|
415
447
|
var ClaudeExecutor = class {
|
|
416
448
|
config;
|
|
417
449
|
contextFetcher = null;
|
package/dist/index.mjs
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
promptForApiKey,
|
|
13
13
|
runDeviceAuth,
|
|
14
14
|
saveCredentials
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-CNJCMX2D.mjs";
|
|
16
16
|
|
|
17
17
|
// node_modules/@anthropic-ai/sdk/internal/tslib.mjs
|
|
18
18
|
function __classPrivateFieldSet(receiver, state, value, kind, f) {
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -245,7 +245,8 @@ async function checkAndClaimTasks(
|
|
|
245
245
|
|
|
246
246
|
// Process first available task
|
|
247
247
|
for (const task of tasks) {
|
|
248
|
-
|
|
248
|
+
// Use task.id (UUID) for deduplication - matches SSE taskId
|
|
249
|
+
if (activeTasks.has(task.id)) {
|
|
249
250
|
continue; // Already processing
|
|
250
251
|
}
|
|
251
252
|
|
|
@@ -281,12 +282,12 @@ async function checkAndClaimTasks(
|
|
|
281
282
|
console.log(` 📎 Using task UUID: ${taskUuid} (from queue: ${task.id})`); // DEBUG
|
|
282
283
|
|
|
283
284
|
// Successfully claimed - now execute
|
|
284
|
-
activeTasks.add(task.
|
|
285
|
+
activeTasks.add(task.id);
|
|
285
286
|
console.log(' ✓ Claimed!');
|
|
286
287
|
|
|
287
288
|
if (dryRun) {
|
|
288
289
|
console.log(' 📋 Dry run - not executing');
|
|
289
|
-
activeTasks.delete(task.
|
|
290
|
+
activeTasks.delete(task.id);
|
|
290
291
|
continue;
|
|
291
292
|
}
|
|
292
293
|
|
|
@@ -324,7 +325,7 @@ async function checkAndClaimTasks(
|
|
|
324
325
|
} catch (error) {
|
|
325
326
|
console.error(` → ❌ Error:`, error instanceof Error ? error.message : error);
|
|
326
327
|
} finally {
|
|
327
|
-
activeTasks.delete(task.
|
|
328
|
+
activeTasks.delete(task.id);
|
|
328
329
|
}
|
|
329
330
|
|
|
330
331
|
// Only process one task at a time for now
|
package/src/context.ts
CHANGED
|
@@ -108,16 +108,34 @@ export function buildPromptWithContext(context: TaskFullContext): string {
|
|
|
108
108
|
|
|
109
109
|
Your job is to complete the assigned task. You have full context about the organization, project, and related work.
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
## Available Tools
|
|
112
|
+
|
|
113
|
+
You have access to Artyfacts MCP tools. USE THEM to complete your task:
|
|
114
|
+
|
|
115
|
+
- **create_artifact** - Create new artifacts (documents, specs, reports)
|
|
116
|
+
- **create_section** - Add sections to artifacts (content, tasks, decisions)
|
|
117
|
+
- **update_section** - Update existing sections
|
|
118
|
+
- **create_agent** - Create new AI agents with specific roles
|
|
119
|
+
- **list_artifacts** - Query existing artifacts
|
|
120
|
+
- **list_sections** - Query sections within an artifact
|
|
121
|
+
- **complete_task** - Mark a task as complete
|
|
122
|
+
- **block_task** - Block a task with a reason
|
|
123
|
+
- **create_blocker** - Create a decision blocker
|
|
124
|
+
|
|
125
|
+
IMPORTANT: When asked to create agents or update artifacts, USE THE TOOLS. Don't just describe what you would do - actually do it with the tools.
|
|
126
|
+
|
|
127
|
+
## Guidelines
|
|
128
|
+
|
|
112
129
|
- Be thorough but concise
|
|
113
|
-
-
|
|
114
|
-
- If the task requires
|
|
115
|
-
- If the task requires
|
|
130
|
+
- USE THE TOOLS to take action, don't just analyze
|
|
131
|
+
- If the task requires creating something, use create_artifact or create_section
|
|
132
|
+
- If the task requires creating agents, use create_agent
|
|
116
133
|
- If you cannot complete the task, explain why
|
|
117
134
|
|
|
118
135
|
Format your response as follows:
|
|
119
|
-
1. First,
|
|
120
|
-
2.
|
|
136
|
+
1. First, use the tools to complete the task
|
|
137
|
+
2. Then summarize what you did
|
|
138
|
+
3. End with a brief summary line starting with "SUMMARY:"`);
|
|
121
139
|
|
|
122
140
|
parts.push('');
|
|
123
141
|
parts.push('---');
|
package/src/executor.ts
CHANGED
|
@@ -68,21 +68,35 @@ const DEFAULT_TIMEOUT = 5 * 60 * 1000; // 5 minutes
|
|
|
68
68
|
|
|
69
69
|
const DEFAULT_SYSTEM_PROMPT = `You are an AI agent working within the Artyfacts task management system.
|
|
70
70
|
|
|
71
|
-
Your job is to complete tasks assigned to you
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
-
|
|
78
|
-
-
|
|
79
|
-
-
|
|
80
|
-
-
|
|
71
|
+
Your job is to complete tasks assigned to you using the available tools.
|
|
72
|
+
|
|
73
|
+
## Available Tools
|
|
74
|
+
|
|
75
|
+
You have access to Artyfacts MCP tools. USE THEM to complete your task:
|
|
76
|
+
|
|
77
|
+
- **create_artifact** - Create new artifacts (documents, specs, reports)
|
|
78
|
+
- **create_section** - Add sections to artifacts (content, tasks, decisions)
|
|
79
|
+
- **update_section** - Update existing sections
|
|
80
|
+
- **create_agent** - Create new AI agents with specific roles
|
|
81
|
+
- **list_artifacts** - Query existing artifacts
|
|
82
|
+
- **list_sections** - Query sections within an artifact
|
|
83
|
+
- **complete_task** - Mark a task as complete
|
|
84
|
+
- **block_task** - Block a task with a reason
|
|
85
|
+
- **create_blocker** - Create a decision blocker
|
|
86
|
+
|
|
87
|
+
IMPORTANT: When asked to create agents or update artifacts, USE THE TOOLS. Don't just describe what you would do - actually do it.
|
|
88
|
+
|
|
89
|
+
## Guidelines
|
|
90
|
+
|
|
91
|
+
- USE THE TOOLS to take action
|
|
92
|
+
- If creating something, use create_artifact or create_section
|
|
93
|
+
- If creating agents, use create_agent
|
|
81
94
|
- If you cannot complete the task, explain why
|
|
82
95
|
|
|
83
96
|
Format your response as follows:
|
|
84
|
-
1. First,
|
|
85
|
-
2.
|
|
97
|
+
1. First, use the tools to complete the task
|
|
98
|
+
2. Summarize what you accomplished
|
|
99
|
+
3. End with a brief summary line starting with "SUMMARY:"`;
|
|
86
100
|
|
|
87
101
|
// ============================================================================
|
|
88
102
|
// Executor Class
|