projects-plus-sdk 0.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/LICENSE +21 -0
- package/README.md +228 -0
- package/dist/index.d.mts +674 -0
- package/dist/index.d.ts +674 -0
- package/dist/index.js +771 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +759 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +50 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,771 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/errors/index.ts
|
|
4
|
+
var ApiError = class _ApiError extends Error {
|
|
5
|
+
constructor(message, status, code, details) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.status = status;
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.details = details;
|
|
10
|
+
this.name = "ApiError";
|
|
11
|
+
Object.setPrototypeOf(this, _ApiError.prototype);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
var AuthenticationError = class _AuthenticationError extends ApiError {
|
|
15
|
+
constructor(message = "Invalid or missing API key") {
|
|
16
|
+
super(message, 401, "AUTHENTICATION_ERROR");
|
|
17
|
+
this.name = "AuthenticationError";
|
|
18
|
+
Object.setPrototypeOf(this, _AuthenticationError.prototype);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
var RateLimitError = class _RateLimitError extends ApiError {
|
|
22
|
+
constructor(message = "Rate limit exceeded", retryAfter) {
|
|
23
|
+
super(message, 429, "RATE_LIMIT_ERROR");
|
|
24
|
+
this.retryAfter = retryAfter;
|
|
25
|
+
this.name = "RateLimitError";
|
|
26
|
+
Object.setPrototypeOf(this, _RateLimitError.prototype);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
var NotFoundError = class _NotFoundError extends ApiError {
|
|
30
|
+
constructor(message = "Resource not found") {
|
|
31
|
+
super(message, 404, "NOT_FOUND_ERROR");
|
|
32
|
+
this.name = "NotFoundError";
|
|
33
|
+
Object.setPrototypeOf(this, _NotFoundError.prototype);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
var ValidationError = class _ValidationError extends ApiError {
|
|
37
|
+
constructor(message = "Invalid request", details) {
|
|
38
|
+
super(message, 400, "VALIDATION_ERROR", details);
|
|
39
|
+
this.name = "ValidationError";
|
|
40
|
+
Object.setPrototypeOf(this, _ValidationError.prototype);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
var ServerError = class _ServerError extends ApiError {
|
|
44
|
+
constructor(message = "Server error") {
|
|
45
|
+
super(message, 500, "SERVER_ERROR");
|
|
46
|
+
this.name = "ServerError";
|
|
47
|
+
Object.setPrototypeOf(this, _ServerError.prototype);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
var TimeoutError = class _TimeoutError extends ApiError {
|
|
51
|
+
constructor(message = "Request timed out") {
|
|
52
|
+
super(message, 408, "TIMEOUT_ERROR");
|
|
53
|
+
this.name = "TimeoutError";
|
|
54
|
+
Object.setPrototypeOf(this, _TimeoutError.prototype);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
var NetworkError = class _NetworkError extends ApiError {
|
|
58
|
+
constructor(message = "Network error") {
|
|
59
|
+
super(message, 0, "NETWORK_ERROR");
|
|
60
|
+
this.name = "NetworkError";
|
|
61
|
+
Object.setPrototypeOf(this, _NetworkError.prototype);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
function createApiError(status, message, details) {
|
|
65
|
+
switch (status) {
|
|
66
|
+
case 401:
|
|
67
|
+
return new AuthenticationError(message);
|
|
68
|
+
case 404:
|
|
69
|
+
return new NotFoundError(message);
|
|
70
|
+
case 429:
|
|
71
|
+
return new RateLimitError(message);
|
|
72
|
+
case 400:
|
|
73
|
+
return new ValidationError(message, details);
|
|
74
|
+
case 408:
|
|
75
|
+
return new TimeoutError(message);
|
|
76
|
+
default:
|
|
77
|
+
if (status >= 500) {
|
|
78
|
+
return new ServerError(message);
|
|
79
|
+
}
|
|
80
|
+
return new ApiError(message, status, void 0, details);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// src/utils/http.ts
|
|
85
|
+
var HttpClient = class {
|
|
86
|
+
config;
|
|
87
|
+
constructor(config) {
|
|
88
|
+
this.config = config;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Make an HTTP request with automatic retries
|
|
92
|
+
*/
|
|
93
|
+
async request(path, options = {}) {
|
|
94
|
+
const { method = "GET", body, params, headers = {}, skipRetry = false } = options;
|
|
95
|
+
const url = this.buildUrl(path, params);
|
|
96
|
+
const requestInit = {
|
|
97
|
+
method,
|
|
98
|
+
headers: {
|
|
99
|
+
"Content-Type": "application/json",
|
|
100
|
+
"X-API-Key": this.config.apiKey,
|
|
101
|
+
...headers
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
if (body !== void 0) {
|
|
105
|
+
requestInit.body = JSON.stringify(body);
|
|
106
|
+
}
|
|
107
|
+
const maxAttempts = skipRetry ? 1 : this.config.retries;
|
|
108
|
+
let lastError = null;
|
|
109
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
110
|
+
try {
|
|
111
|
+
const response = await this.fetchWithTimeout(url, requestInit);
|
|
112
|
+
return await this.handleResponse(response);
|
|
113
|
+
} catch (error) {
|
|
114
|
+
lastError = error;
|
|
115
|
+
if (error instanceof AuthenticationError || error instanceof ApiError && error.status < 500) {
|
|
116
|
+
throw error;
|
|
117
|
+
}
|
|
118
|
+
if (attempt < maxAttempts) {
|
|
119
|
+
const delay = this.calculateRetryDelay(attempt, error);
|
|
120
|
+
await this.sleep(delay);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
throw lastError ?? new NetworkError("Request failed after retries");
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Build URL with query parameters
|
|
128
|
+
*/
|
|
129
|
+
buildUrl(path, params) {
|
|
130
|
+
const url = new URL(path, this.config.baseUrl);
|
|
131
|
+
if (params) {
|
|
132
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
133
|
+
if (value !== void 0) {
|
|
134
|
+
url.searchParams.append(key, String(value));
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
return url.toString();
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Fetch with timeout
|
|
142
|
+
*/
|
|
143
|
+
async fetchWithTimeout(url, init) {
|
|
144
|
+
const controller = new AbortController();
|
|
145
|
+
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
146
|
+
try {
|
|
147
|
+
const response = await fetch(url, {
|
|
148
|
+
...init,
|
|
149
|
+
signal: controller.signal
|
|
150
|
+
});
|
|
151
|
+
return response;
|
|
152
|
+
} catch (error) {
|
|
153
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
154
|
+
throw new TimeoutError(`Request timed out after ${this.config.timeout}ms`);
|
|
155
|
+
}
|
|
156
|
+
throw new NetworkError(
|
|
157
|
+
error instanceof Error ? error.message : "Network error"
|
|
158
|
+
);
|
|
159
|
+
} finally {
|
|
160
|
+
clearTimeout(timeoutId);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Handle response and parse JSON
|
|
165
|
+
*/
|
|
166
|
+
async handleResponse(response) {
|
|
167
|
+
let data;
|
|
168
|
+
const contentType = response.headers.get("content-type");
|
|
169
|
+
if (contentType?.includes("application/json")) {
|
|
170
|
+
try {
|
|
171
|
+
data = await response.json();
|
|
172
|
+
} catch {
|
|
173
|
+
data = null;
|
|
174
|
+
}
|
|
175
|
+
} else {
|
|
176
|
+
data = await response.text();
|
|
177
|
+
}
|
|
178
|
+
if (!response.ok) {
|
|
179
|
+
const message = this.extractErrorMessage(data) ?? response.statusText;
|
|
180
|
+
if (response.status === 429) {
|
|
181
|
+
const retryAfter = parseInt(
|
|
182
|
+
response.headers.get("Retry-After") ?? "60",
|
|
183
|
+
10
|
|
184
|
+
);
|
|
185
|
+
throw new RateLimitError(message, retryAfter);
|
|
186
|
+
}
|
|
187
|
+
throw createApiError(response.status, message, data);
|
|
188
|
+
}
|
|
189
|
+
return data;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Extract error message from response data
|
|
193
|
+
*/
|
|
194
|
+
extractErrorMessage(data) {
|
|
195
|
+
if (typeof data === "string") return data;
|
|
196
|
+
if (typeof data === "object" && data !== null) {
|
|
197
|
+
const obj = data;
|
|
198
|
+
if (typeof obj["error"] === "string") return obj["error"];
|
|
199
|
+
if (typeof obj["message"] === "string") return obj["message"];
|
|
200
|
+
}
|
|
201
|
+
return void 0;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Calculate retry delay with exponential backoff
|
|
205
|
+
*/
|
|
206
|
+
calculateRetryDelay(attempt, error) {
|
|
207
|
+
if (error instanceof RateLimitError && error.retryAfter) {
|
|
208
|
+
return error.retryAfter * 1e3;
|
|
209
|
+
}
|
|
210
|
+
return this.config.retryDelay * Math.pow(2, attempt - 1);
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Sleep for the specified duration
|
|
214
|
+
*/
|
|
215
|
+
sleep(ms) {
|
|
216
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
// src/resources/context.ts
|
|
221
|
+
var ContextResource = class {
|
|
222
|
+
constructor(http) {
|
|
223
|
+
this.http = http;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Get theme context including all projects and tasks
|
|
227
|
+
*
|
|
228
|
+
* @example
|
|
229
|
+
* ```ts
|
|
230
|
+
* const context = await pp.context.get();
|
|
231
|
+
* console.log(context.theme.name);
|
|
232
|
+
* console.log(context.projects);
|
|
233
|
+
* ```
|
|
234
|
+
*/
|
|
235
|
+
async get() {
|
|
236
|
+
const response = await this.http.request("/context");
|
|
237
|
+
return response.context;
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
// src/resources/sessions.ts
|
|
242
|
+
var SessionsResource = class {
|
|
243
|
+
constructor(http) {
|
|
244
|
+
this.http = http;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Start a new AI development session
|
|
248
|
+
*
|
|
249
|
+
* @param params - Session parameters
|
|
250
|
+
* @returns The created session
|
|
251
|
+
*
|
|
252
|
+
* @example
|
|
253
|
+
* ```ts
|
|
254
|
+
* const session = await pp.sessions.start({ ai: 'claude' });
|
|
255
|
+
* console.log(session.id);
|
|
256
|
+
* ```
|
|
257
|
+
*/
|
|
258
|
+
async start(params) {
|
|
259
|
+
const response = await this.http.request(
|
|
260
|
+
"/sessions/start",
|
|
261
|
+
{
|
|
262
|
+
method: "POST",
|
|
263
|
+
body: params
|
|
264
|
+
}
|
|
265
|
+
);
|
|
266
|
+
return response.session;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* End the current AI development session
|
|
270
|
+
*
|
|
271
|
+
* @param params - Optional handoff note
|
|
272
|
+
* @returns The ended session
|
|
273
|
+
*
|
|
274
|
+
* @example
|
|
275
|
+
* ```ts
|
|
276
|
+
* const session = await pp.sessions.end({
|
|
277
|
+
* handoffNote: 'Completed tasks X, Y, Z. Remaining: A, B.'
|
|
278
|
+
* });
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
281
|
+
async end(params) {
|
|
282
|
+
const response = await this.http.request(
|
|
283
|
+
"/sessions/end",
|
|
284
|
+
{
|
|
285
|
+
method: "POST",
|
|
286
|
+
body: params ?? {}
|
|
287
|
+
}
|
|
288
|
+
);
|
|
289
|
+
return response.session;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Get the current active session if any
|
|
293
|
+
*
|
|
294
|
+
* @returns The current session or null
|
|
295
|
+
*/
|
|
296
|
+
async current() {
|
|
297
|
+
try {
|
|
298
|
+
const response = await this.http.request(
|
|
299
|
+
"/sessions/current"
|
|
300
|
+
);
|
|
301
|
+
return response.session;
|
|
302
|
+
} catch {
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
// src/resources/tasks.ts
|
|
309
|
+
var TasksResource = class {
|
|
310
|
+
constructor(http) {
|
|
311
|
+
this.http = http;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* List tasks with optional filters
|
|
315
|
+
*
|
|
316
|
+
* @param params - Filter parameters
|
|
317
|
+
* @returns List of tasks
|
|
318
|
+
*
|
|
319
|
+
* @example
|
|
320
|
+
* ```ts
|
|
321
|
+
* // Get all active tasks
|
|
322
|
+
* const tasks = await pp.tasks.list({ status: 'active' });
|
|
323
|
+
*
|
|
324
|
+
* // Get tasks for a specific project
|
|
325
|
+
* const projectTasks = await pp.tasks.list({
|
|
326
|
+
* projectId: 'proj-123',
|
|
327
|
+
* status: 'active'
|
|
328
|
+
* });
|
|
329
|
+
* ```
|
|
330
|
+
*/
|
|
331
|
+
async list(params) {
|
|
332
|
+
const response = await this.http.request("/tasks", {
|
|
333
|
+
params
|
|
334
|
+
});
|
|
335
|
+
return response.tasks;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Get a specific task
|
|
339
|
+
*
|
|
340
|
+
* @param taskId - Task ID
|
|
341
|
+
* @param params - Additional parameters (projectId required)
|
|
342
|
+
* @returns The task
|
|
343
|
+
*
|
|
344
|
+
* @example
|
|
345
|
+
* ```ts
|
|
346
|
+
* const task = await pp.tasks.get('task-123', {
|
|
347
|
+
* projectId: 'proj-123'
|
|
348
|
+
* });
|
|
349
|
+
* ```
|
|
350
|
+
*/
|
|
351
|
+
async get(taskId, params) {
|
|
352
|
+
const response = await this.http.request(
|
|
353
|
+
`/tasks/${taskId}`,
|
|
354
|
+
{
|
|
355
|
+
params: {
|
|
356
|
+
projectId: params.projectId
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
);
|
|
360
|
+
return response.task;
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Mark a task as completed (archived)
|
|
364
|
+
*
|
|
365
|
+
* @param taskId - Task ID
|
|
366
|
+
* @param params - Additional parameters (projectId required)
|
|
367
|
+
* @returns The updated task
|
|
368
|
+
*
|
|
369
|
+
* @example
|
|
370
|
+
* ```ts
|
|
371
|
+
* await pp.tasks.complete('task-123', {
|
|
372
|
+
* projectId: 'proj-123'
|
|
373
|
+
* });
|
|
374
|
+
* ```
|
|
375
|
+
*/
|
|
376
|
+
async complete(taskId, params) {
|
|
377
|
+
const response = await this.http.request(
|
|
378
|
+
`/tasks/${taskId}/complete`,
|
|
379
|
+
{
|
|
380
|
+
method: "POST",
|
|
381
|
+
body: params
|
|
382
|
+
}
|
|
383
|
+
);
|
|
384
|
+
return response.task;
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Update task status
|
|
388
|
+
*
|
|
389
|
+
* @param taskId - Task ID
|
|
390
|
+
* @param params - Status and projectId
|
|
391
|
+
* @returns The updated task
|
|
392
|
+
*
|
|
393
|
+
* @example
|
|
394
|
+
* ```ts
|
|
395
|
+
* await pp.tasks.updateStatus('task-123', {
|
|
396
|
+
* projectId: 'proj-123',
|
|
397
|
+
* status: 'paused'
|
|
398
|
+
* });
|
|
399
|
+
* ```
|
|
400
|
+
*/
|
|
401
|
+
async updateStatus(taskId, params) {
|
|
402
|
+
const response = await this.http.request(
|
|
403
|
+
`/tasks/${taskId}/status`,
|
|
404
|
+
{
|
|
405
|
+
method: "PATCH",
|
|
406
|
+
body: params
|
|
407
|
+
}
|
|
408
|
+
);
|
|
409
|
+
return response.task;
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
// src/resources/projects.ts
|
|
414
|
+
var ProjectsResource = class {
|
|
415
|
+
constructor(http) {
|
|
416
|
+
this.http = http;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* List all projects
|
|
420
|
+
*
|
|
421
|
+
* @param params - Filter parameters
|
|
422
|
+
* @returns List of projects
|
|
423
|
+
*
|
|
424
|
+
* @example
|
|
425
|
+
* ```ts
|
|
426
|
+
* const projects = await pp.projects.list();
|
|
427
|
+
*
|
|
428
|
+
* // Filter by status
|
|
429
|
+
* const activeProjects = await pp.projects.list({ status: 'active' });
|
|
430
|
+
* ```
|
|
431
|
+
*/
|
|
432
|
+
async list(params) {
|
|
433
|
+
const response = await this.http.request("/projects", {
|
|
434
|
+
params
|
|
435
|
+
});
|
|
436
|
+
return response.projects;
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Get a specific project
|
|
440
|
+
*
|
|
441
|
+
* @param projectId - Project ID
|
|
442
|
+
* @returns The project
|
|
443
|
+
*
|
|
444
|
+
* @example
|
|
445
|
+
* ```ts
|
|
446
|
+
* const project = await pp.projects.get('proj-123');
|
|
447
|
+
* ```
|
|
448
|
+
*/
|
|
449
|
+
async get(projectId) {
|
|
450
|
+
const response = await this.http.request(
|
|
451
|
+
`/projects/${projectId}`
|
|
452
|
+
);
|
|
453
|
+
return response.project;
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Get tasks for a specific project
|
|
457
|
+
*
|
|
458
|
+
* @param projectId - Project ID
|
|
459
|
+
* @param params - Filter parameters
|
|
460
|
+
* @returns List of tasks
|
|
461
|
+
*
|
|
462
|
+
* @example
|
|
463
|
+
* ```ts
|
|
464
|
+
* const tasks = await pp.projects.getTasks('proj-123');
|
|
465
|
+
*
|
|
466
|
+
* // Filter by status
|
|
467
|
+
* const activeTasks = await pp.projects.getTasks('proj-123', {
|
|
468
|
+
* status: 'active'
|
|
469
|
+
* });
|
|
470
|
+
* ```
|
|
471
|
+
*/
|
|
472
|
+
async getTasks(projectId, params) {
|
|
473
|
+
const response = await this.http.request(
|
|
474
|
+
`/projects/${projectId}/tasks`,
|
|
475
|
+
{
|
|
476
|
+
params
|
|
477
|
+
}
|
|
478
|
+
);
|
|
479
|
+
return response.tasks;
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
// src/resources/comments.ts
|
|
484
|
+
var CommentsResource = class {
|
|
485
|
+
constructor(http) {
|
|
486
|
+
this.http = http;
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* List comments for a task
|
|
490
|
+
*
|
|
491
|
+
* @param params - Task identifiers
|
|
492
|
+
* @returns List of comments
|
|
493
|
+
*
|
|
494
|
+
* @example
|
|
495
|
+
* ```ts
|
|
496
|
+
* const comments = await pp.comments.list({
|
|
497
|
+
* projectId: 'proj-123',
|
|
498
|
+
* taskId: 'task-123'
|
|
499
|
+
* });
|
|
500
|
+
* ```
|
|
501
|
+
*/
|
|
502
|
+
async list(params) {
|
|
503
|
+
const response = await this.http.request(
|
|
504
|
+
"/comments",
|
|
505
|
+
{
|
|
506
|
+
params: {
|
|
507
|
+
projectId: params.projectId,
|
|
508
|
+
taskId: params.taskId
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
);
|
|
512
|
+
return response.comments;
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Create a new comment on a task
|
|
516
|
+
*
|
|
517
|
+
* @param params - Comment data
|
|
518
|
+
* @returns The created comment
|
|
519
|
+
*
|
|
520
|
+
* @example
|
|
521
|
+
* ```ts
|
|
522
|
+
* await pp.comments.create({
|
|
523
|
+
* projectId: 'proj-123',
|
|
524
|
+
* taskId: 'task-123',
|
|
525
|
+
* content: '## 実装完了\n\n### 変更内容\n- file1.ts\n- file2.ts',
|
|
526
|
+
* aiName: 'Claude'
|
|
527
|
+
* });
|
|
528
|
+
* ```
|
|
529
|
+
*/
|
|
530
|
+
async create(params) {
|
|
531
|
+
const response = await this.http.request(
|
|
532
|
+
"/comments",
|
|
533
|
+
{
|
|
534
|
+
method: "POST",
|
|
535
|
+
body: params
|
|
536
|
+
}
|
|
537
|
+
);
|
|
538
|
+
return response.comment;
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Delete a comment
|
|
542
|
+
*
|
|
543
|
+
* @param commentId - Comment ID
|
|
544
|
+
* @param params - Task identifiers
|
|
545
|
+
*
|
|
546
|
+
* @example
|
|
547
|
+
* ```ts
|
|
548
|
+
* await pp.comments.delete('comment-123', {
|
|
549
|
+
* projectId: 'proj-123',
|
|
550
|
+
* taskId: 'task-123'
|
|
551
|
+
* });
|
|
552
|
+
* ```
|
|
553
|
+
*/
|
|
554
|
+
async delete(commentId, params) {
|
|
555
|
+
await this.http.request(`/comments/${commentId}`, {
|
|
556
|
+
method: "DELETE",
|
|
557
|
+
params: {
|
|
558
|
+
projectId: params.projectId,
|
|
559
|
+
taskId: params.taskId
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
};
|
|
564
|
+
|
|
565
|
+
// src/workflow.ts
|
|
566
|
+
var Workflow = class {
|
|
567
|
+
client;
|
|
568
|
+
ai;
|
|
569
|
+
currentSession = null;
|
|
570
|
+
currentContext = null;
|
|
571
|
+
constructor(client, ai) {
|
|
572
|
+
this.client = client;
|
|
573
|
+
this.ai = ai;
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* Start session and get context in one call
|
|
577
|
+
*
|
|
578
|
+
* @returns Session and context
|
|
579
|
+
*/
|
|
580
|
+
async start() {
|
|
581
|
+
const session = await this.client.sessions.start({ ai: this.ai });
|
|
582
|
+
const context = await this.client.context.get();
|
|
583
|
+
this.currentSession = session;
|
|
584
|
+
this.currentContext = context;
|
|
585
|
+
return { session, context };
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* Report progress with auto-formatted markdown comment
|
|
589
|
+
*
|
|
590
|
+
* @param taskId - Task ID
|
|
591
|
+
* @param params - Progress details
|
|
592
|
+
*/
|
|
593
|
+
async reportProgress(taskId, params) {
|
|
594
|
+
const content = this.formatProgressComment(params);
|
|
595
|
+
await this.client.comments.create({
|
|
596
|
+
projectId: params.projectId,
|
|
597
|
+
taskId,
|
|
598
|
+
content,
|
|
599
|
+
aiName: this.ai.charAt(0).toUpperCase() + this.ai.slice(1)
|
|
600
|
+
// Capitalize
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Complete a task and refresh context
|
|
605
|
+
*
|
|
606
|
+
* @param taskId - Task ID
|
|
607
|
+
* @param params - Project ID
|
|
608
|
+
* @returns Updated context
|
|
609
|
+
*/
|
|
610
|
+
async completeAndRefresh(taskId, params) {
|
|
611
|
+
await this.client.tasks.complete(taskId, params);
|
|
612
|
+
const context = await this.client.context.get();
|
|
613
|
+
this.currentContext = context;
|
|
614
|
+
return context;
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Refresh context without completing a task
|
|
618
|
+
*
|
|
619
|
+
* @returns Updated context
|
|
620
|
+
*/
|
|
621
|
+
async refresh() {
|
|
622
|
+
const context = await this.client.context.get();
|
|
623
|
+
this.currentContext = context;
|
|
624
|
+
return context;
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* End the session with optional handoff note
|
|
628
|
+
*
|
|
629
|
+
* @param handoffNote - Summary for next session
|
|
630
|
+
* @returns Ended session
|
|
631
|
+
*/
|
|
632
|
+
async end(handoffNote) {
|
|
633
|
+
const session = await this.client.sessions.end({ handoffNote });
|
|
634
|
+
this.currentSession = session;
|
|
635
|
+
return session;
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Get the current session
|
|
639
|
+
*/
|
|
640
|
+
getSession() {
|
|
641
|
+
return this.currentSession;
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Get the current context
|
|
645
|
+
*/
|
|
646
|
+
getContext() {
|
|
647
|
+
return this.currentContext;
|
|
648
|
+
}
|
|
649
|
+
/**
|
|
650
|
+
* Format a progress comment from params
|
|
651
|
+
*/
|
|
652
|
+
formatProgressComment(params) {
|
|
653
|
+
const lines = ["## \u5B9F\u88C5\u5B8C\u4E86", ""];
|
|
654
|
+
if (params.changes && params.changes.length > 0) {
|
|
655
|
+
lines.push("### \u5909\u66F4\u5185\u5BB9");
|
|
656
|
+
for (const change of params.changes) {
|
|
657
|
+
lines.push(`- \`${change}\``);
|
|
658
|
+
}
|
|
659
|
+
lines.push("");
|
|
660
|
+
}
|
|
661
|
+
if (params.testResults) {
|
|
662
|
+
lines.push("### \u30C6\u30B9\u30C8\u7D50\u679C");
|
|
663
|
+
const { passed, failed, skipped } = params.testResults;
|
|
664
|
+
if (passed !== void 0) {
|
|
665
|
+
lines.push(`- \u2705 \u6210\u529F: ${passed}`);
|
|
666
|
+
}
|
|
667
|
+
if (failed !== void 0) {
|
|
668
|
+
lines.push(`- \u274C \u5931\u6557: ${failed}`);
|
|
669
|
+
}
|
|
670
|
+
if (skipped !== void 0) {
|
|
671
|
+
lines.push(`- \u23ED\uFE0F \u30B9\u30AD\u30C3\u30D7: ${skipped}`);
|
|
672
|
+
}
|
|
673
|
+
lines.push("");
|
|
674
|
+
}
|
|
675
|
+
if (params.note) {
|
|
676
|
+
lines.push("### \u5099\u8003");
|
|
677
|
+
lines.push(params.note);
|
|
678
|
+
lines.push("");
|
|
679
|
+
}
|
|
680
|
+
lines.push("---");
|
|
681
|
+
lines.push(`*\u{1F916} Generated by ${this.ai.charAt(0).toUpperCase() + this.ai.slice(1)} via Projects Plus SDK*`);
|
|
682
|
+
return lines.join("\n");
|
|
683
|
+
}
|
|
684
|
+
};
|
|
685
|
+
|
|
686
|
+
// src/client.ts
|
|
687
|
+
var DEFAULT_BASE_URL = "https://us-central1-projects-plus-app.cloudfunctions.net/api/v1";
|
|
688
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
689
|
+
var DEFAULT_RETRIES = 3;
|
|
690
|
+
var DEFAULT_RETRY_DELAY = 1e3;
|
|
691
|
+
var ProjectsPlus = class {
|
|
692
|
+
http;
|
|
693
|
+
/** Context resource for getting theme overview */
|
|
694
|
+
context;
|
|
695
|
+
/** Sessions resource for managing AI development sessions */
|
|
696
|
+
sessions;
|
|
697
|
+
/** Tasks resource for managing tasks */
|
|
698
|
+
tasks;
|
|
699
|
+
/** Projects resource for managing projects */
|
|
700
|
+
projects;
|
|
701
|
+
/** Comments resource for managing task comments */
|
|
702
|
+
comments;
|
|
703
|
+
/**
|
|
704
|
+
* Create a new Projects Plus client
|
|
705
|
+
*
|
|
706
|
+
* @param config - Client configuration
|
|
707
|
+
*/
|
|
708
|
+
constructor(config) {
|
|
709
|
+
if (!config.apiKey) {
|
|
710
|
+
throw new Error("API key is required");
|
|
711
|
+
}
|
|
712
|
+
this.http = new HttpClient({
|
|
713
|
+
apiKey: config.apiKey,
|
|
714
|
+
baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,
|
|
715
|
+
timeout: config.timeout ?? DEFAULT_TIMEOUT,
|
|
716
|
+
retries: config.retries ?? DEFAULT_RETRIES,
|
|
717
|
+
retryDelay: config.retryDelay ?? DEFAULT_RETRY_DELAY
|
|
718
|
+
});
|
|
719
|
+
this.context = new ContextResource(this.http);
|
|
720
|
+
this.sessions = new SessionsResource(this.http);
|
|
721
|
+
this.tasks = new TasksResource(this.http);
|
|
722
|
+
this.projects = new ProjectsResource(this.http);
|
|
723
|
+
this.comments = new CommentsResource(this.http);
|
|
724
|
+
}
|
|
725
|
+
/**
|
|
726
|
+
* Create a workflow helper for common development patterns
|
|
727
|
+
*
|
|
728
|
+
* @param params - Workflow parameters
|
|
729
|
+
* @returns Workflow instance
|
|
730
|
+
*
|
|
731
|
+
* @example
|
|
732
|
+
* ```ts
|
|
733
|
+
* const workflow = pp.workflow({ ai: 'claude' });
|
|
734
|
+
*
|
|
735
|
+
* // Start session and get context in one call
|
|
736
|
+
* const { session, context } = await workflow.start();
|
|
737
|
+
*
|
|
738
|
+
* // Report progress with auto-formatted markdown
|
|
739
|
+
* await workflow.reportProgress('task-id', {
|
|
740
|
+
* projectId: 'proj-id',
|
|
741
|
+
* changes: ['file1.ts', 'file2.ts'],
|
|
742
|
+
* testResults: { passed: 10, failed: 0 },
|
|
743
|
+
* });
|
|
744
|
+
*
|
|
745
|
+
* // Complete task and refresh context
|
|
746
|
+
* const newContext = await workflow.completeAndRefresh('task-id', {
|
|
747
|
+
* projectId: 'proj-id'
|
|
748
|
+
* });
|
|
749
|
+
*
|
|
750
|
+
* // End session
|
|
751
|
+
* await workflow.end('Summary...');
|
|
752
|
+
* ```
|
|
753
|
+
*/
|
|
754
|
+
workflow(params) {
|
|
755
|
+
return new Workflow(this, params.ai);
|
|
756
|
+
}
|
|
757
|
+
};
|
|
758
|
+
|
|
759
|
+
exports.ApiError = ApiError;
|
|
760
|
+
exports.AuthenticationError = AuthenticationError;
|
|
761
|
+
exports.NetworkError = NetworkError;
|
|
762
|
+
exports.NotFoundError = NotFoundError;
|
|
763
|
+
exports.ProjectsPlus = ProjectsPlus;
|
|
764
|
+
exports.RateLimitError = RateLimitError;
|
|
765
|
+
exports.ServerError = ServerError;
|
|
766
|
+
exports.TimeoutError = TimeoutError;
|
|
767
|
+
exports.ValidationError = ValidationError;
|
|
768
|
+
exports.Workflow = Workflow;
|
|
769
|
+
exports.createApiError = createApiError;
|
|
770
|
+
//# sourceMappingURL=index.js.map
|
|
771
|
+
//# sourceMappingURL=index.js.map
|