@pstdio/sdk 0.7.0 → 0.9.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 +27 -188
- package/dist/api/extensions.d.ts +1 -1
- package/dist/api/index.d.ts +2 -2
- package/dist/api/settings.d.ts +1 -0
- package/dist/api/statuses.d.ts +1 -0
- package/dist/api/tags.d.ts +1 -0
- package/dist/api/tickets.d.ts +3 -0
- package/dist/api/workspaces.d.ts +10 -1
- package/dist/client/client.d.ts +7 -2
- package/dist/client/index.d.ts +5 -3
- package/dist/client/index.js +285 -31
- package/dist/client/projects.d.ts +0 -11
- package/dist/client/request.d.ts +9 -0
- package/dist/client/sessions.d.ts +25 -3
- package/dist/client/settings.d.ts +7 -0
- package/dist/client/sse.d.ts +15 -0
- package/dist/client/statuses.d.ts +2 -0
- package/dist/client/sync.d.ts +35 -0
- package/dist/client/tags.d.ts +2 -0
- package/dist/client/tickets.d.ts +6 -1
- package/dist/client/workspaces.d.ts +2 -0
- package/dist/extensions/define-command.d.ts +1 -1
- package/dist/extensions/define-extension.d.ts +50 -7
- package/dist/extensions/index.d.ts +3 -2
- package/dist/extensions/index.js +151 -11
- package/dist/extensions/kernel-slots.d.ts +131 -10
- package/dist/extensions/params.d.ts +19 -12
- package/dist/extensions/refs.d.ts +3 -3
- package/dist/extensions/slots.d.ts +1 -9
- package/dist/extensions/types/commands.d.ts +8 -0
- package/dist/extensions/types/context.d.ts +225 -18
- package/dist/extensions/types/contributions.d.ts +183 -10
- package/dist/extensions/types/extension.d.ts +16 -10
- package/dist/extensions/types/params.d.ts +43 -29
- package/dist/extensions/types/slots.d.ts +1 -1
- package/dist/extensions/types/webview-capabilities.d.ts +12 -2
- package/dist/extensions/workbench-targets.d.ts +134 -0
- package/dist/hooks/attempt.d.ts +2 -0
- package/dist/hooks/entities.d.ts +2 -0
- package/dist/hooks/ticket.d.ts +3 -0
- package/dist/resources/index.d.ts +3 -0
- package/dist/resources/index.js +26 -0
- package/dist/resources/known-agents.d.ts +12 -0
- package/dist/resources/settings.d.ts +1 -0
- package/dist/resources/status.d.ts +1 -0
- package/dist/resources/tag.d.ts +1 -0
- package/dist/resources/ticket.d.ts +1 -0
- package/dist/resources/workspace.d.ts +4 -1
- package/package.json +2 -6
- package/dist/api/actions.d.ts +0 -13
- package/dist/client/actions.d.ts +0 -8
- package/dist/plugins/define-plugin.d.ts +0 -2
- package/dist/plugins/helpers/context.d.ts +0 -24
- package/dist/plugins/helpers/create-attempt.d.ts +0 -5
- package/dist/plugins/helpers/create-session.d.ts +0 -21
- package/dist/plugins/helpers/create-workspace.d.ts +0 -5
- package/dist/plugins/helpers/find-ticket-by-ref.d.ts +0 -6
- package/dist/plugins/helpers/find-workspace-by-ref.d.ts +0 -5
- package/dist/plugins/helpers/followup-session.d.ts +0 -29
- package/dist/plugins/helpers/get-attempts-for-ticket.d.ts +0 -17
- package/dist/plugins/helpers/index.d.ts +0 -16
- package/dist/plugins/helpers/remove-all-worktrees-for-ticket.d.ts +0 -2
- package/dist/plugins/helpers/run-command.d.ts +0 -10
- package/dist/plugins/helpers/save-ticket.d.ts +0 -14
- package/dist/plugins/helpers/set-ticket-status.d.ts +0 -7
- package/dist/plugins/helpers/set-workspace-attempt-status.d.ts +0 -7
- package/dist/plugins/helpers/ticket-pull.d.ts +0 -18
- package/dist/plugins/helpers/update-ticket-when-all-attempts-match.d.ts +0 -7
- package/dist/plugins/helpers/workspaces-for-ticket.d.ts +0 -17
- package/dist/plugins/helpers/worktree-bootstrap.d.ts +0 -8
- package/dist/plugins/hooks.d.ts +0 -42
- package/dist/plugins/index.d.ts +0 -5
- package/dist/plugins/index.js +0 -739
- package/dist/plugins/types.d.ts +0 -112
package/dist/client/index.js
CHANGED
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
// src/client/actions.ts
|
|
2
|
-
var createActionClient = (request) => ({
|
|
3
|
-
list: (projectId, targetType) => request(targetType ? `/v1/projects/${projectId}/actions?targetType=${targetType}` : `/v1/projects/${projectId}/actions`),
|
|
4
|
-
execute: (projectId, actionKey, input) => request(`/v1/projects/${projectId}/actions/${encodeURIComponent(actionKey)}/execute`, {
|
|
5
|
-
method: "POST",
|
|
6
|
-
body: input
|
|
7
|
-
})
|
|
8
|
-
});
|
|
9
|
-
|
|
10
1
|
// src/client/agents.ts
|
|
11
2
|
var createAgentClient = (request) => ({
|
|
12
3
|
list: () => request("/v1/agents"),
|
|
@@ -62,8 +53,6 @@ var createProjectClient = (request) => ({
|
|
|
62
53
|
const query = params.toString();
|
|
63
54
|
return request(`/v1/projects/${projectId}/activity${query ? `?${query}` : ""}`);
|
|
64
55
|
},
|
|
65
|
-
listPlugins: (projectId) => request(`/v1/projects/${projectId}/plugins`),
|
|
66
|
-
registerPlugins: (projectId) => request(`/v1/projects/${projectId}/plugins/register`, { method: "POST" }),
|
|
67
56
|
listRepos: (projectId) => request(`/v1/projects/${projectId}/repos`),
|
|
68
57
|
registerRepo: (projectId, input) => request(`/v1/projects/${projectId}/repos`, { method: "POST", body: input }),
|
|
69
58
|
removeRepo: (projectId, repoId) => request(`/v1/projects/${projectId}/repos/${repoId}`, { method: "DELETE" })
|
|
@@ -107,20 +96,32 @@ ${hookOutput}` : message;
|
|
|
107
96
|
}
|
|
108
97
|
return `Request failed: ${status}`;
|
|
109
98
|
};
|
|
99
|
+
var resolveBaseUrl = (options) => options.baseUrl ?? (typeof process !== "undefined" ? process.env.PSTDIO_API_URL : undefined) ?? "http://localhost:19840";
|
|
100
|
+
var resolveClientUrl = (baseUrl, path) => path.startsWith("http://") || path.startsWith("https://") ? path : `${baseUrl}${path}`;
|
|
101
|
+
var resolveFetch = (options) => options.fetch ?? globalThis.fetch;
|
|
102
|
+
var createRequestHeaders = (options, reqOpts = {}) => {
|
|
103
|
+
const headers = new Headers(reqOpts.headers);
|
|
104
|
+
if (reqOpts.hasJsonBody && !headers.has("content-type"))
|
|
105
|
+
headers.set("content-type", "application/json");
|
|
106
|
+
if (options.token)
|
|
107
|
+
headers.set("authorization", `Bearer ${options.token}`);
|
|
108
|
+
return headers;
|
|
109
|
+
};
|
|
110
110
|
var createRequest = (options) => {
|
|
111
|
-
const baseUrl = options
|
|
112
|
-
const fetchFn = options
|
|
111
|
+
const baseUrl = resolveBaseUrl(options);
|
|
112
|
+
const fetchFn = resolveFetch(options);
|
|
113
113
|
return async (path, reqOpts = {}) => {
|
|
114
|
-
const headers = {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
const response = await fetchFn(
|
|
114
|
+
const headers = createRequestHeaders(options, {
|
|
115
|
+
headers: reqOpts.headers,
|
|
116
|
+
hasJsonBody: reqOpts.body !== undefined
|
|
117
|
+
});
|
|
118
|
+
const url = resolveClientUrl(baseUrl, path);
|
|
119
|
+
const response = await fetchFn(url, {
|
|
120
120
|
method: reqOpts.method ?? "GET",
|
|
121
|
-
headers,
|
|
121
|
+
headers: Object.fromEntries(headers.entries()),
|
|
122
122
|
body: reqOpts.body !== undefined ? JSON.stringify(reqOpts.body) : undefined,
|
|
123
|
-
signal: reqOpts.signal
|
|
123
|
+
signal: reqOpts.signal,
|
|
124
|
+
cache: reqOpts.cache
|
|
124
125
|
});
|
|
125
126
|
if (!response.ok) {
|
|
126
127
|
const errorBody = await response.json().catch(() => null);
|
|
@@ -133,8 +134,105 @@ var createRequest = (options) => {
|
|
|
133
134
|
};
|
|
134
135
|
};
|
|
135
136
|
|
|
137
|
+
// src/client/sse.ts
|
|
138
|
+
var parseSseEvent = (part) => {
|
|
139
|
+
let event = "message";
|
|
140
|
+
const data = [];
|
|
141
|
+
for (const line of part.split(`
|
|
142
|
+
`)) {
|
|
143
|
+
if (line.startsWith("event: ")) {
|
|
144
|
+
event = line.slice(7);
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
if (line.startsWith("data: ")) {
|
|
148
|
+
data.push(line.slice(6));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (!event || data.length === 0)
|
|
152
|
+
return null;
|
|
153
|
+
return { event, data: data.join(`
|
|
154
|
+
`) };
|
|
155
|
+
};
|
|
156
|
+
var consumeSseBuffer = (buffer) => {
|
|
157
|
+
const parts = buffer.split(`
|
|
158
|
+
|
|
159
|
+
`);
|
|
160
|
+
const remainder = parts.pop() ?? "";
|
|
161
|
+
const events = parts.map((part) => parseSseEvent(part)).filter((event) => event !== null);
|
|
162
|
+
return { remainder, events };
|
|
163
|
+
};
|
|
164
|
+
var readSseStream = async (body, onEvent, options = {}) => {
|
|
165
|
+
const reader = body.getReader();
|
|
166
|
+
const decoder = new TextDecoder;
|
|
167
|
+
let buffer = "";
|
|
168
|
+
const abort = () => {
|
|
169
|
+
reader.cancel();
|
|
170
|
+
};
|
|
171
|
+
options.signal?.addEventListener("abort", abort, { once: true });
|
|
172
|
+
try {
|
|
173
|
+
while (!options.signal?.aborted) {
|
|
174
|
+
const { done, value } = await reader.read();
|
|
175
|
+
if (done)
|
|
176
|
+
break;
|
|
177
|
+
buffer += decoder.decode(value, { stream: true });
|
|
178
|
+
const { remainder, events } = consumeSseBuffer(buffer);
|
|
179
|
+
buffer = remainder;
|
|
180
|
+
for (const event of events) {
|
|
181
|
+
onEvent(event);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
} finally {
|
|
185
|
+
options.signal?.removeEventListener("abort", abort);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
|
|
136
189
|
// src/client/sessions.ts
|
|
137
|
-
var
|
|
190
|
+
var buildSessionsQuery = (projectId, input = {}) => {
|
|
191
|
+
const params = new URLSearchParams({ project_id: projectId });
|
|
192
|
+
if (input.status)
|
|
193
|
+
params.append("status", input.status);
|
|
194
|
+
if (input.agent)
|
|
195
|
+
params.append("agent", input.agent);
|
|
196
|
+
if (input.archived)
|
|
197
|
+
params.append("archived", "true");
|
|
198
|
+
return params.toString();
|
|
199
|
+
};
|
|
200
|
+
var buildSessionStreamPath = (sessionId, attempt) => {
|
|
201
|
+
const path = `/v1/sessions/${sessionId}/stream`;
|
|
202
|
+
return attempt === undefined ? path : `${path}?attempt=${attempt}`;
|
|
203
|
+
};
|
|
204
|
+
var parseEventData = (data) => {
|
|
205
|
+
if (data.length === 0)
|
|
206
|
+
return null;
|
|
207
|
+
return JSON.parse(data);
|
|
208
|
+
};
|
|
209
|
+
var streamSessionEvents = async (clientOptions, path, onEvent, options = {}) => {
|
|
210
|
+
const response = await resolveFetch(clientOptions)(resolveClientUrl(resolveBaseUrl(clientOptions), path), {
|
|
211
|
+
headers: Object.fromEntries(createRequestHeaders(clientOptions).entries()),
|
|
212
|
+
signal: options.signal
|
|
213
|
+
});
|
|
214
|
+
if (!response.ok || !response.body)
|
|
215
|
+
throw new Error(`Connection failed: ${response.status}`);
|
|
216
|
+
await readSseStream(response.body, onEvent, { signal: options.signal });
|
|
217
|
+
};
|
|
218
|
+
var dispatchSessionStreamEvent = (event, handlers) => {
|
|
219
|
+
if (event.event === "ready") {
|
|
220
|
+
handlers.onReady?.(parseEventData(event.data));
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
if (event.event === "patch") {
|
|
224
|
+
handlers.onPatch?.(parseEventData(event.data));
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
if (event.event === "approval_request") {
|
|
228
|
+
handlers.onApprovalRequest?.(parseEventData(event.data));
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
if (event.event === "end") {
|
|
232
|
+
handlers.onEnd?.(parseEventData(event.data));
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
var createSessionClient = (request, clientOptions) => ({
|
|
138
236
|
listActivity: (sessionId, input = {}) => {
|
|
139
237
|
const params = new URLSearchParams;
|
|
140
238
|
if (input.event_type)
|
|
@@ -150,7 +248,7 @@ var createSessionClient = (request) => ({
|
|
|
150
248
|
const query = params.toString();
|
|
151
249
|
return request(`/v1/sessions/${sessionId}/activity${query ? `?${query}` : ""}`);
|
|
152
250
|
},
|
|
153
|
-
list: (projectId) => request(`/v1/sessions
|
|
251
|
+
list: (projectId, input) => request(`/v1/sessions?${buildSessionsQuery(projectId, input)}`),
|
|
154
252
|
get: (sessionId) => request(`/v1/sessions/${sessionId}`),
|
|
155
253
|
create: (input) => request("/v1/sessions", { method: "POST", body: input }),
|
|
156
254
|
archive: (sessionId) => request(`/v1/sessions/${sessionId}/archive`, { method: "POST" }),
|
|
@@ -158,7 +256,29 @@ var createSessionClient = (request) => ({
|
|
|
158
256
|
approve: (sessionId, input) => request(`/v1/sessions/${sessionId}/approve`, { method: "POST", body: input }),
|
|
159
257
|
getConversation: (sessionId) => request(`/v1/sessions/${sessionId}/conversation`),
|
|
160
258
|
resolveSessionId: (input) => request("/v1/sessions/resolve-session-id", { method: "POST", body: input }),
|
|
161
|
-
updateStatus: (sessionId, status) => request(`/v1/sessions/${sessionId}/status`, { method: "PATCH", body: { status } })
|
|
259
|
+
updateStatus: (sessionId, status) => request(`/v1/sessions/${sessionId}/status`, { method: "PATCH", body: { status } }),
|
|
260
|
+
stream: (sessionId, onEvent, options = {}) => streamSessionEvents(clientOptions, buildSessionStreamPath(sessionId), onEvent, options),
|
|
261
|
+
connectStream: (sessionId, handlers, options = {}) => {
|
|
262
|
+
const abortController = new AbortController;
|
|
263
|
+
let closed = false;
|
|
264
|
+
streamSessionEvents(clientOptions, buildSessionStreamPath(sessionId, options.attempt), (event) => dispatchSessionStreamEvent(event, handlers), { signal: abortController.signal }).catch((error) => {
|
|
265
|
+
if (closed || error.name === "AbortError")
|
|
266
|
+
return;
|
|
267
|
+
handlers.onError?.(error);
|
|
268
|
+
});
|
|
269
|
+
return {
|
|
270
|
+
close: () => {
|
|
271
|
+
closed = true;
|
|
272
|
+
abortController.abort();
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
// src/client/settings.ts
|
|
279
|
+
var createSettingsClient = (request) => ({
|
|
280
|
+
get: () => request("/v1/settings"),
|
|
281
|
+
update: (input) => request("/v1/settings", { method: "PATCH", body: input })
|
|
162
282
|
});
|
|
163
283
|
|
|
164
284
|
// src/client/skills.ts
|
|
@@ -181,6 +301,137 @@ var createStatusClient = (request) => ({
|
|
|
181
301
|
deleteAttemptStatus: (projectId, statusId) => request(`/v1/projects/${projectId}/attempt-statuses/${statusId}`, { method: "DELETE" })
|
|
182
302
|
});
|
|
183
303
|
|
|
304
|
+
// src/client/sync.ts
|
|
305
|
+
var DEFAULT_HEARTBEAT_INTERVAL_MS = 1e4;
|
|
306
|
+
var DEFAULT_HEARTBEAT_THRESHOLD = 3;
|
|
307
|
+
var DEFAULT_RECONNECT_DELAY_MS = 1000;
|
|
308
|
+
var parseSyncDeleteEvent = (data) => {
|
|
309
|
+
const parsed = JSON.parse(data);
|
|
310
|
+
const id = parsed.id ?? parsed.data?.id;
|
|
311
|
+
if (!id) {
|
|
312
|
+
throw new Error("Missing id in sync:delete event.");
|
|
313
|
+
}
|
|
314
|
+
return {
|
|
315
|
+
table: parsed.table,
|
|
316
|
+
id,
|
|
317
|
+
seq: parsed.seq
|
|
318
|
+
};
|
|
319
|
+
};
|
|
320
|
+
var applySyncEvent = (event, data, writers) => {
|
|
321
|
+
if (event === "init") {
|
|
322
|
+
const parsed = JSON.parse(data);
|
|
323
|
+
for (const [table, rows] of Object.entries(parsed.tables)) {
|
|
324
|
+
writers.getWriter(table)?.truncateAndWrite(rows);
|
|
325
|
+
}
|
|
326
|
+
return parsed.seq;
|
|
327
|
+
}
|
|
328
|
+
if (event === "sync:set") {
|
|
329
|
+
const parsed = JSON.parse(data);
|
|
330
|
+
writers.getWriter(parsed.table)?.upsert(parsed.data);
|
|
331
|
+
return parsed.seq;
|
|
332
|
+
}
|
|
333
|
+
if (event === "sync:delete") {
|
|
334
|
+
const parsed = parseSyncDeleteEvent(data);
|
|
335
|
+
writers.getWriter(parsed.table)?.remove(parsed.id);
|
|
336
|
+
return parsed.seq;
|
|
337
|
+
}
|
|
338
|
+
if (event === "heartbeat") {
|
|
339
|
+
return JSON.parse(data).seq;
|
|
340
|
+
}
|
|
341
|
+
return null;
|
|
342
|
+
};
|
|
343
|
+
var createHeartbeatMonitor = (input) => {
|
|
344
|
+
let missedHeartbeats = 0;
|
|
345
|
+
let timer = null;
|
|
346
|
+
return {
|
|
347
|
+
recordHeartbeat: () => {
|
|
348
|
+
missedHeartbeats = 0;
|
|
349
|
+
},
|
|
350
|
+
start: () => {
|
|
351
|
+
timer = setInterval(() => {
|
|
352
|
+
missedHeartbeats += 1;
|
|
353
|
+
if (missedHeartbeats >= input.threshold) {
|
|
354
|
+
input.onConnectionLost?.();
|
|
355
|
+
}
|
|
356
|
+
}, input.intervalMs);
|
|
357
|
+
},
|
|
358
|
+
stop: () => {
|
|
359
|
+
if (timer)
|
|
360
|
+
clearInterval(timer);
|
|
361
|
+
timer = null;
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
};
|
|
365
|
+
var buildSyncStreamPath = (lastSeq) => lastSeq > 0 ? `/v1/sync/stream?since=${lastSeq}` : "/v1/sync/stream";
|
|
366
|
+
var createSyncClient = (clientOptions) => ({
|
|
367
|
+
start: (input) => {
|
|
368
|
+
let lastSeq = 0;
|
|
369
|
+
let abortController = null;
|
|
370
|
+
let reconnectTimer = null;
|
|
371
|
+
let closed = false;
|
|
372
|
+
const state = { close: () => {}, connected: false };
|
|
373
|
+
const heartbeatMonitor = createHeartbeatMonitor({
|
|
374
|
+
intervalMs: input.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS,
|
|
375
|
+
threshold: input.heartbeatThreshold ?? DEFAULT_HEARTBEAT_THRESHOLD,
|
|
376
|
+
onConnectionLost: input.onConnectionLost
|
|
377
|
+
});
|
|
378
|
+
const setConnected = () => {
|
|
379
|
+
const wasConnected = state.connected;
|
|
380
|
+
state.connected = true;
|
|
381
|
+
if (!wasConnected)
|
|
382
|
+
input.onConnected?.();
|
|
383
|
+
};
|
|
384
|
+
const setDisconnected = () => {
|
|
385
|
+
const wasConnected = state.connected;
|
|
386
|
+
state.connected = false;
|
|
387
|
+
if (wasConnected)
|
|
388
|
+
input.onDisconnected?.();
|
|
389
|
+
};
|
|
390
|
+
const handleEvent = (event, data) => {
|
|
391
|
+
heartbeatMonitor.recordHeartbeat();
|
|
392
|
+
const nextSeq = applySyncEvent(event, data, input);
|
|
393
|
+
if (nextSeq !== null)
|
|
394
|
+
lastSeq = Math.max(lastSeq, nextSeq);
|
|
395
|
+
if (event === "init")
|
|
396
|
+
setConnected();
|
|
397
|
+
};
|
|
398
|
+
const connect = async () => {
|
|
399
|
+
if (closed)
|
|
400
|
+
return;
|
|
401
|
+
abortController = new AbortController;
|
|
402
|
+
try {
|
|
403
|
+
const response = await resolveFetch(clientOptions)(resolveClientUrl(resolveBaseUrl(clientOptions), buildSyncStreamPath(lastSeq)), {
|
|
404
|
+
headers: Object.fromEntries(createRequestHeaders(clientOptions).entries()),
|
|
405
|
+
signal: abortController.signal
|
|
406
|
+
});
|
|
407
|
+
if (!response.ok || !response.body)
|
|
408
|
+
throw new Error("SSE connection failed");
|
|
409
|
+
await readSseStream(response.body, ({ event, data }) => handleEvent(event, data), {
|
|
410
|
+
signal: abortController.signal
|
|
411
|
+
});
|
|
412
|
+
} catch (err) {
|
|
413
|
+
if (closed || err.name === "AbortError")
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
if (closed)
|
|
417
|
+
return;
|
|
418
|
+
setDisconnected();
|
|
419
|
+
reconnectTimer = setTimeout(connect, input.reconnectDelayMs ?? DEFAULT_RECONNECT_DELAY_MS);
|
|
420
|
+
};
|
|
421
|
+
heartbeatMonitor.start();
|
|
422
|
+
connect();
|
|
423
|
+
state.close = () => {
|
|
424
|
+
closed = true;
|
|
425
|
+
state.connected = false;
|
|
426
|
+
heartbeatMonitor.stop();
|
|
427
|
+
abortController?.abort();
|
|
428
|
+
if (reconnectTimer)
|
|
429
|
+
clearTimeout(reconnectTimer);
|
|
430
|
+
};
|
|
431
|
+
return state;
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
|
|
184
435
|
// src/client/tags.ts
|
|
185
436
|
var createTagClient = (request) => ({
|
|
186
437
|
list: (projectId) => request(`/v1/projects/${projectId}/ticket-tags`),
|
|
@@ -202,7 +453,7 @@ var createTemplateClient = (request) => ({
|
|
|
202
453
|
});
|
|
203
454
|
|
|
204
455
|
// src/client/tickets.ts
|
|
205
|
-
var
|
|
456
|
+
var resolveBaseUrl2 = (options) => options.baseUrl ?? (typeof process !== "undefined" ? process.env.PSTDIO_API_URL : undefined) ?? "http://localhost:19840";
|
|
206
457
|
var readErrorMessage2 = async (response) => {
|
|
207
458
|
const errorBody = await response.json().catch(() => null);
|
|
208
459
|
if (errorBody && typeof errorBody === "object" && errorBody !== null && "error" in errorBody) {
|
|
@@ -265,13 +516,13 @@ var createTicketClient = (request, options = {}) => ({
|
|
|
265
516
|
},
|
|
266
517
|
updateWhenAttemptStatus: (ticketId, input) => request(`/v1/tickets/${ticketId}/update-when-attempt-status`, { method: "POST", body: input }),
|
|
267
518
|
listFiles: (ticketId) => request(`/v1/tickets/${ticketId}/files`),
|
|
268
|
-
getFileContent: async (ticketId, fileId) => {
|
|
269
|
-
const baseUrl =
|
|
519
|
+
getFileContent: async (ticketId, fileId, requestOptions = {}) => {
|
|
520
|
+
const baseUrl = resolveBaseUrl2(options);
|
|
270
521
|
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
271
522
|
const headers = {};
|
|
272
523
|
if (options.token)
|
|
273
524
|
headers.authorization = `Bearer ${options.token}`;
|
|
274
|
-
const response = await fetchFn(`${baseUrl}/v1/tickets/${encodeURIComponent(ticketId)}/files/${encodeURIComponent(fileId)}/content`, { headers });
|
|
525
|
+
const response = await fetchFn(`${baseUrl}/v1/tickets/${encodeURIComponent(ticketId)}/files/${encodeURIComponent(fileId)}/content`, { cache: requestOptions.cache, headers, signal: requestOptions.signal });
|
|
275
526
|
if (!response.ok) {
|
|
276
527
|
throw new PstdioApiError(await readErrorMessage2(response), response.status);
|
|
277
528
|
}
|
|
@@ -313,18 +564,21 @@ var createClient = (options = {}) => {
|
|
|
313
564
|
projects: createProjectClient(request),
|
|
314
565
|
tickets: createTicketClient(request, options),
|
|
315
566
|
workspaces: createWorkspaceClient(request),
|
|
316
|
-
sessions: createSessionClient(request),
|
|
567
|
+
sessions: createSessionClient(request, options),
|
|
317
568
|
statuses: createStatusClient(request),
|
|
318
569
|
tags: createTagClient(request),
|
|
319
570
|
templates: createTemplateClient(request),
|
|
320
571
|
skills: createSkillClient(request),
|
|
321
572
|
agents: createAgentClient(request),
|
|
322
|
-
|
|
323
|
-
|
|
573
|
+
extensions: createExtensionClient(request),
|
|
574
|
+
settings: createSettingsClient(request),
|
|
575
|
+
sync: createSyncClient(options)
|
|
324
576
|
};
|
|
325
577
|
};
|
|
326
578
|
export {
|
|
579
|
+
parseSyncDeleteEvent,
|
|
327
580
|
createRequest,
|
|
328
581
|
createClient,
|
|
582
|
+
applySyncEvent,
|
|
329
583
|
PstdioApiError
|
|
330
584
|
};
|
|
@@ -1,25 +1,14 @@
|
|
|
1
1
|
import type { CreateProjectInput, ListProjectActivityForTicketsInput, ListTicketActivityResponse, RegisterRepoInput, Repo } from "pstdio-api-contracts";
|
|
2
2
|
import type { Project } from "../resources";
|
|
3
3
|
import type { RequestFn } from "./request";
|
|
4
|
-
type RegisteredPlugin = {
|
|
5
|
-
identity: string;
|
|
6
|
-
filePath: string;
|
|
7
|
-
};
|
|
8
|
-
type RegisteredPluginsResponse = {
|
|
9
|
-
plugins: RegisteredPlugin[];
|
|
10
|
-
pluginsDir: string | null;
|
|
11
|
-
};
|
|
12
4
|
export type ProjectClient = {
|
|
13
5
|
list(): Promise<Project[]>;
|
|
14
6
|
get(projectId: string): Promise<Project>;
|
|
15
7
|
create(input: CreateProjectInput): Promise<Project>;
|
|
16
8
|
delete(projectId: string): Promise<void>;
|
|
17
|
-
listPlugins(projectId: string): Promise<RegisteredPluginsResponse>;
|
|
18
|
-
registerPlugins(projectId: string): Promise<RegisteredPluginsResponse>;
|
|
19
9
|
listActivity(projectId: string, input?: ListProjectActivityForTicketsInput): Promise<ListTicketActivityResponse>;
|
|
20
10
|
listRepos(projectId: string): Promise<Repo[]>;
|
|
21
11
|
registerRepo(projectId: string, input: RegisterRepoInput): Promise<Repo>;
|
|
22
12
|
removeRepo(projectId: string, repoId: string): Promise<void>;
|
|
23
13
|
};
|
|
24
14
|
export declare const createProjectClient: (request: RequestFn) => ProjectClient;
|
|
25
|
-
export {};
|
package/dist/client/request.d.ts
CHANGED
|
@@ -11,6 +11,15 @@ export type RequestOptions = {
|
|
|
11
11
|
method?: string;
|
|
12
12
|
body?: unknown;
|
|
13
13
|
signal?: AbortSignal;
|
|
14
|
+
headers?: HeadersInit;
|
|
15
|
+
cache?: RequestCache;
|
|
14
16
|
};
|
|
15
17
|
export type RequestFn = <T>(path: string, options?: RequestOptions) => Promise<T>;
|
|
18
|
+
export declare const resolveBaseUrl: (options: ClientOptions) => string;
|
|
19
|
+
export declare const resolveClientUrl: (baseUrl: string, path: string) => string;
|
|
20
|
+
export declare const resolveFetch: (options: ClientOptions) => typeof fetch;
|
|
21
|
+
export declare const createRequestHeaders: (options: ClientOptions, reqOpts?: {
|
|
22
|
+
headers?: HeadersInit;
|
|
23
|
+
hasJsonBody?: boolean;
|
|
24
|
+
}) => Headers;
|
|
16
25
|
export declare const createRequest: (options: ClientOptions) => RequestFn;
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import type { ApprovalInput, CreateSessionInput, FollowUpInput, FollowUpResponse, ListSessionActivityInput, ListSessionActivityResponse, ResolveSessionIdInput, ResolveSessionIdResponse, SessionConversationResponse } from "pstdio-api-contracts";
|
|
2
2
|
import type { Session } from "../resources";
|
|
3
|
-
import type
|
|
3
|
+
import { type ClientOptions, type RequestFn } from "./request";
|
|
4
|
+
import { type SseEvent } from "./sse";
|
|
5
|
+
export type ListSessionsInput = {
|
|
6
|
+
status?: string;
|
|
7
|
+
agent?: string;
|
|
8
|
+
archived?: boolean;
|
|
9
|
+
};
|
|
4
10
|
export type SessionClient = {
|
|
5
|
-
list(projectId: string): Promise<Session[]>;
|
|
11
|
+
list(projectId: string, input?: ListSessionsInput): Promise<Session[]>;
|
|
6
12
|
get(sessionId: string): Promise<Session>;
|
|
7
13
|
create(input: CreateSessionInput): Promise<Session>;
|
|
8
14
|
archive(sessionId: string): Promise<void>;
|
|
@@ -12,5 +18,21 @@ export type SessionClient = {
|
|
|
12
18
|
resolveSessionId(input: ResolveSessionIdInput): Promise<ResolveSessionIdResponse>;
|
|
13
19
|
updateStatus(sessionId: string, status: string): Promise<Session>;
|
|
14
20
|
listActivity(sessionId: string, input?: ListSessionActivityInput): Promise<ListSessionActivityResponse>;
|
|
21
|
+
stream(sessionId: string, onEvent: (event: SseEvent) => void, options?: {
|
|
22
|
+
signal?: AbortSignal;
|
|
23
|
+
}): Promise<void>;
|
|
24
|
+
connectStream(sessionId: string, handlers: SessionStreamHandlers, options?: {
|
|
25
|
+
attempt?: number;
|
|
26
|
+
}): SessionStreamConnection;
|
|
27
|
+
};
|
|
28
|
+
export type SessionStreamHandlers = {
|
|
29
|
+
onReady?: (data: unknown) => void;
|
|
30
|
+
onPatch?: (data: unknown) => void;
|
|
31
|
+
onApprovalRequest?: (data: unknown) => void;
|
|
32
|
+
onEnd?: (data: unknown) => void;
|
|
33
|
+
onError?: (error: unknown) => void;
|
|
34
|
+
};
|
|
35
|
+
export type SessionStreamConnection = {
|
|
36
|
+
close: () => void;
|
|
15
37
|
};
|
|
16
|
-
export declare const createSessionClient: (request: RequestFn) => SessionClient;
|
|
38
|
+
export declare const createSessionClient: (request: RequestFn, clientOptions: ClientOptions) => SessionClient;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Settings, UpdateSettingsInput } from "../api/settings";
|
|
2
|
+
import type { RequestFn } from "./request";
|
|
3
|
+
export type SettingsClient = {
|
|
4
|
+
get(): Promise<Settings>;
|
|
5
|
+
update(input: UpdateSettingsInput): Promise<Settings>;
|
|
6
|
+
};
|
|
7
|
+
export declare const createSettingsClient: (request: RequestFn) => SettingsClient;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type SseEvent = {
|
|
2
|
+
event: string;
|
|
3
|
+
data: string;
|
|
4
|
+
};
|
|
5
|
+
export declare const parseSseEvent: (part: string) => {
|
|
6
|
+
event: string;
|
|
7
|
+
data: string;
|
|
8
|
+
} | null;
|
|
9
|
+
export declare const consumeSseBuffer: (buffer: string) => {
|
|
10
|
+
remainder: string;
|
|
11
|
+
events: SseEvent[];
|
|
12
|
+
};
|
|
13
|
+
export declare const readSseStream: (body: ReadableStream<Uint8Array>, onEvent: (event: SseEvent) => void, options?: {
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
}) => Promise<void>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { AttemptStatus, CreateAttemptStatusInput, CreateStatusInput } from "pstdio-api-contracts";
|
|
2
2
|
import type { Status } from "../resources";
|
|
3
3
|
import type { RequestFn } from "./request";
|
|
4
|
+
/** @deprecated Legacy core ticket status client. Ticket statuses are owned by the pstdio tickets extension. */
|
|
4
5
|
export type StatusClient = {
|
|
5
6
|
list(projectId: string): Promise<Status[]>;
|
|
6
7
|
create(projectId: string, input: CreateStatusInput): Promise<Status>;
|
|
@@ -19,4 +20,5 @@ export type StatusClient = {
|
|
|
19
20
|
}): Promise<AttemptStatus>;
|
|
20
21
|
deleteAttemptStatus(projectId: string, statusId: string): Promise<void>;
|
|
21
22
|
};
|
|
23
|
+
/** @deprecated Legacy core ticket status client. Ticket statuses are owned by the pstdio tickets extension. */
|
|
22
24
|
export declare const createStatusClient: (request: RequestFn) => StatusClient;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type ClientOptions } from "./request";
|
|
2
|
+
export type SyncRow = {
|
|
3
|
+
id: string;
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
};
|
|
6
|
+
export type SyncWriter = {
|
|
7
|
+
truncateAndWrite: (rows: SyncRow[]) => void;
|
|
8
|
+
upsert: (row: SyncRow) => void;
|
|
9
|
+
remove: (id: string) => void;
|
|
10
|
+
};
|
|
11
|
+
export type SyncWriterProvider = {
|
|
12
|
+
getWriter: (table: string) => SyncWriter | undefined;
|
|
13
|
+
};
|
|
14
|
+
export type SyncConnection = {
|
|
15
|
+
close: () => void;
|
|
16
|
+
connected: boolean;
|
|
17
|
+
};
|
|
18
|
+
export type StartSyncInput = SyncWriterProvider & {
|
|
19
|
+
onConnected?: () => void;
|
|
20
|
+
onDisconnected?: () => void;
|
|
21
|
+
onConnectionLost?: () => void;
|
|
22
|
+
heartbeatIntervalMs?: number;
|
|
23
|
+
heartbeatThreshold?: number;
|
|
24
|
+
reconnectDelayMs?: number;
|
|
25
|
+
};
|
|
26
|
+
export type SyncClient = {
|
|
27
|
+
start: (input: StartSyncInput) => SyncConnection;
|
|
28
|
+
};
|
|
29
|
+
export declare const parseSyncDeleteEvent: (data: string) => {
|
|
30
|
+
table: string;
|
|
31
|
+
id: string;
|
|
32
|
+
seq: number;
|
|
33
|
+
};
|
|
34
|
+
export declare const applySyncEvent: (event: string, data: string, writers: SyncWriterProvider) => number | null;
|
|
35
|
+
export declare const createSyncClient: (clientOptions: ClientOptions) => SyncClient;
|
package/dist/client/tags.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CreateTagInput, CreateTagOptionInput, UpdateTagInput, UpdateTagOptionInput } from "../api/tags";
|
|
2
2
|
import type { Tag, TagOption } from "../resources";
|
|
3
3
|
import type { RequestFn } from "./request";
|
|
4
|
+
/** @deprecated Legacy core ticket tag client. Ticket tags are owned by the pstdio tickets extension. */
|
|
4
5
|
export type TagClient = {
|
|
5
6
|
list(projectId: string): Promise<Tag[]>;
|
|
6
7
|
create(projectId: string, input: CreateTagInput): Promise<Tag>;
|
|
@@ -10,4 +11,5 @@ export type TagClient = {
|
|
|
10
11
|
updateOption(projectId: string, tagId: string, optionId: string, input: UpdateTagOptionInput): Promise<TagOption>;
|
|
11
12
|
deleteOption(projectId: string, tagId: string, optionId: string): Promise<void>;
|
|
12
13
|
};
|
|
14
|
+
/** @deprecated Legacy core ticket tag client. Ticket tags are owned by the pstdio tickets extension. */
|
|
13
15
|
export declare const createTagClient: (request: RequestFn) => TagClient;
|
package/dist/client/tickets.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CreateTicketAttemptInput, CreateTicketInput, ListProjectActivityForTicketsInput, ListTicketActivityInput, ListTicketActivityResponse, ListTicketsInput, TicketAttemptResponse, UpdateTicketInput, UpdateWhenAttemptStatusInput, UpdateWhenAttemptStatusResponse, UploadTicketFileInput } from "../api/tickets";
|
|
2
2
|
import type { Ticket, TicketDetail, TicketFile, TicketListItem } from "../resources";
|
|
3
3
|
import { type ClientOptions, type RequestFn } from "./request";
|
|
4
|
+
/** @deprecated Legacy core ticket client. Ticket data is owned by the pstdio tickets extension. */
|
|
4
5
|
export type TicketClient = {
|
|
5
6
|
list(projectId: string, input?: ListTicketsInput): Promise<TicketListItem[]>;
|
|
6
7
|
get(ticketId: string): Promise<TicketDetail>;
|
|
@@ -12,8 +13,12 @@ export type TicketClient = {
|
|
|
12
13
|
listProjectActivity(projectId: string, input?: ListProjectActivityForTicketsInput): Promise<ListTicketActivityResponse>;
|
|
13
14
|
updateWhenAttemptStatus(ticketId: string, input: UpdateWhenAttemptStatusInput): Promise<UpdateWhenAttemptStatusResponse>;
|
|
14
15
|
listFiles(ticketId: string): Promise<TicketFile[]>;
|
|
15
|
-
getFileContent(ticketId: string, fileId: string
|
|
16
|
+
getFileContent(ticketId: string, fileId: string, options?: {
|
|
17
|
+
cache?: RequestCache;
|
|
18
|
+
signal?: AbortSignal;
|
|
19
|
+
}): Promise<Uint8Array>;
|
|
16
20
|
uploadFile(ticketId: string, input: UploadTicketFileInput): Promise<TicketFile>;
|
|
17
21
|
deleteFile(ticketId: string, fileId: string): Promise<void>;
|
|
18
22
|
};
|
|
23
|
+
/** @deprecated Legacy core ticket client. Ticket data is owned by the pstdio tickets extension. */
|
|
19
24
|
export declare const createTicketClient: (request: RequestFn, options?: ClientOptions) => TicketClient;
|
|
@@ -4,7 +4,9 @@ import type { RequestFn } from "./request";
|
|
|
4
4
|
export type WorkspaceClient = {
|
|
5
5
|
list(projectId: string): Promise<WorkspaceListItem[]>;
|
|
6
6
|
getByShorthand(projectId: string, shorthand: string): Promise<Workspace>;
|
|
7
|
+
/** @deprecated Requires legacy ticket-workspace linkage. Ticket ownership is moving to the pstdio tickets extension. */
|
|
7
8
|
create(input: CreateWorkspaceInput): Promise<Workspace>;
|
|
9
|
+
/** @deprecated Legacy ticket attempt status mutation. Workspace status automation is extension-owned. */
|
|
8
10
|
updateAttemptStatus(workspaceId: string, input: UpdateAttemptStatusInput): Promise<UpdateAttemptStatusResponse>;
|
|
9
11
|
listActivity(workspaceId: string, input?: ListWorkspaceActivityInput): Promise<ListWorkspaceActivityResponse>;
|
|
10
12
|
removeWorktree(workspaceId: string): Promise<RemoveWorktreeResponse>;
|
|
@@ -9,7 +9,7 @@ import type { ParamObjectSchema } from "./types/params";
|
|
|
9
9
|
* @example
|
|
10
10
|
* export const sayHello = defineCommand({
|
|
11
11
|
* title: "Say hello",
|
|
12
|
-
* params: { name: params.text() },
|
|
12
|
+
* params: { name: params.text({ required: true }) },
|
|
13
13
|
* async run(ctx) {
|
|
14
14
|
* ctx.params.name; // string
|
|
15
15
|
* },
|