@rallycry/conveyor-mcp 5.0.16 → 5.0.18
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-P4WATE3Z.js → chunk-BOAMGYLU.js} +4 -4
- package/dist/{chunk-OPZL4NDT.js → chunk-J7LQ5DAT.js} +80 -5
- package/dist/{chunk-E43OFCNP.js → chunk-XLNIBIX4.js} +15 -1
- package/dist/cli.js +24 -17
- package/dist/{connection-aXGLRE5V.d.ts → connection-C2qTFync.d.ts} +31 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/site-assets-cli.js +2 -2
- package/dist/tunnel-cli.js +1 -1
- package/dist/tunnel.d.ts +1 -1
- package/dist/wait-cli.js +2 -2
- package/dist/wait-runner.d.ts +23 -4
- package/dist/wait-runner.js +1 -1
- package/dist/wait.d.ts +9 -5
- package/package.json +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// ../shared/dist/chunk-
|
|
1
|
+
// ../shared/dist/chunk-RSAY7FNH.js
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { z as z2 } from "zod";
|
|
4
4
|
var DEFAULT_SONNET_MODEL = "claude-sonnet-5-5";
|
|
@@ -500,9 +500,9 @@ var searchFilterFields = {
|
|
|
500
500
|
desc: "Only return cards with no assignee (mutually exclusive with assigneeId)"
|
|
501
501
|
})
|
|
502
502
|
),
|
|
503
|
-
limit: f.optional(f.number({ desc: "Max results to return (default 20)" }))
|
|
503
|
+
limit: f.optional(f.number({ desc: "Max results to return (default 20, at most 200)" }))
|
|
504
504
|
};
|
|
505
|
-
var searchResultNote = "Every result lists the tags it carries, so you can see why it matched. Results are relevance-ordered: highest priority first then newest; suggestions-only queries rank by upvote score. Returns summaries \u2014 plan omitted, description truncated; use get_task for full details.";
|
|
505
|
+
var searchResultNote = "Every result lists the tags it carries, so you can see why it matched. Searches every status, Complete and Cancelled included, unless statusFilters narrows it. Returns at most 200 results. Results are relevance-ordered: highest priority first then newest; suggestions-only queries rank by upvote score. Returns summaries \u2014 plan omitted, description truncated; use get_task for full details.";
|
|
506
506
|
var searchTasksContract = defineToolContract({
|
|
507
507
|
name: "search_tasks",
|
|
508
508
|
agent: {
|
|
@@ -1096,7 +1096,7 @@ var listTaskFilesContract = defineToolContract({
|
|
|
1096
1096
|
var getAttachmentContract = defineToolContract({
|
|
1097
1097
|
name: "get_attachment",
|
|
1098
1098
|
agent: {
|
|
1099
|
-
description: "Fetch one task file
|
|
1099
|
+
description: "Fetch one task file by ID. Text and images under the inline size caps come back inline. Any other file (PDF, Word, Excel, zip, large logs) is saved into this pod, and the result names the local path: open it with the Read tool or Bash. A document downloadUrl answers 404 without a signed-in project member's session, so do not curl or WebFetch it. Call list_task_files first to discover IDs and sizes. Pass task_id when the file is attached to another card in this project, such as the pack parent.",
|
|
1100
1100
|
fields: {
|
|
1101
1101
|
fileId: f.string({ desc: "The file ID to retrieve" }),
|
|
1102
1102
|
task_id: agentTaskIdOrSlug
|
|
@@ -4,10 +4,26 @@ import {
|
|
|
4
4
|
} from "./chunk-D3Q2QZJA.js";
|
|
5
5
|
|
|
6
6
|
// src/wait-runner.ts
|
|
7
|
+
var STATE_PAGE_LIMIT = 1e3;
|
|
8
|
+
var STATE_MAX_PAGES = 50;
|
|
7
9
|
var SNAPSHOT_PAGE_LIMIT = 500;
|
|
8
10
|
var SNAPSHOT_MAX_PAGES = 20;
|
|
9
11
|
var RESYNC_ATTEMPTS = 4;
|
|
10
12
|
var RESYNC_RETRY_DELAY_MS = 3e3;
|
|
13
|
+
function isLeanSeedUnsupported(error) {
|
|
14
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
15
|
+
return /^Request timed out: listCardStates$|^Validation error|unknown method/i.test(message);
|
|
16
|
+
}
|
|
17
|
+
function toWaitCardFromState(row) {
|
|
18
|
+
return {
|
|
19
|
+
id: row.id,
|
|
20
|
+
slug: row.slug ?? null,
|
|
21
|
+
title: row.title ?? null,
|
|
22
|
+
type: row.type ?? null,
|
|
23
|
+
status: row.status ?? null,
|
|
24
|
+
assignedUserId: row.assignedUserId ?? null
|
|
25
|
+
};
|
|
26
|
+
}
|
|
11
27
|
var WaitSession = class {
|
|
12
28
|
constructor(options) {
|
|
13
29
|
this.options = options;
|
|
@@ -23,6 +39,14 @@ var WaitSession = class {
|
|
|
23
39
|
buffered = [];
|
|
24
40
|
seeded = false;
|
|
25
41
|
done = false;
|
|
42
|
+
/** Flips off once the API shows it lacks `listCardStates`. */
|
|
43
|
+
leanSeed = true;
|
|
44
|
+
/**
|
|
45
|
+
* Set once a `listCardStates` call has answered. From then on the method
|
|
46
|
+
* exists, so a failure is transient and goes to the resync retry — it never
|
|
47
|
+
* downgrades the session to the walk.
|
|
48
|
+
*/
|
|
49
|
+
leanSeedConfirmed = false;
|
|
26
50
|
offDelta;
|
|
27
51
|
offReconnect;
|
|
28
52
|
timer;
|
|
@@ -118,8 +142,57 @@ var WaitSession = class {
|
|
|
118
142
|
break;
|
|
119
143
|
}
|
|
120
144
|
}
|
|
121
|
-
/**
|
|
145
|
+
/** The lean seed while the API has `listCardStates`, else the collection walk. */
|
|
122
146
|
async snapshotAll() {
|
|
147
|
+
if (this.leanSeed) {
|
|
148
|
+
const lean = await this.leanSnapshot();
|
|
149
|
+
if (lean) return lean;
|
|
150
|
+
}
|
|
151
|
+
if (this.done) return { cards: [], complete: false, pages: 0 };
|
|
152
|
+
return this.walkCollection();
|
|
153
|
+
}
|
|
154
|
+
fetchStates(cursor) {
|
|
155
|
+
const { source, projectId, filter, statePageLimit = STATE_PAGE_LIMIT } = this.options;
|
|
156
|
+
return source.listCardStates(projectId, {
|
|
157
|
+
statuses: filter.statuses,
|
|
158
|
+
types: filter.types,
|
|
159
|
+
cursor,
|
|
160
|
+
limit: statePageLimit
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Join the scope room, then page the cards in the watched statuses and
|
|
165
|
+
* types. Returns null when the first `listCardStates` call of the session
|
|
166
|
+
* fails the way an older API does: the session then walks the collection
|
|
167
|
+
* for the rest of its life.
|
|
168
|
+
*/
|
|
169
|
+
async leanSnapshot() {
|
|
170
|
+
const { source, projectId, stateMaxPages = STATE_MAX_PAGES, log } = this.options;
|
|
171
|
+
await source.subscribeToCardCollection(projectId, { limit: 1 });
|
|
172
|
+
let page;
|
|
173
|
+
try {
|
|
174
|
+
page = await this.fetchStates(null);
|
|
175
|
+
} catch (error) {
|
|
176
|
+
if (this.leanSeedConfirmed || !isLeanSeedUnsupported(error)) throw error;
|
|
177
|
+
this.leanSeed = false;
|
|
178
|
+
if (!this.done) {
|
|
179
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
180
|
+
log?.(`listCardStates did not answer (${message}) \u2014 walking the board instead.`);
|
|
181
|
+
}
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
this.leanSeedConfirmed = true;
|
|
185
|
+
const cards = page.items.map(toWaitCardFromState);
|
|
186
|
+
let pages = 1;
|
|
187
|
+
while (page.nextCursor !== null && pages < stateMaxPages) {
|
|
188
|
+
page = await this.fetchStates(page.nextCursor);
|
|
189
|
+
pages++;
|
|
190
|
+
cards.push(...page.items.map(toWaitCardFromState));
|
|
191
|
+
}
|
|
192
|
+
return { cards, complete: page.nextCursor === null, pages };
|
|
193
|
+
}
|
|
194
|
+
/** The fallback: walk the collection to the end, or until the page cap stops us. */
|
|
195
|
+
async walkCollection() {
|
|
123
196
|
const {
|
|
124
197
|
source,
|
|
125
198
|
projectId,
|
|
@@ -129,11 +202,13 @@ var WaitSession = class {
|
|
|
129
202
|
const cards = [];
|
|
130
203
|
let cursor = null;
|
|
131
204
|
let complete = false;
|
|
132
|
-
|
|
205
|
+
let pages = 0;
|
|
206
|
+
while (pages < maxPages) {
|
|
133
207
|
const result = await source.subscribeToCardCollection(projectId, {
|
|
134
208
|
cursor,
|
|
135
209
|
limit: pageLimit
|
|
136
210
|
});
|
|
211
|
+
pages++;
|
|
137
212
|
for (const item of result.items ?? []) cards.push(toWaitCard(item));
|
|
138
213
|
cursor = result.nextCursor ?? null;
|
|
139
214
|
if (cursor === null) {
|
|
@@ -141,16 +216,16 @@ var WaitSession = class {
|
|
|
141
216
|
break;
|
|
142
217
|
}
|
|
143
218
|
}
|
|
144
|
-
return { cards, complete };
|
|
219
|
+
return { cards, complete, pages };
|
|
145
220
|
}
|
|
146
221
|
async seedOrResync(initial) {
|
|
147
222
|
this.seeded = false;
|
|
148
|
-
const { cards, complete } = await this.snapshotAll();
|
|
223
|
+
const { cards, complete, pages } = await this.snapshotAll();
|
|
149
224
|
if (this.done) return;
|
|
150
225
|
if (initial) {
|
|
151
226
|
this.tracker.seed(cards);
|
|
152
227
|
this.options.log?.(
|
|
153
|
-
`
|
|
228
|
+
`Seeded ${cards.length} card(s) from ${pages} page(s) \u2014 ${this.tracker.size} already match; waiting for new work.`
|
|
154
229
|
);
|
|
155
230
|
} else {
|
|
156
231
|
const triggers = this.tracker.reseed(cards, complete);
|
|
@@ -394,7 +394,7 @@ var ConveyorConnection = class {
|
|
|
394
394
|
});
|
|
395
395
|
}
|
|
396
396
|
resumeTask(taskId, projectId) {
|
|
397
|
-
return this.callService("cloudBuildService", "
|
|
397
|
+
return this.callService("cloudBuildService", "wakeWorkspace", {
|
|
398
398
|
taskId,
|
|
399
399
|
projectId: this.resolveProjectId(projectId)
|
|
400
400
|
});
|
|
@@ -1104,6 +1104,20 @@ var ConveyorConnection = class {
|
|
|
1104
1104
|
limit: opts.limit
|
|
1105
1105
|
});
|
|
1106
1106
|
}
|
|
1107
|
+
/**
|
|
1108
|
+
* A lean, status-filtered page of a project's cards, ordered by id — the
|
|
1109
|
+
* conveyor-wait seed. An API from before this method never acks the call,
|
|
1110
|
+
* so callers on an older server see a timeout (see `wait-runner.ts`).
|
|
1111
|
+
*/
|
|
1112
|
+
listCardStates(projectId, opts) {
|
|
1113
|
+
return this.call("listCardStates", {
|
|
1114
|
+
projectId,
|
|
1115
|
+
statuses: opts.statuses,
|
|
1116
|
+
types: opts.types,
|
|
1117
|
+
cursor: opts.cursor ?? null,
|
|
1118
|
+
limit: opts.limit
|
|
1119
|
+
});
|
|
1120
|
+
}
|
|
1107
1121
|
/**
|
|
1108
1122
|
* Listen for card collection deltas on a project scope. The event name is
|
|
1109
1123
|
* the room name by design — no id parsing client-side. Returns an
|
package/dist/cli.js
CHANGED
|
@@ -81,13 +81,13 @@ import {
|
|
|
81
81
|
uploadAttachmentContract,
|
|
82
82
|
uploadSiteAssetsContract,
|
|
83
83
|
voteDecisionContract
|
|
84
|
-
} from "./chunk-
|
|
84
|
+
} from "./chunk-BOAMGYLU.js";
|
|
85
85
|
import {
|
|
86
86
|
installLifecycle
|
|
87
87
|
} from "./chunk-5KU3QS6A.js";
|
|
88
88
|
import {
|
|
89
89
|
ConveyorConnection
|
|
90
|
-
} from "./chunk-
|
|
90
|
+
} from "./chunk-XLNIBIX4.js";
|
|
91
91
|
|
|
92
92
|
// src/cli.ts
|
|
93
93
|
import { createRequire } from "module";
|
|
@@ -119,7 +119,7 @@ function registerProjectTools(server2, conn2) {
|
|
|
119
119
|
);
|
|
120
120
|
server2.tool(
|
|
121
121
|
"get_onboarding_status",
|
|
122
|
-
"Get the project's onboarding/setup readiness checklist so you can drive setup to green without the user opening Project Settings. Returns { ok, checks[] } where each check has a key (githubApp, githubOauthScopes,
|
|
122
|
+
"Get the project's onboarding/setup readiness checklist so you can drive setup to green without the user opening Project Settings. Returns { ok, checks[] } where each check has a key (githubApp, githubOauthScopes, codingAgentCredential, devBranch, anthropicKey, compute), a status (ok | warn | fail), a human-readable reason, and an optional fix hint. Call this first during onboarding, resolve every 'fail' (use gh/gcloud CLIs or point the user at the fix), then call again until ok is true. Pass projectId to target a specific project; otherwise the configured default project is used.",
|
|
123
123
|
{
|
|
124
124
|
projectId: z.string().optional().describe("Target Conveyor project ID")
|
|
125
125
|
},
|
|
@@ -536,7 +536,7 @@ function formatTaskSessionState(t, limit = 20) {
|
|
|
536
536
|
}
|
|
537
537
|
}
|
|
538
538
|
if (t.workspaces.length === 0) {
|
|
539
|
-
lines.push(" (no
|
|
539
|
+
lines.push(" (no workspaces)");
|
|
540
540
|
} else {
|
|
541
541
|
const { kept, omitted } = latestByCreatedAt(t.workspaces, limit);
|
|
542
542
|
lines.push(...kept.flatMap(formatWorkspace));
|
|
@@ -552,7 +552,7 @@ function summarizeTask(task) {
|
|
|
552
552
|
const { plan, description, ...rest } = task;
|
|
553
553
|
const summary = { ...rest };
|
|
554
554
|
summary.description = typeof description === "string" && description.length > DESCRIPTION_PREVIEW_CHARS ? `${description.slice(0, DESCRIPTION_PREVIEW_CHARS)}\u2026 [truncated \u2014 use get_task for the full description]` : description ?? null;
|
|
555
|
-
summary.hasPlan = typeof plan === "string"
|
|
555
|
+
summary.hasPlan = typeof plan === "string" ? plan.length > 0 : rest.hasPlan === true;
|
|
556
556
|
return summary;
|
|
557
557
|
}
|
|
558
558
|
|
|
@@ -579,10 +579,10 @@ function registerListTasks(server2, conn2) {
|
|
|
579
579
|
registerHotTool(
|
|
580
580
|
server2,
|
|
581
581
|
"list_tasks",
|
|
582
|
-
"List project cards, optionally filtered by card type, status, or assignment (a specific assignee, or unassigned tasks). Defaults to type=task \u2014 pass typeFilters to list incidents, suggestions or decisions. Results are relevance-ordered: highest priority first then newest; suggestions-only queries rank by upvote score. Pass projectId to target a specific project; otherwise the configured default project is used. Returns summaries \u2014 plan omitted, description truncated; use get_task for full details.",
|
|
582
|
+
"List project cards, optionally filtered by card type, status, or assignment (a specific assignee, or unassigned tasks). Defaults to type=task \u2014 pass typeFilters to list incidents, suggestions or decisions. Without a status, Complete and Cancelled cards are left out \u2014 pass status to list one of them, or use search_tasks, which covers every status. Returns at most 200 cards. Results are relevance-ordered: highest priority first then newest; suggestions-only queries rank by upvote score. Pass projectId to target a specific project; otherwise the configured default project is used. Returns summaries \u2014 plan omitted, description truncated; use get_task for full details.",
|
|
583
583
|
{
|
|
584
584
|
projectId: z5.string().optional().describe("Target Conveyor project ID"),
|
|
585
|
-
status: z5.enum(STATUS_ENUM).optional().describe("Filter by task status"),
|
|
585
|
+
status: z5.enum(STATUS_ENUM).optional().describe("Filter by task status. Omit for every status except Complete and Cancelled."),
|
|
586
586
|
typeFilters: z5.array(z5.enum(CARD_TYPE_ENUM)).optional().describe(
|
|
587
587
|
'Card types to include, e.g. ["incident"] or ["task", "incident"]. Omit for tasks only.'
|
|
588
588
|
),
|
|
@@ -590,7 +590,7 @@ function registerListTasks(server2, conn2) {
|
|
|
590
590
|
unassigned: z5.boolean().optional().describe("Only return tasks with no assignee (mutually exclusive with assigneeId)"),
|
|
591
591
|
subProjectId: BOARD_FILTER,
|
|
592
592
|
onHold: z5.boolean().optional().describe("true = only cards on hold, false = exclude them, omit = both"),
|
|
593
|
-
limit: z5.number().optional().describe("Max tasks to return (default 50)")
|
|
593
|
+
limit: z5.number().optional().describe("Max tasks to return (default 50, at most 200)")
|
|
594
594
|
},
|
|
595
595
|
async (params) => {
|
|
596
596
|
const tasks = await conn2.listTasks(params);
|
|
@@ -770,7 +770,7 @@ function registerGetTaskCli(server2, conn2) {
|
|
|
770
770
|
function registerGetTaskSessions(server2, conn2) {
|
|
771
771
|
server2.tool(
|
|
772
772
|
"get_task_sessions",
|
|
773
|
-
"Read compute-session state for a task:
|
|
773
|
+
"Read compute-session state for a task: workspace sessions and workspaces, including purpose=review review workspaces. Shows pod identity, liveness, lifecycle, and code-review claim state. Use to diagnose stalled/dead agents or code-review runs. Pass projectId to target a specific project; otherwise the configured default project is used.",
|
|
774
774
|
{
|
|
775
775
|
projectId: z5.string().optional().describe("Target Conveyor project ID"),
|
|
776
776
|
taskId: z5.string().describe("The task ID or slug"),
|
|
@@ -958,7 +958,7 @@ function registerTaskLifecycleTools(server2, conn2) {
|
|
|
958
958
|
function registerBuildTools(server2, conn2) {
|
|
959
959
|
server2.tool(
|
|
960
960
|
"start_task",
|
|
961
|
-
"Start a cloud build
|
|
961
|
+
"Start a cloud build for a task. Pass projectId to target a specific project; otherwise the configured default project is used.",
|
|
962
962
|
{
|
|
963
963
|
projectId: z6.string().optional().describe("Target Conveyor project ID"),
|
|
964
964
|
taskId: z6.string().describe("The task ID")
|
|
@@ -997,7 +997,7 @@ function registerBuildTools(server2, conn2) {
|
|
|
997
997
|
);
|
|
998
998
|
server2.tool(
|
|
999
999
|
"get_build_status",
|
|
1000
|
-
"Check
|
|
1000
|
+
"Check environment and agent status for a task. Pass projectId to target a specific project; otherwise the configured default project is used.",
|
|
1001
1001
|
{
|
|
1002
1002
|
projectId: z6.string().optional().describe("Target Conveyor project ID"),
|
|
1003
1003
|
taskId: z6.string().describe("The task ID")
|
|
@@ -1767,7 +1767,9 @@ var GetTaskFilesRequestSchema = z52.object({
|
|
|
1767
1767
|
var GetTaskFileRequestSchema = z52.object({
|
|
1768
1768
|
sessionId: z52.string(),
|
|
1769
1769
|
fileId: z52.string(),
|
|
1770
|
-
taskId: z52.string().optional()
|
|
1770
|
+
taskId: z52.string().optional(),
|
|
1771
|
+
/** Ask for a short-lived `agentDownloadUrl` when the bytes are not inlined. */
|
|
1772
|
+
agentDownload: z52.boolean().optional()
|
|
1771
1773
|
});
|
|
1772
1774
|
var DeleteTaskFileRequestSchema = z52.object({
|
|
1773
1775
|
sessionId: z52.string(),
|
|
@@ -1907,10 +1909,6 @@ var ReportDiscoveredPortsRequestSchema = z52.object({
|
|
|
1907
1909
|
sessionId: z52.string(),
|
|
1908
1910
|
ports: z52.array(DiscoveredPortSchema).max(64)
|
|
1909
1911
|
});
|
|
1910
|
-
var ReportBootMilestoneRequestSchema = z52.object({
|
|
1911
|
-
sessionId: z52.string(),
|
|
1912
|
-
key: z52.string().max(64)
|
|
1913
|
-
});
|
|
1914
1912
|
var CreateSubtaskRequestSchema = z52.object({
|
|
1915
1913
|
sessionId: z52.string(),
|
|
1916
1914
|
title: z52.string().min(1),
|
|
@@ -2274,6 +2272,13 @@ var ListProjectTasksRequestSchema = z72.object({
|
|
|
2274
2272
|
}).refine((p) => !(p.unassigned && p.assigneeId), {
|
|
2275
2273
|
message: "Pass either assigneeId or unassigned, not both"
|
|
2276
2274
|
});
|
|
2275
|
+
var ListCardStatesRequestSchema = z72.object({
|
|
2276
|
+
projectId: z72.string(),
|
|
2277
|
+
statuses: z72.array(z72.string()).min(1).max(32),
|
|
2278
|
+
types: z72.array(z72.string()).optional(),
|
|
2279
|
+
cursor: z72.string().nullable().optional(),
|
|
2280
|
+
limit: z72.number().int().positive().optional().default(500)
|
|
2281
|
+
});
|
|
2277
2282
|
var GetProjectTaskRequestSchema = z72.object({
|
|
2278
2283
|
projectId: z72.string(),
|
|
2279
2284
|
taskId: z72.string()
|
|
@@ -3395,6 +3400,8 @@ var ANTHROPIC_CATALOG = [
|
|
|
3395
3400
|
anthropicEntry(DEFAULT_HAIKU_MODEL, "Haiku 4.5", 1, 5, { supportsEffort: false }),
|
|
3396
3401
|
anthropicEntry(FABLE_MODEL, "Fable 5.1", 10, 50)
|
|
3397
3402
|
];
|
|
3403
|
+
var PROJECT_ARCHIVE_RETENTION_DAYS = 30;
|
|
3404
|
+
var RETENTION_MS = PROJECT_ARCHIVE_RETENTION_DAYS * 24 * 60 * 60 * 1e3;
|
|
3398
3405
|
var CLAUDESPACE_WORKLOAD_LABEL = "rc-workload";
|
|
3399
3406
|
var CLAUDESPACE_WORKLOAD_VALUE = "claudespace";
|
|
3400
3407
|
var CONVEYOR_POD_SELECTOR = `${CLAUDESPACE_WORKLOAD_LABEL}=${CLAUDESPACE_WORKLOAD_VALUE}`;
|
|
@@ -3994,7 +4001,7 @@ function registerStartTunnelTool(server2, conn2, startTunnel) {
|
|
|
3994
4001
|
const info = await conn2.getWorkspaceAttachInfo(taskId, sshPublicKey);
|
|
3995
4002
|
if (!info.tunnelUrl || !info.attachToken) {
|
|
3996
4003
|
throw new Error(
|
|
3997
|
-
"Workspace tunnels are unavailable for this task
|
|
4004
|
+
"Workspace tunnels are unavailable for this task \u2014 it has no live workspace tunnel. Use workspace_preview_urls for previews."
|
|
3998
4005
|
);
|
|
3999
4006
|
}
|
|
4000
4007
|
const remotePort = port ?? info.ssh?.remotePort ?? 2222;
|
|
@@ -130,6 +130,23 @@ interface CardCollectionPage {
|
|
|
130
130
|
nextCursor: string | null;
|
|
131
131
|
totalCount: number;
|
|
132
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* One `listCardStates` row: the six fields conveyor-wait filters on and
|
|
135
|
+
* prints, with a flat assignee id. Mirrors `CardStateDTO` in @project/shared.
|
|
136
|
+
*/
|
|
137
|
+
interface CardStateRow {
|
|
138
|
+
id: string;
|
|
139
|
+
slug: string | null;
|
|
140
|
+
title: string | null;
|
|
141
|
+
type: string | null;
|
|
142
|
+
status: string | null;
|
|
143
|
+
assignedUserId: string | null;
|
|
144
|
+
}
|
|
145
|
+
/** One page of `listCardStates`, ordered by id. */
|
|
146
|
+
interface CardStatePage {
|
|
147
|
+
items: CardStateRow[];
|
|
148
|
+
nextCursor: string | null;
|
|
149
|
+
}
|
|
133
150
|
/**
|
|
134
151
|
* A quickdraw collection change on a card scope. `added` vs `updated` is
|
|
135
152
|
* cosmetic — most card writes go through a hand-rolled upsert that always
|
|
@@ -164,9 +181,6 @@ interface WorkspaceAttachInfo {
|
|
|
164
181
|
taskId: string;
|
|
165
182
|
sessionId: string;
|
|
166
183
|
workspaceRoot: string;
|
|
167
|
-
/** "codespace" means preview-only — GitHub owns the VM's forwarded ports, so
|
|
168
|
-
* `tunnelUrl`/`attachToken`/`ssh` are null/absent. Older servers omit it. */
|
|
169
|
-
backend?: "gke" | "codespace";
|
|
170
184
|
tunnelUrl: string | null;
|
|
171
185
|
attachToken: string | null;
|
|
172
186
|
expiresAt: string;
|
|
@@ -533,7 +547,8 @@ declare class ConveyorConnection {
|
|
|
533
547
|
}>;
|
|
534
548
|
sleepTask(taskId: string, projectId?: string): Promise<{
|
|
535
549
|
taskId: string;
|
|
536
|
-
codespaceStatus
|
|
550
|
+
codespaceStatus?: string;
|
|
551
|
+
workspaceStatus?: string;
|
|
537
552
|
}>;
|
|
538
553
|
resumeTask(taskId: string, projectId?: string): Promise<{
|
|
539
554
|
status: string;
|
|
@@ -1101,6 +1116,17 @@ declare class ConveyorConnection {
|
|
|
1101
1116
|
cursor?: string | null;
|
|
1102
1117
|
limit?: number;
|
|
1103
1118
|
}): Promise<CardCollectionPage>;
|
|
1119
|
+
/**
|
|
1120
|
+
* A lean, status-filtered page of a project's cards, ordered by id — the
|
|
1121
|
+
* conveyor-wait seed. An API from before this method never acks the call,
|
|
1122
|
+
* so callers on an older server see a timeout (see `wait-runner.ts`).
|
|
1123
|
+
*/
|
|
1124
|
+
listCardStates(projectId: string, opts: {
|
|
1125
|
+
statuses: string[];
|
|
1126
|
+
types?: string[];
|
|
1127
|
+
cursor?: string | null;
|
|
1128
|
+
limit?: number;
|
|
1129
|
+
}): Promise<CardStatePage>;
|
|
1104
1130
|
/**
|
|
1105
1131
|
* Listen for card collection deltas on a project scope. The event name is
|
|
1106
1132
|
* the room name by design — no id parsing client-side. Returns an
|
|
@@ -1117,4 +1143,4 @@ declare class ConveyorConnection {
|
|
|
1117
1143
|
disconnect(): void;
|
|
1118
1144
|
}
|
|
1119
1145
|
|
|
1120
|
-
export { type ActivePtySession as A, type CardCollectionPage as C, type PtyAttachSnapshot as P, type
|
|
1146
|
+
export { type ActivePtySession as A, type CardCollectionPage as C, type PtyAttachSnapshot as P, type CardStatePage as a, type CardCollectionDelta as b, type CardCollectionItem as c, type PtyDataChunk as d, ConveyorConnection as e, type ConveyorMcpConfig as f };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { A as ActivePtySession,
|
|
1
|
+
export { A as ActivePtySession, e as ConveyorConnection, f as ConveyorMcpConfig, P as PtyAttachSnapshot, d as PtyDataChunk } from './connection-C2qTFync.js';
|
|
2
2
|
export { AttachTunnelOptions, ResolvedPtySession, RunTunnelOptions, TunnelConnection, TunnelHandle, TunnelSession, TunnelTty, WaitForPtySessionOptions, attachTunnel, runTunnel, waitForPtySession } from './tunnel.js';
|
|
3
3
|
import 'socket.io-client';
|
|
4
4
|
import '@project/shared';
|
package/dist/index.js
CHANGED
package/dist/site-assets-cli.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
transferSiteAsset
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-BOAMGYLU.js";
|
|
5
5
|
import {
|
|
6
6
|
ConveyorConnection
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-XLNIBIX4.js";
|
|
8
8
|
|
|
9
9
|
// src/site-assets-cli.ts
|
|
10
10
|
import crypto from "crypto";
|
package/dist/tunnel-cli.js
CHANGED
package/dist/tunnel.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as ActivePtySession, P as PtyAttachSnapshot,
|
|
1
|
+
import { A as ActivePtySession, P as PtyAttachSnapshot, d as PtyDataChunk } from './connection-C2qTFync.js';
|
|
2
2
|
import 'socket.io-client';
|
|
3
3
|
import '@project/shared';
|
|
4
4
|
|
package/dist/wait-cli.js
CHANGED
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
} from "./chunk-5KU3QS6A.js";
|
|
5
5
|
import {
|
|
6
6
|
ConveyorConnection
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-XLNIBIX4.js";
|
|
8
8
|
import {
|
|
9
9
|
runWait
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-J7LQ5DAT.js";
|
|
11
11
|
import {
|
|
12
12
|
DEFAULT_WAIT_SCOPES,
|
|
13
13
|
DEFAULT_WAIT_STATUSES,
|
package/dist/wait-runner.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as CardCollectionPage, a as CardCollectionDelta } from './connection-
|
|
1
|
+
import { C as CardCollectionPage, a as CardStatePage, b as CardCollectionDelta } from './connection-C2qTFync.js';
|
|
2
2
|
import { WaitFilter, WaitResult } from './wait.js';
|
|
3
3
|
import 'socket.io-client';
|
|
4
4
|
import '@project/shared';
|
|
@@ -7,9 +7,16 @@ import '@project/shared';
|
|
|
7
7
|
* `conveyor-wait` runner — the live half of the engine.
|
|
8
8
|
*
|
|
9
9
|
* `wait.ts` decides what "matching" means; this module owns the socket-shaped
|
|
10
|
-
* lifecycle around it: seed
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* lifecycle around it: seed, apply deltas, re-seed after a `reset` or a
|
|
11
|
+
* reconnect, and settle on the first card that enters the filter (or on the
|
|
12
|
+
* deadline).
|
|
13
|
+
*
|
|
14
|
+
* A seed is two calls, not a walk of the board. A cursor-less collection
|
|
15
|
+
* subscribe with `limit: 1` joins the scope room, which is what makes deltas
|
|
16
|
+
* flow; its one item is ignored. `listCardStates` then pages just the cards in
|
|
17
|
+
* the watched statuses and types — six fields each, usually one page. An API
|
|
18
|
+
* from before `listCardStates` gets today's walk of the collection instead
|
|
19
|
+
* (conveyor-mcp publishes ahead of the API release).
|
|
13
20
|
*
|
|
14
21
|
* It talks to a narrow `CardCollectionSource` rather than a socket, so the
|
|
15
22
|
* reconnect, reset, and paging paths are unit-testable without a server.
|
|
@@ -24,6 +31,12 @@ interface CardCollectionSource {
|
|
|
24
31
|
cursor?: string | null;
|
|
25
32
|
limit?: number;
|
|
26
33
|
}): Promise<CardCollectionPage>;
|
|
34
|
+
listCardStates(projectId: string, opts: {
|
|
35
|
+
statuses: string[];
|
|
36
|
+
types?: string[];
|
|
37
|
+
cursor?: string | null;
|
|
38
|
+
limit?: number;
|
|
39
|
+
}): Promise<CardStatePage>;
|
|
27
40
|
onCardDelta(projectId: string, handler: (delta: CardCollectionDelta) => void): () => void;
|
|
28
41
|
onReconnect(handler: () => void): () => void;
|
|
29
42
|
}
|
|
@@ -32,7 +45,13 @@ interface RunWaitOptions {
|
|
|
32
45
|
projectId: string;
|
|
33
46
|
filter: WaitFilter;
|
|
34
47
|
timeoutMs: number;
|
|
48
|
+
/** Rows per `listCardStates` page. */
|
|
49
|
+
statePageLimit?: number;
|
|
50
|
+
/** Page cap for one `listCardStates` seed. */
|
|
51
|
+
stateMaxPages?: number;
|
|
52
|
+
/** Items per page of the fallback collection walk. */
|
|
35
53
|
pageLimit?: number;
|
|
54
|
+
/** Page cap for the fallback collection walk. */
|
|
36
55
|
maxPages?: number;
|
|
37
56
|
/** Backoff between re-snapshot attempts. Overridable so tests stay fast. */
|
|
38
57
|
resyncRetryDelayMs?: number;
|
package/dist/wait-runner.js
CHANGED
package/dist/wait.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { c as CardCollectionItem } from './connection-C2qTFync.js';
|
|
2
2
|
import 'socket.io-client';
|
|
3
3
|
import '@project/shared';
|
|
4
4
|
|
|
@@ -14,10 +14,14 @@ import '@project/shared';
|
|
|
14
14
|
* - **Creates arrive as `updated` deltas.** Most card writes go through the
|
|
15
15
|
* service's hand-rolled upsert choke point, which always emits `updated`.
|
|
16
16
|
* "New work" is therefore a set diff, never a delta-type check.
|
|
17
|
-
* - **The
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
17
|
+
* - **The seed is not the collection snapshot.** A snapshot ack is one page
|
|
18
|
+
* of full cards, and a large project's scope runs to thousands of them. The
|
|
19
|
+
* seed instead pages `listCardStates`: only the watched statuses and types,
|
|
20
|
+
* six fields a row. The collection subscribe (with `limit: 1`) only joins
|
|
21
|
+
* the delta room. An older API without `listCardStates` falls back to
|
|
22
|
+
* walking the collection's `nextCursor` to the end. When either walk is
|
|
23
|
+
* capped we merge instead of replacing, because dropping an unseen id would
|
|
24
|
+
* make it look newly-matching on the next delta.
|
|
21
25
|
*
|
|
22
26
|
* The live half — snapshot paging, reconnect, and settling — lives in
|
|
23
27
|
* `wait-runner.ts`; this module is the pure filter and set-diff logic it uses.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rallycry/conveyor-mcp",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.18",
|
|
4
4
|
"description": "Conveyor MCP server for Claude Code PM integration",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"test:unit": "vitest run --passWithNoTests"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
39
|
+
"@modelcontextprotocol/sdk": "^1.32.1",
|
|
40
40
|
"socket.io-client": "^4.8.4",
|
|
41
41
|
"ws": "8.22.0",
|
|
42
42
|
"zod": "^4.6.5"
|