@rallycry/conveyor-agent 7.0.3 → 7.0.5
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-L7ZH423N.js → chunk-FCRGYU2M.js} +398 -143
- package/dist/chunk-FCRGYU2M.js.map +1 -0
- package/dist/cli.js +31 -2
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -28
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-L7ZH423N.js.map +0 -1
|
@@ -263,6 +263,7 @@ var AgentConnection = class {
|
|
|
263
263
|
};
|
|
264
264
|
const heartbeatStatus = statusMap[this.lastEmittedStatus ?? "idle"] ?? "active";
|
|
265
265
|
void this.call("heartbeat", {
|
|
266
|
+
sessionId: this.config.sessionId,
|
|
266
267
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
267
268
|
status: heartbeatStatus
|
|
268
269
|
}).catch(() => {
|
|
@@ -592,6 +593,34 @@ var Lifecycle = class {
|
|
|
592
593
|
|
|
593
594
|
// src/runner/git-utils.ts
|
|
594
595
|
import { execSync } from "child_process";
|
|
596
|
+
function syncWithBaseBranch(cwd, baseBranch) {
|
|
597
|
+
if (!baseBranch) return true;
|
|
598
|
+
try {
|
|
599
|
+
execSync(`git fetch origin ${baseBranch}`, { cwd, stdio: "ignore", timeout: 6e4 });
|
|
600
|
+
} catch {
|
|
601
|
+
process.stderr.write(
|
|
602
|
+
`[conveyor-agent] Warning: git fetch origin ${baseBranch} failed, continuing with current base
|
|
603
|
+
`
|
|
604
|
+
);
|
|
605
|
+
return false;
|
|
606
|
+
}
|
|
607
|
+
try {
|
|
608
|
+
execSync(`git merge origin/${baseBranch} --no-edit`, { cwd, stdio: "ignore", timeout: 3e4 });
|
|
609
|
+
} catch {
|
|
610
|
+
process.stderr.write(
|
|
611
|
+
`[conveyor-agent] Warning: merge origin/${baseBranch} failed, aborting merge and continuing
|
|
612
|
+
`
|
|
613
|
+
);
|
|
614
|
+
try {
|
|
615
|
+
execSync("git merge --abort", { cwd, stdio: "ignore" });
|
|
616
|
+
} catch {
|
|
617
|
+
}
|
|
618
|
+
return false;
|
|
619
|
+
}
|
|
620
|
+
process.stderr.write(`[conveyor-agent] Synced with latest origin/${baseBranch}
|
|
621
|
+
`);
|
|
622
|
+
return true;
|
|
623
|
+
}
|
|
595
624
|
function hasUncommittedChanges(cwd) {
|
|
596
625
|
const status = execSync("git status --porcelain", {
|
|
597
626
|
cwd,
|
|
@@ -832,7 +861,6 @@ function buildPackRunnerSystemPrompt(context, config, setupLog) {
|
|
|
832
861
|
`- "Open" \u2014 Ready to execute (if dependencies are met). Use start_child_cloud_build to fire it.`,
|
|
833
862
|
`- "InProgress" \u2014 Currently being worked on by a Task Runner. Wait \u2014 it will move to ReviewPR when done.`,
|
|
834
863
|
`- "ReviewPR" \u2014 Task Runner finished and opened a PR. Review and merge it.`,
|
|
835
|
-
`- "Hold" \u2014 PR exists but is on hold for team review. Do not merge \u2014 skip and move on.`,
|
|
836
864
|
`- "ReviewDev" \u2014 PR was merged to dev. This child is complete. Move on.`,
|
|
837
865
|
`- "Complete" \u2014 Fully done. Move on.`,
|
|
838
866
|
``,
|
|
@@ -849,7 +877,6 @@ function buildPackRunnerSystemPrompt(context, config, setupLog) {
|
|
|
849
877
|
` - "InProgress": A Task Runner is actively working. Do nothing \u2014 wait.`,
|
|
850
878
|
` - "Open" + allDependenciesMet=true: Ready to fire. Use start_child_cloud_build.`,
|
|
851
879
|
` - "Open" + allDependenciesMet=false: Blocked \u2014 skip for now. Will be unblocked when deps complete.`,
|
|
852
|
-
` - "Hold": On hold \u2014 team must review before merge. Skip.`,
|
|
853
880
|
` - "ReviewDev" / "Complete": Already done. Skip.`,
|
|
854
881
|
` - "Planning": Not ready. If blocking progress, notify team.`,
|
|
855
882
|
``,
|
|
@@ -859,7 +886,7 @@ function buildPackRunnerSystemPrompt(context, config, setupLog) {
|
|
|
859
886
|
``,
|
|
860
887
|
`5. After firing all ready tasks: report which tasks you fired to chat, then state you are going idle.`,
|
|
861
888
|
``,
|
|
862
|
-
`6. When ALL children are in "ReviewDev"
|
|
889
|
+
`6. When ALL children are in "ReviewDev" or "Complete" (no "Open", "InProgress", or "ReviewPR" remaining): do a final review, summarize results in chat, and mark this parent task complete with force_update_task_status("Complete").`,
|
|
863
890
|
``,
|
|
864
891
|
`## Important Rules`,
|
|
865
892
|
`- When dependencies are set on children, use them to determine execution order. Fire all ready tasks in parallel.`,
|
|
@@ -1157,6 +1184,15 @@ function buildDiscoveryPrompt(context) {
|
|
|
1157
1184
|
`- Goal: collaborate with the user to create a clear plan`,
|
|
1158
1185
|
`- Proactively fill task properties (SP, tags, icon) as the plan takes shape`,
|
|
1159
1186
|
``,
|
|
1187
|
+
`### Planning Checklist (complete ALL before calling ExitPlanMode)`,
|
|
1188
|
+
`Your PRIMARY goal is to create a thorough plan. Complete these steps in order:`,
|
|
1189
|
+
`1. Read the task description and chat history \u2014 respond to what's been discussed`,
|
|
1190
|
+
`2. Explore the codebase to understand relevant files and patterns`,
|
|
1191
|
+
`3. Save a detailed plan via \`update_task\``,
|
|
1192
|
+
`4. Set story points, tags, and title via \`update_task_properties\``,
|
|
1193
|
+
`5. Discuss the plan with the team if they're engaged, incorporate feedback`,
|
|
1194
|
+
`6. THEN call ExitPlanMode \u2014 it is the LAST step, not the first`,
|
|
1195
|
+
``,
|
|
1160
1196
|
`### Self-Identification Tools`,
|
|
1161
1197
|
`Use these MCP tools to set your own task properties:`,
|
|
1162
1198
|
`- \`update_task\` \u2014 save your plan and description`,
|
|
@@ -1168,15 +1204,31 @@ function buildDiscoveryPrompt(context) {
|
|
|
1168
1204
|
`- Add matching tags using \`update_task_properties\` \u2014 this links relevant documentation and rules that help you plan more effectively`,
|
|
1169
1205
|
`- Tags accelerate discovery by surfacing domain-specific context automatically`,
|
|
1170
1206
|
``,
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1207
|
+
...context?.isParentTask ? [
|
|
1208
|
+
`### Parent Task Coordination`,
|
|
1209
|
+
`You are a parent task with child tasks. Focus on breaking work into child tasks with detailed plans, not planning implementation for yourself.`,
|
|
1210
|
+
`- Use \`list_subtasks\` to review existing children. Create or update child tasks using \`create_subtask\` / \`update_subtask\`.`,
|
|
1211
|
+
`- Each child task should be a self-contained unit of work with a clear plan.`
|
|
1212
|
+
] : [
|
|
1213
|
+
`### Self-Update vs Subtasks`,
|
|
1214
|
+
`- If the work fits in a single task (1-3 SP), update YOUR OWN plan and properties \u2014 do not create subtasks`,
|
|
1215
|
+
`- Only create subtasks when the work genuinely requires multiple independent pieces (e.g., Pack-tier work, 8+ SP)`
|
|
1216
|
+
],
|
|
1217
|
+
``,
|
|
1218
|
+
`### Subtask Plan Requirements`,
|
|
1219
|
+
`When creating subtasks, each MUST include a detailed \`plan\` field:`,
|
|
1220
|
+
`- Plans should be multi-step implementation guides, not vague descriptions`,
|
|
1221
|
+
`- Include specific file paths, function names, and code patterns to modify`,
|
|
1222
|
+
`- Reference existing implementations when relevant (e.g., "follow the pattern in src/services/foo.ts")`,
|
|
1223
|
+
`- Include testing requirements and acceptance criteria`,
|
|
1224
|
+
`- Set \`storyPointValue\` based on estimated complexity`,
|
|
1174
1225
|
``,
|
|
1175
|
-
`###
|
|
1176
|
-
`Once
|
|
1226
|
+
`### Completing Planning`,
|
|
1227
|
+
`Once ALL checklist items above are done, call the **ExitPlanMode** tool.`,
|
|
1177
1228
|
`- Required before ExitPlanMode will succeed: **plan** (via update_task), **story points** (via update_task_properties), **title** (via update_task_properties)`,
|
|
1178
1229
|
`- ExitPlanMode validates these properties and marks planning as complete`,
|
|
1179
|
-
`- It does NOT start building \u2014 the team controls when to switch to Build mode
|
|
1230
|
+
`- It does NOT start building \u2014 the team controls when to switch to Build mode`,
|
|
1231
|
+
`- Do NOT call ExitPlanMode until you have thoroughly explored the codebase and saved a detailed plan`
|
|
1180
1232
|
];
|
|
1181
1233
|
if (context) parts.push(...buildPropertyInstructions(context));
|
|
1182
1234
|
return parts.join("\n");
|
|
@@ -1203,6 +1255,22 @@ function buildAutoPrompt(context) {
|
|
|
1203
1255
|
`- Once ExitPlanMode succeeds, the system will automatically restart your session in Building mode with the appropriate model`,
|
|
1204
1256
|
`- You do NOT need to do anything after calling ExitPlanMode \u2014 the transition is handled for you`,
|
|
1205
1257
|
``,
|
|
1258
|
+
`### Subtask Plan Requirements`,
|
|
1259
|
+
`When creating subtasks, each MUST include a detailed \`plan\` field:`,
|
|
1260
|
+
`- Plans should be multi-step implementation guides, not vague descriptions`,
|
|
1261
|
+
`- Include specific file paths, function names, and code patterns to modify`,
|
|
1262
|
+
`- Reference existing implementations when relevant`,
|
|
1263
|
+
`- Include testing requirements and acceptance criteria`,
|
|
1264
|
+
`- Set \`storyPointValue\` based on estimated complexity`,
|
|
1265
|
+
``,
|
|
1266
|
+
...context?.isParentTask ? [
|
|
1267
|
+
``,
|
|
1268
|
+
`### Parent Task Guidance`,
|
|
1269
|
+
`You are a parent task. Your plan should define child tasks with detailed plans, not direct implementation steps.`,
|
|
1270
|
+
`After ExitPlanMode, you'll transition to Review mode to coordinate child task execution.`,
|
|
1271
|
+
`Child task status lifecycle: Open \u2192 InProgress \u2192 ReviewPR \u2192 ReviewDev \u2192 Complete.`
|
|
1272
|
+
] : [],
|
|
1273
|
+
``,
|
|
1206
1274
|
`### Autonomous Guidelines:`,
|
|
1207
1275
|
`- Make decisions independently \u2014 do not ask the team for approval at each step`,
|
|
1208
1276
|
`- Only escalate when genuinely blocked (ambiguous requirements, missing access, conflicting instructions)`,
|
|
@@ -1222,34 +1290,31 @@ function buildModePrompt(agentMode, context) {
|
|
|
1222
1290
|
`You are in Building mode \u2014 executing the plan.`,
|
|
1223
1291
|
`- You have full coding access (read, write, edit, bash, git)`,
|
|
1224
1292
|
`- Safety rules: no destructive operations, use --force-with-lease instead of --force`,
|
|
1225
|
-
|
|
1226
|
-
|
|
1293
|
+
...context?.isParentTask ? [
|
|
1294
|
+
`- You are a parent task. Use \`list_subtasks\`, \`start_child_cloud_build\`, and subtask management tools to coordinate children.`,
|
|
1295
|
+
`- Do NOT implement code directly \u2014 fire child builds and review their work.`,
|
|
1296
|
+
`- Goal: coordinate child task execution and ensure all children complete successfully`
|
|
1297
|
+
] : [
|
|
1298
|
+
`- If this is a leaf task (no children): execute the plan directly`,
|
|
1299
|
+
`- Goal: implement the plan, run tests, open a PR when done`
|
|
1300
|
+
]
|
|
1227
1301
|
];
|
|
1228
1302
|
if (process.env.CLAUDESPACE_NAME) {
|
|
1229
1303
|
parts.push(
|
|
1230
1304
|
``,
|
|
1231
1305
|
`### Resource Management`,
|
|
1232
|
-
`Your pod starts with minimal resources
|
|
1233
|
-
`BEFORE running any
|
|
1234
|
-
`- **
|
|
1235
|
-
`- **
|
|
1236
|
-
|
|
1237
|
-
`
|
|
1238
|
-
`CRITICAL: Always scale to at least "light" before running any package install command.`
|
|
1306
|
+
`Your pod starts with minimal resources. You MUST call \`scale_up_resources\``,
|
|
1307
|
+
`BEFORE running any resource-intensive operations \u2014 they WILL fail or OOM at baseline resources:`,
|
|
1308
|
+
`- **setup** \u2014 package installs, basic dev servers, light builds`,
|
|
1309
|
+
`- **build** \u2014 full dev servers, test suites, typecheck, lint, E2E tests`,
|
|
1310
|
+
`Actual CPU/memory values are configured per-project. Scaling is one-way (up only).`,
|
|
1311
|
+
`CRITICAL: Always scale to at least "setup" before running any package install command.`
|
|
1239
1312
|
);
|
|
1240
1313
|
}
|
|
1241
1314
|
return parts.join("\n");
|
|
1242
1315
|
}
|
|
1243
1316
|
case "review":
|
|
1244
|
-
return
|
|
1245
|
-
`
|
|
1246
|
-
## Mode: Review`,
|
|
1247
|
-
`You are in Review mode \u2014 reviewing and coordinating.`,
|
|
1248
|
-
`- You have read-only access plus light edit capability (can suggest fixes, run tests, check linting)`,
|
|
1249
|
-
`- For parent tasks: you can manage children, review child PRs, fire next child builds`,
|
|
1250
|
-
`- You have Pack Runner coordination tools (list_subtasks, fire builds, approve PRs)`,
|
|
1251
|
-
`- Goal: ensure quality, provide feedback, coordinate progression`
|
|
1252
|
-
].join("\n");
|
|
1317
|
+
return buildReviewPrompt(context);
|
|
1253
1318
|
case "auto":
|
|
1254
1319
|
return buildAutoPrompt(context);
|
|
1255
1320
|
case "code-review":
|
|
@@ -1258,6 +1323,64 @@ function buildModePrompt(agentMode, context) {
|
|
|
1258
1323
|
return null;
|
|
1259
1324
|
}
|
|
1260
1325
|
}
|
|
1326
|
+
function buildReviewPrompt(context) {
|
|
1327
|
+
const parts = [
|
|
1328
|
+
`
|
|
1329
|
+
## Mode: Review`,
|
|
1330
|
+
`You are in Review mode \u2014 reviewing and coordinating.`,
|
|
1331
|
+
`- You have read-only access plus light edit capability (can suggest fixes, run tests, check linting)`,
|
|
1332
|
+
``
|
|
1333
|
+
];
|
|
1334
|
+
if (context?.isParentTask) {
|
|
1335
|
+
parts.push(
|
|
1336
|
+
`### Parent Task Review`,
|
|
1337
|
+
`You are reviewing and coordinating child tasks.`,
|
|
1338
|
+
`- Use \`list_subtasks\` to see current child task state and progress.`,
|
|
1339
|
+
`- For children in ReviewPR status: review their code quality and merge with \`approve_and_merge_pr\`.`,
|
|
1340
|
+
`- For children with failing CI: check with \`get_task_cli(childTaskId)\` and escalate if stuck.`,
|
|
1341
|
+
`- Fire next child builds with \`start_child_cloud_build\` when ready.`,
|
|
1342
|
+
`- Create follow-up tasks for issues discovered during review.`,
|
|
1343
|
+
``,
|
|
1344
|
+
`### Coordination Workflow`,
|
|
1345
|
+
`1. Check child task statuses with \`list_subtasks\``,
|
|
1346
|
+
`2. Review completed children \u2014 check PRs, run tests if needed`,
|
|
1347
|
+
`3. Approve and merge passing PRs`,
|
|
1348
|
+
`4. Fire builds for children that are ready`,
|
|
1349
|
+
`5. Create follow-up tasks for anything out of scope`
|
|
1350
|
+
);
|
|
1351
|
+
} else {
|
|
1352
|
+
parts.push(
|
|
1353
|
+
`### Leaf Task Review`,
|
|
1354
|
+
`You are reviewing your own work before completion.`,
|
|
1355
|
+
`- Run tests and check linting to verify the PR is ready.`,
|
|
1356
|
+
`- If the PR is already open, review the diff for correctness.`,
|
|
1357
|
+
`- You can get hands dirty \u2014 if a fix is small, make it directly.`,
|
|
1358
|
+
`- If follow-up work is needed, use \`create_follow_up_task\`.`
|
|
1359
|
+
);
|
|
1360
|
+
}
|
|
1361
|
+
parts.push(
|
|
1362
|
+
``,
|
|
1363
|
+
`### General Review Guidelines`,
|
|
1364
|
+
`- For larger issues, create a follow-up task rather than fixing directly.`,
|
|
1365
|
+
`- Focus on correctness, pattern consistency, and test coverage.`,
|
|
1366
|
+
`- Be concise in feedback \u2014 actionable specifics over general observations.`,
|
|
1367
|
+
`- Goal: ensure quality, provide feedback, coordinate progression.`
|
|
1368
|
+
);
|
|
1369
|
+
if (process.env.CLAUDESPACE_NAME) {
|
|
1370
|
+
parts.push(
|
|
1371
|
+
``,
|
|
1372
|
+
`### Resource Management`,
|
|
1373
|
+
`Your pod starts with minimal resources (0.25 CPU / 1 Gi). You MUST call \`scale_up_resources\``,
|
|
1374
|
+
`BEFORE running any of these operations \u2014 they WILL fail or OOM at baseline resources:`,
|
|
1375
|
+
`- **light** (1 CPU / 4 Gi) \u2014 bun/npm/yarn install, pip install, basic dev servers, light builds`,
|
|
1376
|
+
`- **standard** (2 CPU / 8 Gi) \u2014 full dev servers, test suites, typecheck, lint`,
|
|
1377
|
+
`- **heavy** (4 CPU / 16 Gi) \u2014 E2E/browser automation, large parallel builds`,
|
|
1378
|
+
`Scaling is one-way (up only) and capped by project limits.`,
|
|
1379
|
+
`CRITICAL: Always scale to at least "light" before running any package install command.`
|
|
1380
|
+
);
|
|
1381
|
+
}
|
|
1382
|
+
return parts.join("\n");
|
|
1383
|
+
}
|
|
1261
1384
|
function buildCodeReviewPrompt() {
|
|
1262
1385
|
return [
|
|
1263
1386
|
`
|
|
@@ -1488,6 +1611,7 @@ Your responses are sent directly to the task chat \u2014 the team sees everythin
|
|
|
1488
1611
|
}
|
|
1489
1612
|
|
|
1490
1613
|
// src/execution/prompt-builder.ts
|
|
1614
|
+
var CHAT_HISTORY_LIMIT = 40;
|
|
1491
1615
|
function formatFileSize(bytes) {
|
|
1492
1616
|
if (bytes === void 0) return "";
|
|
1493
1617
|
if (bytes < 1024) return `${bytes}B`;
|
|
@@ -1633,7 +1757,7 @@ function formatTaskFile(file) {
|
|
|
1633
1757
|
return [];
|
|
1634
1758
|
}
|
|
1635
1759
|
function formatChatHistory(chatHistory) {
|
|
1636
|
-
const relevant = chatHistory.slice(-
|
|
1760
|
+
const relevant = chatHistory.slice(-CHAT_HISTORY_LIMIT);
|
|
1637
1761
|
const parts = [`
|
|
1638
1762
|
## Recent Chat Context`];
|
|
1639
1763
|
for (const msg of relevant) {
|
|
@@ -1660,6 +1784,12 @@ async function resolveTaskTagContext(context) {
|
|
|
1660
1784
|
async function buildTaskBody(context) {
|
|
1661
1785
|
const parts = [];
|
|
1662
1786
|
parts.push(`# Task: ${context.title}`);
|
|
1787
|
+
if (context.projectName) {
|
|
1788
|
+
const descLine = context.projectDescription ? `
|
|
1789
|
+
${context.projectDescription}` : "";
|
|
1790
|
+
parts.push(`
|
|
1791
|
+
## Project: ${context.projectName}${descLine}`);
|
|
1792
|
+
}
|
|
1663
1793
|
if (context.description) {
|
|
1664
1794
|
parts.push(`
|
|
1665
1795
|
## Description
|
|
@@ -1739,7 +1869,8 @@ CRITICAL: You are in Auto mode. Do NOT report status, ask for confirmation, or g
|
|
|
1739
1869
|
if (isPm && context.isParentTask) {
|
|
1740
1870
|
return [
|
|
1741
1871
|
`You are the project manager for this task and its subtasks.`,
|
|
1742
|
-
`
|
|
1872
|
+
`Review existing subtasks via \`list_subtasks\` and the chat history before taking action.`,
|
|
1873
|
+
`Read the task description and chat history carefully \u2014 the team may have already provided context and requirements. Respond to what's been discussed rather than starting from scratch.`,
|
|
1743
1874
|
`The task details are provided above. Wait for the team to provide instructions before taking action.`,
|
|
1744
1875
|
`When you finish planning, save the plan with update_task and end your turn. Your reply will be visible to the team in chat.`
|
|
1745
1876
|
];
|
|
@@ -1747,6 +1878,7 @@ CRITICAL: You are in Auto mode. Do NOT report status, ask for confirmation, or g
|
|
|
1747
1878
|
if (isPm) {
|
|
1748
1879
|
return [
|
|
1749
1880
|
`You are the project manager for this task.`,
|
|
1881
|
+
`Read the task description and chat history carefully \u2014 the team may have already provided context and requirements. Respond to what's been discussed rather than starting from scratch.`,
|
|
1750
1882
|
`The task details are provided above. Wait for the team to ask questions or provide additional requirements before starting to plan.`,
|
|
1751
1883
|
`When you finish planning, save the plan with update_task and end your turn. Your reply summarizing the plan will be visible in chat. A separate task agent will execute the plan after review.`
|
|
1752
1884
|
];
|
|
@@ -2000,7 +2132,11 @@ function buildGetTaskCliTool(connection) {
|
|
|
2000
2132
|
taskId: task_id,
|
|
2001
2133
|
source
|
|
2002
2134
|
});
|
|
2003
|
-
const formatted = result.map((entry) =>
|
|
2135
|
+
const formatted = result.map((entry) => {
|
|
2136
|
+
const type = entry.type;
|
|
2137
|
+
const time = entry.timestamp;
|
|
2138
|
+
return `[${time}] [${type}] ${formatCliEvent(entry)}`;
|
|
2139
|
+
}).join("\n");
|
|
2004
2140
|
return textResult(formatted || "No CLI logs found.");
|
|
2005
2141
|
} catch (error) {
|
|
2006
2142
|
return textResult(
|
|
@@ -2248,7 +2384,7 @@ function buildForceUpdateTaskStatusTool(connection) {
|
|
|
2248
2384
|
"force_update_task_status",
|
|
2249
2385
|
"EMERGENCY ONLY: Force-override a task's Kanban status. Status transitions happen automatically (building sets InProgress, PR creation sets ReviewPR, merge sets ReviewDev). Only use this if an automatic transition failed or a task is stuck in the wrong status. Omit task_id to update the current task, or provide a child task ID.",
|
|
2250
2386
|
{
|
|
2251
|
-
status: z.enum(["InProgress", "ReviewPR", "
|
|
2387
|
+
status: z.enum(["InProgress", "ReviewPR", "ReviewDev", "Complete"]).describe("The new status for the task"),
|
|
2252
2388
|
task_id: z.string().optional().describe("Child task ID to update. Omit to update the current task.")
|
|
2253
2389
|
},
|
|
2254
2390
|
async ({ status, task_id }) => {
|
|
@@ -2348,7 +2484,15 @@ Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>`;
|
|
|
2348
2484
|
return textResult(`Pull request #${result.prNumber} created: ${result.prUrl}`);
|
|
2349
2485
|
} catch (error) {
|
|
2350
2486
|
const msg = error instanceof Error ? error.message : "Unknown error";
|
|
2351
|
-
return textResult(
|
|
2487
|
+
return textResult(
|
|
2488
|
+
`Failed to create pull request: ${msg}
|
|
2489
|
+
|
|
2490
|
+
Troubleshooting:
|
|
2491
|
+
- Ensure all changes are committed and pushed to the remote branch
|
|
2492
|
+
- Check that the branch exists on the remote (run: git push -u origin HEAD)
|
|
2493
|
+
- Verify there isn't already an open PR for this branch
|
|
2494
|
+
- If git auth fails, the token may have expired \u2014 retry the operation`
|
|
2495
|
+
);
|
|
2352
2496
|
}
|
|
2353
2497
|
}
|
|
2354
2498
|
);
|
|
@@ -2485,9 +2629,9 @@ function buildVoteSuggestionTool(connection) {
|
|
|
2485
2629
|
function buildScaleUpResourcesTool(connection) {
|
|
2486
2630
|
return defineTool(
|
|
2487
2631
|
"scale_up_resources",
|
|
2488
|
-
"Scale up the pod's CPU and memory resources. Use before running dev servers, tests, builds, or other resource-intensive operations.
|
|
2632
|
+
"Scale up the pod's CPU and memory resources. Use before running dev servers, tests, builds, or other resource-intensive operations. Phases: 'setup' (installs, basic dev servers), 'build' (full dev servers, test suites, typecheck, builds). Actual CPU/memory values are configured per-project. Scaling is one-way (up only).",
|
|
2489
2633
|
{
|
|
2490
|
-
tier: z.enum(["initial", "
|
|
2634
|
+
tier: z.enum(["initial", "setup", "build"]).describe("The resource phase to scale up to"),
|
|
2491
2635
|
reason: z.string().optional().describe("Brief reason for scaling (e.g., 'running test suite')")
|
|
2492
2636
|
},
|
|
2493
2637
|
async ({ tier, reason }) => {
|
|
@@ -2498,13 +2642,8 @@ function buildScaleUpResourcesTool(connection) {
|
|
|
2498
2642
|
reason
|
|
2499
2643
|
});
|
|
2500
2644
|
if (result.success) {
|
|
2501
|
-
if (result.currentTier === result.previousTier) {
|
|
2502
|
-
return textResult(
|
|
2503
|
-
`Already at ${result.currentTier} tier (${result.cpu} CPU / ${result.memory} Gi). No scaling needed.`
|
|
2504
|
-
);
|
|
2505
|
-
}
|
|
2506
2645
|
return textResult(
|
|
2507
|
-
`Scaled to ${result.
|
|
2646
|
+
`Scaled to ${result.currentTier} phase (${result.cpu}). Was ${result.previousTier}.`
|
|
2508
2647
|
);
|
|
2509
2648
|
}
|
|
2510
2649
|
return textResult(
|
|
@@ -2581,14 +2720,15 @@ function buildCreateSubtaskTool(connection) {
|
|
|
2581
2720
|
ordinal: z2.number().optional().describe("Step/order number (0-based)"),
|
|
2582
2721
|
storyPointValue: z2.number().optional().describe(SP_DESCRIPTION)
|
|
2583
2722
|
},
|
|
2584
|
-
async ({ title, description, plan
|
|
2723
|
+
async ({ title, description, plan, ordinal, storyPointValue }) => {
|
|
2585
2724
|
try {
|
|
2586
2725
|
const result = await connection.call("createSubtask", {
|
|
2587
2726
|
sessionId: connection.sessionId,
|
|
2588
2727
|
title,
|
|
2589
|
-
description,
|
|
2590
|
-
|
|
2591
|
-
|
|
2728
|
+
...description !== void 0 && { description },
|
|
2729
|
+
...plan !== void 0 && { plan },
|
|
2730
|
+
...storyPointValue !== void 0 && { storyPointValue },
|
|
2731
|
+
...ordinal !== void 0 && { ordinal }
|
|
2592
2732
|
});
|
|
2593
2733
|
return textResult(`Subtask created with ID: ${result.id}`);
|
|
2594
2734
|
} catch (error) {
|
|
@@ -2611,20 +2751,15 @@ function buildUpdateSubtaskTool(connection) {
|
|
|
2611
2751
|
ordinal: z2.number().optional(),
|
|
2612
2752
|
storyPointValue: z2.number().optional().describe(SP_DESCRIPTION)
|
|
2613
2753
|
},
|
|
2614
|
-
async ({
|
|
2615
|
-
subtaskId,
|
|
2616
|
-
title,
|
|
2617
|
-
description,
|
|
2618
|
-
plan: _plan,
|
|
2619
|
-
ordinal: _ordinal,
|
|
2620
|
-
storyPointValue: _sp
|
|
2621
|
-
}) => {
|
|
2754
|
+
async ({ subtaskId, title, description, plan, storyPointValue }) => {
|
|
2622
2755
|
try {
|
|
2623
2756
|
await connection.call("updateSubtask", {
|
|
2624
2757
|
sessionId: connection.sessionId,
|
|
2625
2758
|
subtaskId,
|
|
2626
|
-
title,
|
|
2627
|
-
description
|
|
2759
|
+
...title !== void 0 && { title },
|
|
2760
|
+
...description !== void 0 && { description },
|
|
2761
|
+
...plan !== void 0 && { plan },
|
|
2762
|
+
...storyPointValue !== void 0 && { storyPointValue }
|
|
2628
2763
|
});
|
|
2629
2764
|
return textResult("Subtask updated.");
|
|
2630
2765
|
} catch (error) {
|
|
@@ -4207,6 +4342,7 @@ function createConveyorMcpServer(harness, connection, config, context, agentMode
|
|
|
4207
4342
|
}
|
|
4208
4343
|
|
|
4209
4344
|
// src/execution/event-handlers.ts
|
|
4345
|
+
var logger = createServiceLogger("event-handlers");
|
|
4210
4346
|
function safeVoid(promise, context) {
|
|
4211
4347
|
if (promise && typeof promise.catch === "function") {
|
|
4212
4348
|
promise.catch((err) => {
|
|
@@ -4384,6 +4520,7 @@ async function emitResultEvent(event, host, context, startTime, lastAssistantUsa
|
|
|
4384
4520
|
}
|
|
4385
4521
|
function handleRateLimitEvent(event, host) {
|
|
4386
4522
|
const { rate_limit_info } = event;
|
|
4523
|
+
logger.info("Rate limit event received", { rate_limit_info });
|
|
4387
4524
|
const status = rate_limit_info.status;
|
|
4388
4525
|
const utilization = rate_limit_info.utilization ?? (status === "rejected" ? 1 : void 0);
|
|
4389
4526
|
if (utilization !== void 0 && rate_limit_info.rateLimitType) {
|
|
@@ -4601,6 +4738,16 @@ async function processEvents(events, context, host) {
|
|
|
4601
4738
|
};
|
|
4602
4739
|
}
|
|
4603
4740
|
|
|
4741
|
+
// src/execution/task-property-utils.ts
|
|
4742
|
+
function collectMissingProps(taskProps) {
|
|
4743
|
+
const missing = [];
|
|
4744
|
+
if (!taskProps.plan?.trim()) missing.push("plan (save via update_task)");
|
|
4745
|
+
if (!taskProps.storyPointId) missing.push("story points (use update_task_properties)");
|
|
4746
|
+
if (!taskProps.title || taskProps.title === "Untitled")
|
|
4747
|
+
missing.push("title (use update_task_properties)");
|
|
4748
|
+
return missing;
|
|
4749
|
+
}
|
|
4750
|
+
|
|
4604
4751
|
// src/execution/tool-access.ts
|
|
4605
4752
|
var PM_PLAN_FILE_TOOLS = /* @__PURE__ */ new Set(["Write", "Edit", "MultiEdit"]);
|
|
4606
4753
|
var DESTRUCTIVE_CMD_PATTERN = /git\s+push\s+--force(?!\s*-with-lease)|git\s+reset\s+--hard|rm\s+-rf\s+\//;
|
|
@@ -4690,24 +4837,43 @@ async function handleExitPlanMode(host, input) {
|
|
|
4690
4837
|
if (host.hasExitedPlanMode) {
|
|
4691
4838
|
return { behavior: "allow", updatedInput: input };
|
|
4692
4839
|
}
|
|
4840
|
+
host.exitPlanAttempts++;
|
|
4693
4841
|
try {
|
|
4694
4842
|
host.syncPlanFile();
|
|
4695
4843
|
const taskProps = await host.connection.getTaskProperties();
|
|
4696
|
-
const missingProps =
|
|
4697
|
-
if (
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4844
|
+
const missingProps = collectMissingProps(taskProps);
|
|
4845
|
+
if (host.isParentTask) {
|
|
4846
|
+
try {
|
|
4847
|
+
const subtasks = await host.connection.call("listSubtasks", {
|
|
4848
|
+
sessionId: host.connection.sessionId
|
|
4849
|
+
});
|
|
4850
|
+
const subtasksWithoutPlans = subtasks.filter(
|
|
4851
|
+
(s) => !s.plan?.trim()
|
|
4852
|
+
);
|
|
4853
|
+
if (subtasksWithoutPlans.length > 0) {
|
|
4854
|
+
const names = subtasksWithoutPlans.map((s) => s.title).join(", ");
|
|
4855
|
+
missingProps.push(
|
|
4856
|
+
`subtask plans \u2014 these subtasks are missing plans: ${names} (use update_subtask with plan field)`
|
|
4857
|
+
);
|
|
4858
|
+
}
|
|
4859
|
+
} catch {
|
|
4860
|
+
}
|
|
4861
|
+
}
|
|
4701
4862
|
if (missingProps.length > 0) {
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4863
|
+
if (host.exitPlanAttempts <= 1) {
|
|
4864
|
+
return {
|
|
4865
|
+
behavior: "deny",
|
|
4866
|
+
message: [
|
|
4867
|
+
"Cannot exit plan mode yet. Required task properties are missing:",
|
|
4868
|
+
...missingProps.map((p) => `- ${p}`),
|
|
4869
|
+
"",
|
|
4870
|
+
"Fill these in using MCP tools, then try ExitPlanMode again."
|
|
4871
|
+
].join("\n")
|
|
4872
|
+
};
|
|
4873
|
+
}
|
|
4874
|
+
host.connection.postChatMessage(
|
|
4875
|
+
`\u26A0\uFE0F ExitPlanMode allowed with missing properties: ${missingProps.join(", ")}. Consider backfilling these later.`
|
|
4876
|
+
);
|
|
4711
4877
|
}
|
|
4712
4878
|
if (host.agentMode === "discovery") {
|
|
4713
4879
|
host.hasExitedPlanMode = true;
|
|
@@ -4812,7 +4978,7 @@ function buildCanUseTool(host) {
|
|
|
4812
4978
|
}
|
|
4813
4979
|
|
|
4814
4980
|
// src/execution/query-executor.ts
|
|
4815
|
-
var
|
|
4981
|
+
var logger2 = createServiceLogger("QueryExecutor");
|
|
4816
4982
|
var API_ERROR_PATTERN3 = /API Error: [45]\d\d/;
|
|
4817
4983
|
var IMAGE_ERROR_PATTERN2 = /Could not process image/i;
|
|
4818
4984
|
var RETRY_DELAYS_MS = [6e4, 12e4, 18e4, 3e5];
|
|
@@ -4832,6 +4998,18 @@ function buildHooks(host) {
|
|
|
4832
4998
|
isError: false
|
|
4833
4999
|
});
|
|
4834
5000
|
host.pendingToolOutputs.push(output);
|
|
5001
|
+
if (input.tool_name === "mcp__conveyor__create_pull_request") {
|
|
5002
|
+
try {
|
|
5003
|
+
const props = await host.connection.getTaskProperties();
|
|
5004
|
+
const missing = collectMissingProps(props);
|
|
5005
|
+
if (missing.length > 0) {
|
|
5006
|
+
host.connection.postChatMessage(
|
|
5007
|
+
`PR created! Please backfill missing task properties: ${missing.join(", ")}`
|
|
5008
|
+
);
|
|
5009
|
+
}
|
|
5010
|
+
} catch {
|
|
5011
|
+
}
|
|
5012
|
+
}
|
|
4835
5013
|
}
|
|
4836
5014
|
return await Promise.resolve({ continue: true });
|
|
4837
5015
|
}
|
|
@@ -4893,7 +5071,7 @@ function buildQueryOptions(host, context) {
|
|
|
4893
5071
|
disallowedTools: buildDisallowedTools(settings, mode, host.hasExitedPlanMode),
|
|
4894
5072
|
enableFileCheckpointing: settings.enableFileCheckpointing,
|
|
4895
5073
|
stderr: (data) => {
|
|
4896
|
-
|
|
5074
|
+
logger2.warn("Claude Code stderr", { data: data.trimEnd() });
|
|
4897
5075
|
}
|
|
4898
5076
|
};
|
|
4899
5077
|
}
|
|
@@ -5203,7 +5381,7 @@ var CostTracker = class {
|
|
|
5203
5381
|
};
|
|
5204
5382
|
|
|
5205
5383
|
// src/runner/query-bridge.ts
|
|
5206
|
-
var
|
|
5384
|
+
var logger3 = createServiceLogger("QueryBridge");
|
|
5207
5385
|
var QueryBridge = class {
|
|
5208
5386
|
constructor(connection, mode, runnerConfig, callbacks, workspaceDir) {
|
|
5209
5387
|
this.connection = connection;
|
|
@@ -5254,8 +5432,13 @@ var QueryBridge = class {
|
|
|
5254
5432
|
await runSdkQuery(host, context, followUpContent);
|
|
5255
5433
|
} catch (err) {
|
|
5256
5434
|
const msg = err instanceof Error ? err.message : String(err);
|
|
5257
|
-
|
|
5258
|
-
|
|
5435
|
+
const isAbort = this._stopped || /abort/i.test(msg);
|
|
5436
|
+
if (isAbort) {
|
|
5437
|
+
logger3.info("Query stopped by user", { error: msg });
|
|
5438
|
+
} else {
|
|
5439
|
+
logger3.error("Query execution failed", { error: msg });
|
|
5440
|
+
this.connection.sendEvent({ type: "error", message: msg });
|
|
5441
|
+
}
|
|
5259
5442
|
} finally {
|
|
5260
5443
|
this.mode.pendingModeRestart = false;
|
|
5261
5444
|
}
|
|
@@ -5285,6 +5468,7 @@ var QueryBridge = class {
|
|
|
5285
5468
|
set hasExitedPlanMode(val) {
|
|
5286
5469
|
bridge.mode.hasExitedPlanMode = val;
|
|
5287
5470
|
},
|
|
5471
|
+
exitPlanAttempts: 0,
|
|
5288
5472
|
get pendingModeRestart() {
|
|
5289
5473
|
return bridge.mode.pendingModeRestart;
|
|
5290
5474
|
},
|
|
@@ -5345,9 +5529,11 @@ var SessionRunner = class _SessionRunner {
|
|
|
5345
5529
|
this.lifecycle = new Lifecycle(lifecycleConfig, {
|
|
5346
5530
|
onHeartbeat: () => this.connection.sendHeartbeat(),
|
|
5347
5531
|
onIdleTimeout: () => {
|
|
5532
|
+
process.stderr.write("[conveyor-agent] Idle timeout reached, entering sleep\n");
|
|
5348
5533
|
this.connection.emitStatus("sleeping");
|
|
5349
5534
|
},
|
|
5350
5535
|
onSleep: () => {
|
|
5536
|
+
process.stderr.write("[conveyor-agent] Sleep mode active\n");
|
|
5351
5537
|
this.connection.postChatMessage("Agent sleeping \u2014 send a message or click Resume to wake.");
|
|
5352
5538
|
},
|
|
5353
5539
|
onSleepGraceExpired: () => {
|
|
@@ -5359,6 +5545,7 @@ var SessionRunner = class _SessionRunner {
|
|
|
5359
5545
|
}
|
|
5360
5546
|
},
|
|
5361
5547
|
onWake: () => {
|
|
5548
|
+
process.stderr.write("[conveyor-agent] Woken from sleep\n");
|
|
5362
5549
|
this.lifecycle.cancelSleepShutdown();
|
|
5363
5550
|
}
|
|
5364
5551
|
});
|
|
@@ -5373,7 +5560,7 @@ var SessionRunner = class _SessionRunner {
|
|
|
5373
5560
|
return this.stopped;
|
|
5374
5561
|
}
|
|
5375
5562
|
// ── Main lifecycle ─────────────────────────────────────────────────
|
|
5376
|
-
// oxlint-disable-next-line max-lines-per-function -- lifecycle orchestration is inherently sequential
|
|
5563
|
+
// oxlint-disable-next-line max-lines-per-function, complexity -- lifecycle orchestration is inherently sequential
|
|
5377
5564
|
async start() {
|
|
5378
5565
|
await this.setState("connecting");
|
|
5379
5566
|
await this.connection.connect();
|
|
@@ -5411,6 +5598,9 @@ var SessionRunner = class _SessionRunner {
|
|
|
5411
5598
|
await this.shutdown("error");
|
|
5412
5599
|
return;
|
|
5413
5600
|
}
|
|
5601
|
+
if (this.fullContext?.baseBranch) {
|
|
5602
|
+
syncWithBaseBranch(this.config.workspaceDir, this.fullContext.baseBranch);
|
|
5603
|
+
}
|
|
5414
5604
|
this.mode.resolveInitialMode(this.taskContext);
|
|
5415
5605
|
this.queryBridge = this.createQueryBridge();
|
|
5416
5606
|
this.logInitialization();
|
|
@@ -5460,8 +5650,11 @@ var SessionRunner = class _SessionRunner {
|
|
|
5460
5650
|
content: msg.content,
|
|
5461
5651
|
userId: msg.userId
|
|
5462
5652
|
});
|
|
5463
|
-
|
|
5464
|
-
|
|
5653
|
+
await this.executeQuery(msg.content);
|
|
5654
|
+
if (this.stopped) break;
|
|
5655
|
+
if (this.interrupted) {
|
|
5656
|
+
this.interrupted = false;
|
|
5657
|
+
continue;
|
|
5465
5658
|
}
|
|
5466
5659
|
if (!this.stopped && this.pendingMessages.length === 0) {
|
|
5467
5660
|
await this.maybeSendPRNudge();
|
|
@@ -5482,7 +5675,7 @@ var SessionRunner = class _SessionRunner {
|
|
|
5482
5675
|
if (effectiveMode === "code-review") {
|
|
5483
5676
|
await this.setState("running");
|
|
5484
5677
|
await this.callbacks.onEvent({ type: "execute_mode", mode: effectiveMode });
|
|
5485
|
-
await this.
|
|
5678
|
+
await this.executeQuery();
|
|
5486
5679
|
this.stopped = true;
|
|
5487
5680
|
return;
|
|
5488
5681
|
}
|
|
@@ -5490,7 +5683,7 @@ var SessionRunner = class _SessionRunner {
|
|
|
5490
5683
|
if (shouldRun) {
|
|
5491
5684
|
await this.setState("running");
|
|
5492
5685
|
await this.callbacks.onEvent({ type: "execute_mode", mode: effectiveMode });
|
|
5493
|
-
await this.
|
|
5686
|
+
await this.executeQuery();
|
|
5494
5687
|
if (!this.stopped) await this.setState("idle");
|
|
5495
5688
|
} else {
|
|
5496
5689
|
await this.setState("idle");
|
|
@@ -5519,6 +5712,20 @@ var SessionRunner = class _SessionRunner {
|
|
|
5519
5712
|
}
|
|
5520
5713
|
}
|
|
5521
5714
|
}
|
|
5715
|
+
// ── Query execution with abort handling ────────────────────────────
|
|
5716
|
+
/** Run queryBridge.execute, swallowing abort errors from stop/softStop. */
|
|
5717
|
+
async executeQuery(followUpContent) {
|
|
5718
|
+
if (!this.fullContext || !this.queryBridge) return;
|
|
5719
|
+
try {
|
|
5720
|
+
await this.queryBridge.execute(this.fullContext, followUpContent);
|
|
5721
|
+
} catch (err) {
|
|
5722
|
+
if (this.interrupted || this.stopped) {
|
|
5723
|
+
process.stderr.write("[conveyor-agent] Query aborted by stop/softStop signal\n");
|
|
5724
|
+
return;
|
|
5725
|
+
}
|
|
5726
|
+
throw err;
|
|
5727
|
+
}
|
|
5728
|
+
}
|
|
5522
5729
|
// ── Stop / soft-stop ───────────────────────────────────────────────
|
|
5523
5730
|
stop() {
|
|
5524
5731
|
this.stopped = true;
|
|
@@ -5588,9 +5795,8 @@ var SessionRunner = class _SessionRunner {
|
|
|
5588
5795
|
this.connection.postChatMessage(chatMsg);
|
|
5589
5796
|
await this.setState("running");
|
|
5590
5797
|
await this.callbacks.onEvent({ type: "pr_nudge", prompt });
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
}
|
|
5798
|
+
await this.executeQuery(prompt);
|
|
5799
|
+
if (this.interrupted || this.stopped) return;
|
|
5594
5800
|
await this.refreshTaskContext();
|
|
5595
5801
|
}
|
|
5596
5802
|
}
|
|
@@ -5627,6 +5833,8 @@ var SessionRunner = class _SessionRunner {
|
|
|
5627
5833
|
model: ctx.model,
|
|
5628
5834
|
githubBranch: ctx.githubBranch ?? "",
|
|
5629
5835
|
baseBranch: ctx.baseBranch ?? "",
|
|
5836
|
+
projectName: ctx.projectName ?? null,
|
|
5837
|
+
projectDescription: ctx.projectDescription ?? null,
|
|
5630
5838
|
githubPRUrl: ctx.githubPRUrl,
|
|
5631
5839
|
claudeSessionId: ctx.claudeSessionId ?? null,
|
|
5632
5840
|
isParentTask: !!ctx.parentTaskId,
|
|
@@ -5660,6 +5868,10 @@ var SessionRunner = class _SessionRunner {
|
|
|
5660
5868
|
);
|
|
5661
5869
|
bridge.isParentTask = this.fullContext?.isParentTask ?? false;
|
|
5662
5870
|
bridge.onModeTransition = (newMode) => {
|
|
5871
|
+
const oldMode = this.mode.effectiveMode;
|
|
5872
|
+
process.stderr.write(`[conveyor-agent] Mode transition: ${oldMode} \u2192 ${newMode}
|
|
5873
|
+
`);
|
|
5874
|
+
this.connection.sendEvent({ type: "mode_transition", from: oldMode, to: newMode });
|
|
5663
5875
|
this.mode.pendingModeRestart = true;
|
|
5664
5876
|
this.connection.emitModeChanged(newMode);
|
|
5665
5877
|
this.softStop();
|
|
@@ -5695,6 +5907,9 @@ var SessionRunner = class _SessionRunner {
|
|
|
5695
5907
|
await this.callbacks.onStatusChange(status);
|
|
5696
5908
|
}
|
|
5697
5909
|
async shutdown(finalState) {
|
|
5910
|
+
process.stderr.write(`[conveyor-agent] Shutdown: reason=${finalState}
|
|
5911
|
+
`);
|
|
5912
|
+
this.connection.sendEvent({ type: "shutdown", reason: finalState });
|
|
5698
5913
|
this.lifecycle.destroy();
|
|
5699
5914
|
await this.setState(finalState);
|
|
5700
5915
|
this.connection.disconnect();
|
|
@@ -5702,21 +5917,29 @@ var SessionRunner = class _SessionRunner {
|
|
|
5702
5917
|
logInitialization() {
|
|
5703
5918
|
const context = {
|
|
5704
5919
|
mode: this.mode.effectiveMode,
|
|
5705
|
-
model: this.taskContext?.model,
|
|
5706
5920
|
runnerMode: this.config.runnerMode ?? "task",
|
|
5707
5921
|
sessionId: this.sessionId,
|
|
5922
|
+
// Task context
|
|
5708
5923
|
isParentTask: this.fullContext?.isParentTask ?? false,
|
|
5709
|
-
status: this.taskContext?.status
|
|
5924
|
+
status: this.taskContext?.status,
|
|
5925
|
+
taskTitle: this.fullContext?.title,
|
|
5926
|
+
hasExistingPR: !!this.fullContext?.githubPRUrl,
|
|
5927
|
+
hasExistingSession: !!this.fullContext?.claudeSessionId,
|
|
5928
|
+
chatHistoryLength: this.fullContext?.chatHistory?.length ?? 0,
|
|
5929
|
+
tagIds: this.fullContext?.taskTagIds ?? [],
|
|
5930
|
+
// Agent config
|
|
5931
|
+
model: this.taskContext?.model,
|
|
5932
|
+
isAuto: this.config.isAuto ?? false
|
|
5710
5933
|
};
|
|
5711
5934
|
process.stderr.write(`[conveyor-agent] Initialized: ${JSON.stringify(context)}
|
|
5712
5935
|
`);
|
|
5713
|
-
this.connection.sendEvent({ type: "
|
|
5936
|
+
this.connection.sendEvent({ type: "session_manifest", ...context });
|
|
5714
5937
|
}
|
|
5715
5938
|
};
|
|
5716
5939
|
|
|
5717
5940
|
// src/connection/project-connection.ts
|
|
5718
5941
|
import { io as io2 } from "socket.io-client";
|
|
5719
|
-
var
|
|
5942
|
+
var logger4 = createServiceLogger("ProjectConnection");
|
|
5720
5943
|
var EVENT_BATCH_MS2 = 500;
|
|
5721
5944
|
var ProjectConnection = class {
|
|
5722
5945
|
socket = null;
|
|
@@ -5759,7 +5982,7 @@ var ProjectConnection = class {
|
|
|
5759
5982
|
let settled = false;
|
|
5760
5983
|
let attempts = 0;
|
|
5761
5984
|
const maxInitialAttempts = 30;
|
|
5762
|
-
|
|
5985
|
+
logger4.info("Connecting", { apiUrl: this.config.apiUrl, projectId: this.config.projectId });
|
|
5763
5986
|
this.socket = io2(this.config.apiUrl, {
|
|
5764
5987
|
auth: {
|
|
5765
5988
|
projectToken: this.config.projectToken,
|
|
@@ -5779,7 +6002,7 @@ var ProjectConnection = class {
|
|
|
5779
6002
|
settled = true;
|
|
5780
6003
|
resolve2();
|
|
5781
6004
|
}
|
|
5782
|
-
|
|
6005
|
+
logger4.info("Connected to API");
|
|
5783
6006
|
});
|
|
5784
6007
|
this.socket.on("connect_error", (error) => {
|
|
5785
6008
|
attempts++;
|
|
@@ -5791,10 +6014,10 @@ var ProjectConnection = class {
|
|
|
5791
6014
|
}
|
|
5792
6015
|
});
|
|
5793
6016
|
this.socket.on("disconnect", (reason) => {
|
|
5794
|
-
|
|
6017
|
+
logger4.warn("Disconnected from API", { reason });
|
|
5795
6018
|
});
|
|
5796
6019
|
this.socket.io.on("reconnect", () => {
|
|
5797
|
-
|
|
6020
|
+
logger4.info("Reconnected to API");
|
|
5798
6021
|
for (const cb of this.reconnectCallbacks) cb();
|
|
5799
6022
|
});
|
|
5800
6023
|
});
|
|
@@ -5941,7 +6164,7 @@ function runStartCommand(cmd, cwd, onOutput) {
|
|
|
5941
6164
|
|
|
5942
6165
|
// src/runner/commit-watcher.ts
|
|
5943
6166
|
import { execSync as execSync3 } from "child_process";
|
|
5944
|
-
var
|
|
6167
|
+
var logger5 = createServiceLogger("CommitWatcher");
|
|
5945
6168
|
var CommitWatcher = class {
|
|
5946
6169
|
constructor(config, callbacks) {
|
|
5947
6170
|
this.config = config;
|
|
@@ -5957,7 +6180,7 @@ var CommitWatcher = class {
|
|
|
5957
6180
|
this.branch = branch;
|
|
5958
6181
|
this.lastKnownRemoteSha = this.getLocalHeadSha();
|
|
5959
6182
|
this.interval = setInterval(() => void this.poll(), this.config.pollIntervalMs);
|
|
5960
|
-
|
|
6183
|
+
logger5.info("Commit watcher started", {
|
|
5961
6184
|
branch,
|
|
5962
6185
|
baseSha: this.lastKnownRemoteSha?.slice(0, 8)
|
|
5963
6186
|
});
|
|
@@ -6022,7 +6245,7 @@ var CommitWatcher = class {
|
|
|
6022
6245
|
}
|
|
6023
6246
|
this.lastKnownRemoteSha = remoteSha;
|
|
6024
6247
|
this.isSyncing = true;
|
|
6025
|
-
|
|
6248
|
+
logger5.info("New commits detected", {
|
|
6026
6249
|
branch: this.branch,
|
|
6027
6250
|
commitCount,
|
|
6028
6251
|
sha: remoteSha.slice(0, 8)
|
|
@@ -6038,7 +6261,7 @@ var CommitWatcher = class {
|
|
|
6038
6261
|
});
|
|
6039
6262
|
} catch (err) {
|
|
6040
6263
|
const msg = err instanceof Error ? err.message : String(err);
|
|
6041
|
-
|
|
6264
|
+
logger5.error("Error handling new commits", { error: msg });
|
|
6042
6265
|
} finally {
|
|
6043
6266
|
this.isSyncing = false;
|
|
6044
6267
|
}
|
|
@@ -6275,7 +6498,7 @@ function buildProjectTools(connection) {
|
|
|
6275
6498
|
}
|
|
6276
6499
|
|
|
6277
6500
|
// src/runner/project-chat-handler.ts
|
|
6278
|
-
var
|
|
6501
|
+
var logger6 = createServiceLogger("ProjectChat");
|
|
6279
6502
|
var FALLBACK_MODEL = "claude-sonnet-4-20250514";
|
|
6280
6503
|
function buildSystemPrompt2(projectDir, agentCtx) {
|
|
6281
6504
|
const parts = [];
|
|
@@ -6322,7 +6545,7 @@ async function fetchContext(connection, chatId) {
|
|
|
6322
6545
|
projectId: connection.projectId
|
|
6323
6546
|
});
|
|
6324
6547
|
} catch {
|
|
6325
|
-
|
|
6548
|
+
logger6.warn("Could not fetch agent context, using defaults");
|
|
6326
6549
|
}
|
|
6327
6550
|
let chatHistory = [];
|
|
6328
6551
|
try {
|
|
@@ -6332,7 +6555,7 @@ async function fetchContext(connection, chatId) {
|
|
|
6332
6555
|
chatId
|
|
6333
6556
|
});
|
|
6334
6557
|
} catch {
|
|
6335
|
-
|
|
6558
|
+
logger6.warn("Could not fetch chat history, proceeding without it");
|
|
6336
6559
|
}
|
|
6337
6560
|
return { agentCtx, chatHistory };
|
|
6338
6561
|
}
|
|
@@ -6450,7 +6673,7 @@ async function handleProjectChatMessage(message, connection, projectDir, session
|
|
|
6450
6673
|
return await runChatQuery(message, connection, projectDir, sessionId);
|
|
6451
6674
|
} catch (error) {
|
|
6452
6675
|
const msg = error instanceof Error ? error.message : String(error);
|
|
6453
|
-
|
|
6676
|
+
logger6.error("Failed to handle message", { error: msg });
|
|
6454
6677
|
try {
|
|
6455
6678
|
await connection.call("postProjectAgentMessage", {
|
|
6456
6679
|
projectId: connection.projectId,
|
|
@@ -6466,7 +6689,7 @@ async function handleProjectChatMessage(message, connection, projectDir, session
|
|
|
6466
6689
|
}
|
|
6467
6690
|
|
|
6468
6691
|
// src/runner/project-runner.ts
|
|
6469
|
-
var
|
|
6692
|
+
var logger7 = createServiceLogger("ProjectRunner");
|
|
6470
6693
|
var __filename = fileURLToPath(import.meta.url);
|
|
6471
6694
|
var __dirname = path.dirname(__filename);
|
|
6472
6695
|
var HEARTBEAT_INTERVAL_MS = 3e4;
|
|
@@ -6485,7 +6708,7 @@ function setupWorkDir(projectDir, assignment) {
|
|
|
6485
6708
|
}
|
|
6486
6709
|
if (branch && branch !== devBranch) {
|
|
6487
6710
|
if (hasUncommittedChanges(workDir)) {
|
|
6488
|
-
|
|
6711
|
+
logger7.warn("Uncommitted changes, skipping checkout", { taskId: shortId, branch });
|
|
6489
6712
|
} else {
|
|
6490
6713
|
try {
|
|
6491
6714
|
execSync5(`git checkout ${branch}`, { cwd: workDir, stdio: "ignore" });
|
|
@@ -6493,7 +6716,7 @@ function setupWorkDir(projectDir, assignment) {
|
|
|
6493
6716
|
try {
|
|
6494
6717
|
execSync5(`git checkout -b ${branch}`, { cwd: workDir, stdio: "ignore" });
|
|
6495
6718
|
} catch {
|
|
6496
|
-
|
|
6719
|
+
logger7.warn("Could not checkout branch", { taskId: shortId, branch });
|
|
6497
6720
|
}
|
|
6498
6721
|
}
|
|
6499
6722
|
}
|
|
@@ -6509,7 +6732,7 @@ function spawnChildAgent(assignment, workDir) {
|
|
|
6509
6732
|
const effectiveAgentMode = agentMode ?? (isAuto ? "auto" : "");
|
|
6510
6733
|
const effectiveApiUrl = apiUrl || process.env.CONVEYOR_API_URL || "";
|
|
6511
6734
|
if (!effectiveApiUrl) {
|
|
6512
|
-
|
|
6735
|
+
logger7.error("No API URL available for child agent", { taskId: taskId.slice(0, 8) });
|
|
6513
6736
|
}
|
|
6514
6737
|
const child = fork(cliPath, [], {
|
|
6515
6738
|
env: {
|
|
@@ -6537,12 +6760,12 @@ function spawnChildAgent(assignment, workDir) {
|
|
|
6537
6760
|
const shortId = taskId.slice(0, 8);
|
|
6538
6761
|
child.stdout?.on("data", (data) => {
|
|
6539
6762
|
for (const line of data.toString().trimEnd().split("\n")) {
|
|
6540
|
-
|
|
6763
|
+
logger7.info(line, { taskId: shortId });
|
|
6541
6764
|
}
|
|
6542
6765
|
});
|
|
6543
6766
|
child.stderr?.on("data", (data) => {
|
|
6544
6767
|
for (const line of data.toString().trimEnd().split("\n")) {
|
|
6545
|
-
|
|
6768
|
+
logger7.info(line, { taskId: shortId });
|
|
6546
6769
|
}
|
|
6547
6770
|
});
|
|
6548
6771
|
return child;
|
|
@@ -6590,7 +6813,7 @@ var ProjectRunner = class {
|
|
|
6590
6813
|
capabilities: ["task", "pm", "code-review", "audit"]
|
|
6591
6814
|
});
|
|
6592
6815
|
this.branchSwitchCommand = registration.branchSwitchCommand ?? process.env.CONVEYOR_BRANCH_SWITCH_COMMAND;
|
|
6593
|
-
|
|
6816
|
+
logger7.info("Registered as project agent", { agentName: registration.agentName });
|
|
6594
6817
|
try {
|
|
6595
6818
|
await this.executeSetupCommand();
|
|
6596
6819
|
this.executeStartCommand();
|
|
@@ -6601,7 +6824,7 @@ var ProjectRunner = class {
|
|
|
6601
6824
|
});
|
|
6602
6825
|
} catch (error) {
|
|
6603
6826
|
const msg = error instanceof Error ? error.message : String(error);
|
|
6604
|
-
|
|
6827
|
+
logger7.error("Environment setup failed", { error: msg });
|
|
6605
6828
|
this.setupComplete = false;
|
|
6606
6829
|
}
|
|
6607
6830
|
this.wireEventHandlers();
|
|
@@ -6613,7 +6836,7 @@ var ProjectRunner = class {
|
|
|
6613
6836
|
if (currentBranch) {
|
|
6614
6837
|
this.commitWatcher.start(currentBranch);
|
|
6615
6838
|
}
|
|
6616
|
-
|
|
6839
|
+
logger7.info("Connected, waiting for task assignments");
|
|
6617
6840
|
await new Promise((resolve2) => {
|
|
6618
6841
|
this.resolveLifecycle = resolve2;
|
|
6619
6842
|
});
|
|
@@ -6621,7 +6844,7 @@ var ProjectRunner = class {
|
|
|
6621
6844
|
async stop() {
|
|
6622
6845
|
if (this.stopping) return;
|
|
6623
6846
|
this.stopping = true;
|
|
6624
|
-
|
|
6847
|
+
logger7.info("Shutting down");
|
|
6625
6848
|
this.commitWatcher.stop();
|
|
6626
6849
|
await this.killStartCommand();
|
|
6627
6850
|
if (this.heartbeatTimer) {
|
|
@@ -6652,7 +6875,7 @@ var ProjectRunner = class {
|
|
|
6652
6875
|
} catch {
|
|
6653
6876
|
}
|
|
6654
6877
|
this.connection.disconnect();
|
|
6655
|
-
|
|
6878
|
+
logger7.info("Shutdown complete");
|
|
6656
6879
|
if (this.resolveLifecycle) {
|
|
6657
6880
|
this.resolveLifecycle();
|
|
6658
6881
|
this.resolveLifecycle = null;
|
|
@@ -6688,10 +6911,10 @@ var ProjectRunner = class {
|
|
|
6688
6911
|
capabilities: ["task", "pm", "code-review", "audit"]
|
|
6689
6912
|
});
|
|
6690
6913
|
this.connection.emitStatus(this.activeAgents.size > 0 ? "busy" : "idle");
|
|
6691
|
-
|
|
6914
|
+
logger7.info("Re-registered after reconnect");
|
|
6692
6915
|
} catch (error) {
|
|
6693
6916
|
const msg = error instanceof Error ? error.message : String(error);
|
|
6694
|
-
|
|
6917
|
+
logger7.error("Failed to re-register after reconnect", { error: msg });
|
|
6695
6918
|
}
|
|
6696
6919
|
}
|
|
6697
6920
|
// ── Tag audit ──────────────────────────────────────────────────────────
|
|
@@ -6702,7 +6925,7 @@ var ProjectRunner = class {
|
|
|
6702
6925
|
await handleTagAudit(request, this.connection, this.projectDir);
|
|
6703
6926
|
} catch (error) {
|
|
6704
6927
|
const msg = error instanceof Error ? error.message : String(error);
|
|
6705
|
-
|
|
6928
|
+
logger7.error("Tag audit failed", { error: msg, requestId: request.requestId });
|
|
6706
6929
|
try {
|
|
6707
6930
|
await this.connection.call("reportTagAuditResult", {
|
|
6708
6931
|
projectId: this.connection.projectId,
|
|
@@ -6721,15 +6944,15 @@ var ProjectRunner = class {
|
|
|
6721
6944
|
async killAgent(agent, taskId) {
|
|
6722
6945
|
const shortId = taskId.slice(0, 8);
|
|
6723
6946
|
if (agent.process.exitCode !== null) {
|
|
6724
|
-
|
|
6947
|
+
logger7.info("Agent process already exited", { taskId: shortId });
|
|
6725
6948
|
return;
|
|
6726
6949
|
}
|
|
6727
|
-
|
|
6950
|
+
logger7.info("Killing agent process", { taskId: shortId });
|
|
6728
6951
|
agent.process.kill("SIGTERM");
|
|
6729
6952
|
await new Promise((resolve2) => {
|
|
6730
6953
|
const timer = setTimeout(() => {
|
|
6731
6954
|
if (agent.process.exitCode === null) {
|
|
6732
|
-
|
|
6955
|
+
logger7.warn("Agent did not exit after SIGTERM, sending SIGKILL", { taskId: shortId });
|
|
6733
6956
|
agent.process.kill("SIGKILL");
|
|
6734
6957
|
}
|
|
6735
6958
|
resolve2();
|
|
@@ -6748,15 +6971,15 @@ var ProjectRunner = class {
|
|
|
6748
6971
|
const existing = this.activeAgents.get(agentKey);
|
|
6749
6972
|
if (existing) {
|
|
6750
6973
|
if (existing.process.exitCode === null) {
|
|
6751
|
-
|
|
6974
|
+
logger7.info("Re-assignment received, killing existing agent", { taskId: shortId });
|
|
6752
6975
|
await this.killAgent(existing, taskId);
|
|
6753
6976
|
} else {
|
|
6754
|
-
|
|
6977
|
+
logger7.info("Stale agent entry (process already exited), cleaning up", { taskId: shortId });
|
|
6755
6978
|
}
|
|
6756
6979
|
this.activeAgents.delete(agentKey);
|
|
6757
6980
|
}
|
|
6758
6981
|
if (this.activeAgents.size >= MAX_CONCURRENT) {
|
|
6759
|
-
|
|
6982
|
+
logger7.warn("Max concurrent agents reached", { maxConcurrent: MAX_CONCURRENT });
|
|
6760
6983
|
this.connection.emitTaskStopped(taskId, "max_concurrent_reached");
|
|
6761
6984
|
return;
|
|
6762
6985
|
}
|
|
@@ -6764,9 +6987,12 @@ var ProjectRunner = class {
|
|
|
6764
6987
|
try {
|
|
6765
6988
|
execSync5("git fetch origin", { cwd: this.projectDir, stdio: "ignore" });
|
|
6766
6989
|
} catch {
|
|
6767
|
-
|
|
6990
|
+
logger7.warn("Git fetch failed", { taskId: shortId });
|
|
6768
6991
|
}
|
|
6769
6992
|
const { workDir, usesWorktree } = setupWorkDir(this.projectDir, assignment);
|
|
6993
|
+
if (assignment.devBranch) {
|
|
6994
|
+
syncWithBaseBranch(workDir, assignment.devBranch);
|
|
6995
|
+
}
|
|
6770
6996
|
const child = spawnChildAgent(assignment, workDir);
|
|
6771
6997
|
this.activeAgents.set(agentKey, {
|
|
6772
6998
|
process: child,
|
|
@@ -6775,12 +7001,12 @@ var ProjectRunner = class {
|
|
|
6775
7001
|
usesWorktree
|
|
6776
7002
|
});
|
|
6777
7003
|
this.connection.emitTaskStarted(taskId);
|
|
6778
|
-
|
|
7004
|
+
logger7.info("Started task", { taskId: shortId, mode, workDir });
|
|
6779
7005
|
child.on("exit", (code) => {
|
|
6780
7006
|
this.activeAgents.delete(agentKey);
|
|
6781
7007
|
const reason = code === 0 ? "completed" : `exited with code ${code}`;
|
|
6782
7008
|
this.connection.emitTaskStopped(taskId, reason);
|
|
6783
|
-
|
|
7009
|
+
logger7.info("Task exited", { taskId: shortId, reason });
|
|
6784
7010
|
if (code === 0 && usesWorktree) {
|
|
6785
7011
|
try {
|
|
6786
7012
|
removeWorktree(this.projectDir, taskId);
|
|
@@ -6790,7 +7016,7 @@ var ProjectRunner = class {
|
|
|
6790
7016
|
});
|
|
6791
7017
|
} catch (error) {
|
|
6792
7018
|
const msg = error instanceof Error ? error.message : "Unknown";
|
|
6793
|
-
|
|
7019
|
+
logger7.error("Failed to start task", { taskId: shortId, error: msg });
|
|
6794
7020
|
this.connection.emitTaskStopped(taskId, `start_failed: ${msg}`);
|
|
6795
7021
|
}
|
|
6796
7022
|
}
|
|
@@ -6798,7 +7024,7 @@ var ProjectRunner = class {
|
|
|
6798
7024
|
const agentKey = this.activeAgents.has(taskId) ? taskId : `${taskId}:code-review`;
|
|
6799
7025
|
const agent = this.activeAgents.get(agentKey);
|
|
6800
7026
|
if (!agent) return;
|
|
6801
|
-
|
|
7027
|
+
logger7.info("Stopping task", { taskId: taskId.slice(0, 8) });
|
|
6802
7028
|
void this.killAgent(agent, taskId).then(() => {
|
|
6803
7029
|
if (agent.usesWorktree) {
|
|
6804
7030
|
try {
|
|
@@ -6815,30 +7041,30 @@ var ProjectRunner = class {
|
|
|
6815
7041
|
const currentBranch = this.getCurrentBranch();
|
|
6816
7042
|
if (currentBranch === workspaceBranch) return;
|
|
6817
7043
|
if (hasUncommittedChanges(this.projectDir)) {
|
|
6818
|
-
|
|
7044
|
+
logger7.warn("Uncommitted changes, skipping workspace branch checkout");
|
|
6819
7045
|
return;
|
|
6820
7046
|
}
|
|
6821
7047
|
try {
|
|
6822
7048
|
execSync5(`git fetch origin ${workspaceBranch}`, { cwd: this.projectDir, stdio: "pipe" });
|
|
6823
7049
|
execSync5(`git checkout ${workspaceBranch}`, { cwd: this.projectDir, stdio: "pipe" });
|
|
6824
|
-
|
|
7050
|
+
logger7.info("Checked out workspace branch", { workspaceBranch });
|
|
6825
7051
|
} catch {
|
|
6826
|
-
|
|
7052
|
+
logger7.warn("Failed to checkout workspace branch", { workspaceBranch });
|
|
6827
7053
|
}
|
|
6828
7054
|
}
|
|
6829
7055
|
async executeSetupCommand() {
|
|
6830
7056
|
const cmd = process.env.CONVEYOR_SETUP_COMMAND;
|
|
6831
7057
|
if (!cmd) return;
|
|
6832
|
-
|
|
7058
|
+
logger7.info("Running setup command", { command: cmd });
|
|
6833
7059
|
try {
|
|
6834
7060
|
await runSetupCommand(cmd, this.projectDir, (stream, data) => {
|
|
6835
7061
|
this.connection.sendEvent({ type: "setup_output", stream, data });
|
|
6836
7062
|
(stream === "stderr" ? process.stderr : process.stdout).write(data);
|
|
6837
7063
|
});
|
|
6838
|
-
|
|
7064
|
+
logger7.info("Setup command completed");
|
|
6839
7065
|
} catch (error) {
|
|
6840
7066
|
const msg = error instanceof Error ? error.message : "Setup command failed";
|
|
6841
|
-
|
|
7067
|
+
logger7.error("Setup command failed", { error: msg });
|
|
6842
7068
|
this.connection.sendEvent({ type: "setup_error", message: msg });
|
|
6843
7069
|
throw error;
|
|
6844
7070
|
}
|
|
@@ -6846,7 +7072,7 @@ var ProjectRunner = class {
|
|
|
6846
7072
|
executeStartCommand() {
|
|
6847
7073
|
const cmd = process.env.CONVEYOR_START_COMMAND;
|
|
6848
7074
|
if (!cmd) return;
|
|
6849
|
-
|
|
7075
|
+
logger7.info("Running start command", { command: cmd });
|
|
6850
7076
|
const child = runStartCommand(cmd, this.projectDir, (stream, data) => {
|
|
6851
7077
|
this.connection.sendEvent({ type: "start_command_output", stream, data });
|
|
6852
7078
|
(stream === "stderr" ? process.stderr : process.stdout).write(data);
|
|
@@ -6856,13 +7082,13 @@ var ProjectRunner = class {
|
|
|
6856
7082
|
child.on("exit", (code, signal) => {
|
|
6857
7083
|
this.startCommandRunning = false;
|
|
6858
7084
|
this.startCommandChild = null;
|
|
6859
|
-
|
|
7085
|
+
logger7.info("Start command exited", { code, signal });
|
|
6860
7086
|
this.connection.sendEvent({ type: "start_command_exited", code, signal });
|
|
6861
7087
|
});
|
|
6862
7088
|
child.on("error", (err) => {
|
|
6863
7089
|
this.startCommandRunning = false;
|
|
6864
7090
|
this.startCommandChild = null;
|
|
6865
|
-
|
|
7091
|
+
logger7.error("Start command error", { error: err.message });
|
|
6866
7092
|
});
|
|
6867
7093
|
}
|
|
6868
7094
|
async killStartCommand() {
|
|
@@ -6905,7 +7131,7 @@ var ProjectRunner = class {
|
|
|
6905
7131
|
try {
|
|
6906
7132
|
execSync5("git fetch origin", { cwd: this.projectDir, stdio: "pipe" });
|
|
6907
7133
|
} catch {
|
|
6908
|
-
|
|
7134
|
+
logger7.warn("Git fetch failed during branch switch");
|
|
6909
7135
|
}
|
|
6910
7136
|
detachWorktreeBranch(this.projectDir, data.branch);
|
|
6911
7137
|
try {
|
|
@@ -6918,7 +7144,7 @@ var ProjectRunner = class {
|
|
|
6918
7144
|
try {
|
|
6919
7145
|
execSync5(`git pull origin ${data.branch}`, { cwd: this.projectDir, stdio: "pipe" });
|
|
6920
7146
|
} catch {
|
|
6921
|
-
|
|
7147
|
+
logger7.warn("Git pull failed during branch switch");
|
|
6922
7148
|
}
|
|
6923
7149
|
if (data.syncAfter !== false) {
|
|
6924
7150
|
await this.handleSyncEnvironment();
|
|
@@ -6927,7 +7153,7 @@ var ProjectRunner = class {
|
|
|
6927
7153
|
callback({ ok: true });
|
|
6928
7154
|
} catch (err) {
|
|
6929
7155
|
const msg = err instanceof Error ? err.message : "Branch switch failed";
|
|
6930
|
-
|
|
7156
|
+
logger7.error("Branch switch failed", { error: msg });
|
|
6931
7157
|
callback({ ok: false, error: msg });
|
|
6932
7158
|
}
|
|
6933
7159
|
}
|
|
@@ -6942,14 +7168,14 @@ var ProjectRunner = class {
|
|
|
6942
7168
|
});
|
|
6943
7169
|
} catch (err) {
|
|
6944
7170
|
const msg = err instanceof Error ? err.message : "Sync command failed";
|
|
6945
|
-
|
|
7171
|
+
logger7.error("Branch switch sync command failed", { error: msg });
|
|
6946
7172
|
}
|
|
6947
7173
|
}
|
|
6948
7174
|
this.executeStartCommand();
|
|
6949
7175
|
callback?.({ ok: true });
|
|
6950
7176
|
} catch (err) {
|
|
6951
7177
|
const msg = err instanceof Error ? err.message : "Sync failed";
|
|
6952
|
-
|
|
7178
|
+
logger7.error("Environment sync failed", { error: msg });
|
|
6953
7179
|
callback?.({ ok: false, error: msg });
|
|
6954
7180
|
}
|
|
6955
7181
|
}
|
|
@@ -6974,7 +7200,7 @@ var ProjectRunner = class {
|
|
|
6974
7200
|
setupComplete: this.setupComplete,
|
|
6975
7201
|
startCommandRunning: this.startCommandRunning
|
|
6976
7202
|
});
|
|
6977
|
-
|
|
7203
|
+
logger7.info("Commit sync complete", { steps: stepsRun.join(", ") });
|
|
6978
7204
|
}
|
|
6979
7205
|
async smartSync(previousSha, newSha, branch) {
|
|
6980
7206
|
if (hasUncommittedChanges(this.projectDir)) {
|
|
@@ -6993,7 +7219,7 @@ var ProjectRunner = class {
|
|
|
6993
7219
|
});
|
|
6994
7220
|
} catch (err) {
|
|
6995
7221
|
const msg = err instanceof Error ? err.message : "Pull failed";
|
|
6996
|
-
|
|
7222
|
+
logger7.error("Git pull failed during commit sync", { error: msg });
|
|
6997
7223
|
this.executeStartCommand();
|
|
6998
7224
|
return ["error:pull"];
|
|
6999
7225
|
}
|
|
@@ -7020,7 +7246,7 @@ var ProjectRunner = class {
|
|
|
7020
7246
|
stepsRun.push("branchSwitchCommand");
|
|
7021
7247
|
} catch (err) {
|
|
7022
7248
|
const msg = err instanceof Error ? err.message : "Sync command failed";
|
|
7023
|
-
|
|
7249
|
+
logger7.error("Branch switch command failed", { error: msg });
|
|
7024
7250
|
}
|
|
7025
7251
|
} else if (!cmd) {
|
|
7026
7252
|
this.runIndividualSyncSteps(needsInstall, needsPrisma, stepsRun);
|
|
@@ -7033,7 +7259,7 @@ var ProjectRunner = class {
|
|
|
7033
7259
|
stepsRun.push("install");
|
|
7034
7260
|
} catch (err) {
|
|
7035
7261
|
const msg = err instanceof Error ? err.message : "Install failed";
|
|
7036
|
-
|
|
7262
|
+
logger7.error("bun install failed", { error: msg });
|
|
7037
7263
|
}
|
|
7038
7264
|
}
|
|
7039
7265
|
if (needsPrisma) {
|
|
@@ -7047,7 +7273,7 @@ var ProjectRunner = class {
|
|
|
7047
7273
|
stepsRun.push("prisma");
|
|
7048
7274
|
} catch (err) {
|
|
7049
7275
|
const msg = err instanceof Error ? err.message : "Prisma sync failed";
|
|
7050
|
-
|
|
7276
|
+
logger7.error("Prisma sync failed", { error: msg });
|
|
7051
7277
|
}
|
|
7052
7278
|
}
|
|
7053
7279
|
}
|
|
@@ -7063,6 +7289,33 @@ var ProjectRunner = class {
|
|
|
7063
7289
|
}
|
|
7064
7290
|
};
|
|
7065
7291
|
|
|
7292
|
+
// src/setup/config.ts
|
|
7293
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
7294
|
+
import { join as join3 } from "path";
|
|
7295
|
+
var DEVCONTAINER_PATH = ".devcontainer/conveyor/devcontainer.json";
|
|
7296
|
+
async function loadForwardPorts(workspaceDir) {
|
|
7297
|
+
try {
|
|
7298
|
+
const raw = await readFile2(join3(workspaceDir, DEVCONTAINER_PATH), "utf-8");
|
|
7299
|
+
const parsed = JSON.parse(raw);
|
|
7300
|
+
return parsed.forwardPorts ?? [];
|
|
7301
|
+
} catch {
|
|
7302
|
+
return [];
|
|
7303
|
+
}
|
|
7304
|
+
}
|
|
7305
|
+
function loadConveyorConfig() {
|
|
7306
|
+
const envSetup = process.env.CONVEYOR_SETUP_COMMAND;
|
|
7307
|
+
const envStart = process.env.CONVEYOR_START_COMMAND;
|
|
7308
|
+
const envPort = process.env.CONVEYOR_PREVIEW_PORT;
|
|
7309
|
+
if (envSetup || envStart) {
|
|
7310
|
+
return {
|
|
7311
|
+
setupCommand: envSetup,
|
|
7312
|
+
startCommand: envStart,
|
|
7313
|
+
previewPort: envPort ? Number(envPort) : void 0
|
|
7314
|
+
};
|
|
7315
|
+
}
|
|
7316
|
+
return null;
|
|
7317
|
+
}
|
|
7318
|
+
|
|
7066
7319
|
export {
|
|
7067
7320
|
AgentConnection,
|
|
7068
7321
|
ModeController,
|
|
@@ -7085,6 +7338,8 @@ export {
|
|
|
7085
7338
|
ensureWorktree,
|
|
7086
7339
|
detachWorktreeBranch,
|
|
7087
7340
|
removeWorktree,
|
|
7088
|
-
ProjectRunner
|
|
7341
|
+
ProjectRunner,
|
|
7342
|
+
loadForwardPorts,
|
|
7343
|
+
loadConveyorConfig
|
|
7089
7344
|
};
|
|
7090
|
-
//# sourceMappingURL=chunk-
|
|
7345
|
+
//# sourceMappingURL=chunk-FCRGYU2M.js.map
|