chatroom-cli 1.57.2 → 1.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1729 -438
- package/dist/index.js.map +71 -52
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -28903,6 +28903,12 @@ function normalizeCursorSdkListedModels(listedModelIds) {
|
|
|
28903
28903
|
var CURSOR_PROVIDER2 = "cursor", DEFAULT_AUTO_MODEL_ID = "default", UI_AUTO_MODEL_ID = "auto";
|
|
28904
28904
|
|
|
28905
28905
|
// src/infrastructure/services/remote-agents/cursor-sdk/cursor-sdk-package.ts
|
|
28906
|
+
var exports_cursor_sdk_package = {};
|
|
28907
|
+
__export(exports_cursor_sdk_package, {
|
|
28908
|
+
importBundledCursorSdk: () => importBundledCursorSdk,
|
|
28909
|
+
getBundledCursorSdkVersion: () => getBundledCursorSdkVersion,
|
|
28910
|
+
formatCursorSdkLoadError: () => formatCursorSdkLoadError
|
|
28911
|
+
});
|
|
28906
28912
|
import { existsSync, readFileSync as readFileSync2 } from "node:fs";
|
|
28907
28913
|
import { createRequire as createRequire3 } from "node:module";
|
|
28908
28914
|
import { dirname as dirname2, join as join7 } from "node:path";
|
|
@@ -32520,6 +32526,12 @@ var init_opencode_sdk = __esm(() => {
|
|
|
32520
32526
|
});
|
|
32521
32527
|
|
|
32522
32528
|
// src/infrastructure/services/remote-agents/pi-sdk/pi-sdk-package.ts
|
|
32529
|
+
var exports_pi_sdk_package = {};
|
|
32530
|
+
__export(exports_pi_sdk_package, {
|
|
32531
|
+
importBundledPiSdk: () => importBundledPiSdk,
|
|
32532
|
+
getBundledPiSdkVersion: () => getBundledPiSdkVersion,
|
|
32533
|
+
formatPiSdkLoadError: () => formatPiSdkLoadError
|
|
32534
|
+
});
|
|
32523
32535
|
import { existsSync as existsSync3, readFileSync as readFileSync4 } from "node:fs";
|
|
32524
32536
|
import { dirname as dirname4, join as join9 } from "node:path";
|
|
32525
32537
|
import { fileURLToPath as fileURLToPath3, pathToFileURL as pathToFileURL2 } from "node:url";
|
|
@@ -75554,14 +75566,25 @@ Put your **complete** deliverable in the handoff message — not in session text
|
|
|
75554
75566
|
function getBuilderToPlannerHandoffTemplate() {
|
|
75555
75567
|
return `${getHandoffRecipientVisibilityCallout("planner")}
|
|
75556
75568
|
|
|
75557
|
-
**Handoff Template (Builder → Planner)** — paste into the handoff message. Fill in EVERY section
|
|
75569
|
+
**Handoff Template (Builder → Planner)** — paste into the handoff message. Fill in EVERY section below. If a section does not apply, write \`Not Applicable\` (do not delete the section):
|
|
75558
75570
|
|
|
75559
75571
|
\`\`\`markdown
|
|
75560
75572
|
## Summary
|
|
75561
75573
|
<what was implemented or attempted, in plain terms>
|
|
75562
75574
|
|
|
75563
|
-
##
|
|
75575
|
+
## Template Disclosure Confirmation
|
|
75576
|
+
- [ ] I confirm that I have seen this template at the start of this task, before implementing or modifying any code
|
|
75577
|
+
|
|
75578
|
+
## Proof of Principle
|
|
75579
|
+
<!-- Demonstrate adherence to:
|
|
75580
|
+
- Organization & Maintainability: a small change in requirements should result in a small change in code in a small number of files and folders.
|
|
75581
|
+
- Static Evaluability and Provability: the system's behavior should be provably correct by looking at the source code, then automated tests, then manual tests, in this order.
|
|
75582
|
+
-->
|
|
75583
|
+
<how this work follows the principles above — localized changes, readable structure, correctness provable from source then tests>
|
|
75584
|
+
|
|
75585
|
+
## Proof of Completion
|
|
75564
75586
|
- \`path/to/file.ts\` — <what changed and why>
|
|
75587
|
+
<evidence the goal was met — list every file you modified>
|
|
75565
75588
|
|
|
75566
75589
|
## Verification
|
|
75567
75590
|
- \`pnpm typecheck && pnpm test\` — <pass/fail + notes>
|
|
@@ -75643,7 +75666,7 @@ Cross-file types, interfaces, or patterns that apply beyond a single file. Write
|
|
|
75643
75666
|
- <e.g. "Do not add new abstractions", "Do not refactor unrelated files", "Do not change existing public APIs", or "Not Applicable">
|
|
75644
75667
|
|
|
75645
75668
|
## Skills to activate
|
|
75646
|
-
- <e.g. chatroom skill activate
|
|
75669
|
+
- <e.g. chatroom skill activate code-review --chatroom-id=<id> --role=builder, or "Not Applicable">
|
|
75647
75670
|
|
|
75648
75671
|
## Out of scope
|
|
75649
75672
|
- <files or areas the builder must NOT touch in this slice, or "Not Applicable">
|
|
@@ -75684,6 +75707,15 @@ function getPlannerToUserReportTemplate() {
|
|
|
75684
75707
|
- \`path/to/file.ts\` — <what changed and why>
|
|
75685
75708
|
<evidence the goal was met — list every file you (or the builder) modified>
|
|
75686
75709
|
|
|
75710
|
+
## Backlog Tasks Implemented
|
|
75711
|
+
- \`backlog-item-id\` — <backlog item title/summary and how this work addresses it>
|
|
75712
|
+
<List every backlog item this work implemented. Write \`Not Applicable\` if no backlog items were in scope.>
|
|
75713
|
+
|
|
75714
|
+
## Backlog Pending User Review Confirmation
|
|
75715
|
+
- [ ] I confirm that every backlog item implemented in this work has been moved to \`pending_user_review\` via \`chatroom backlog mark-for-review\` because a PR has been raised for user review
|
|
75716
|
+
- PR URL(s): <link to PR(s), or \`Not Applicable\` if no PR was raised>
|
|
75717
|
+
- If no backlog items apply, write \`Not Applicable\` for the checkbox and explain in one line
|
|
75718
|
+
|
|
75687
75719
|
## Key Technical Decisions
|
|
75688
75720
|
- <schema design, modules, interfaces, domain entities — what you chose and why, or "Not Applicable">
|
|
75689
75721
|
|
|
@@ -76013,16 +76045,11 @@ var init_fromContext = __esm(() => {
|
|
|
76013
76045
|
init_planner();
|
|
76014
76046
|
init_solo();
|
|
76015
76047
|
});
|
|
76016
|
-
// ../../services/backend/prompts/cli/sections/handoff-templates-preview.ts
|
|
76017
|
-
var init_handoff_templates_preview = __esm(() => {
|
|
76018
|
-
init_handoff_templates3();
|
|
76019
|
-
});
|
|
76020
76048
|
|
|
76021
76049
|
// ../../services/backend/prompts/native/task-started-content.ts
|
|
76022
76050
|
var init_task_started_content = __esm(() => {
|
|
76023
76051
|
init_new();
|
|
76024
76052
|
});
|
|
76025
|
-
|
|
76026
76053
|
// ../../services/backend/prompts/sections/classification-guide.ts
|
|
76027
76054
|
var init_classification_guide = __esm(() => {
|
|
76028
76055
|
init_cli();
|
|
@@ -76050,6 +76077,8 @@ var init_current_classification = () => {};
|
|
|
76050
76077
|
var init_getting_started = __esm(() => {
|
|
76051
76078
|
init_getting_started_content();
|
|
76052
76079
|
});
|
|
76080
|
+
// ../../services/backend/src/domain/usecase/skills/modules/attachments/index.ts
|
|
76081
|
+
var init_attachments = () => {};
|
|
76053
76082
|
|
|
76054
76083
|
// ../../services/backend/prompts/cli/backlog/command.ts
|
|
76055
76084
|
var init_command3 = __esm(() => {
|
|
@@ -76064,18 +76093,11 @@ var init_backlog = __esm(() => {
|
|
|
76064
76093
|
// ../../services/backend/src/domain/usecase/skills/modules/code-review/index.ts
|
|
76065
76094
|
var init_code_review = () => {};
|
|
76066
76095
|
|
|
76067
|
-
// ../../services/backend/src/domain/usecase/skills/modules/development-workflow/index.ts
|
|
76068
|
-
var init_development_workflow = () => {};
|
|
76069
|
-
|
|
76070
|
-
// ../../services/backend/src/domain/usecase/skills/modules/software-engineering/index.ts
|
|
76071
|
-
var init_software_engineering = () => {};
|
|
76072
|
-
|
|
76073
76096
|
// ../../services/backend/src/domain/usecase/skills/registry.ts
|
|
76074
76097
|
var init_registry3 = __esm(() => {
|
|
76098
|
+
init_attachments();
|
|
76075
76099
|
init_backlog();
|
|
76076
76100
|
init_code_review();
|
|
76077
|
-
init_development_workflow();
|
|
76078
|
-
init_software_engineering();
|
|
76079
76101
|
});
|
|
76080
76102
|
|
|
76081
76103
|
// ../../services/backend/prompts/sections/glossary.ts
|
|
@@ -76102,20 +76124,15 @@ var init_glossary = __esm(() => {
|
|
|
76102
76124
|
linkedSkillId: "backlog"
|
|
76103
76125
|
},
|
|
76104
76126
|
{
|
|
76105
|
-
term: "
|
|
76106
|
-
definition: "
|
|
76107
|
-
linkedSkillId: "
|
|
76127
|
+
term: "attachments",
|
|
76128
|
+
definition: "Message attachment types (task, backlog, message, snippet) and their compose, delivery, and task-read paths. " + "Use when adding or changing attachment UI, delivery XML, or agent-facing attachment formats.",
|
|
76129
|
+
linkedSkillId: "attachments"
|
|
76108
76130
|
},
|
|
76109
76131
|
{
|
|
76110
76132
|
term: "code-review",
|
|
76111
76133
|
definition: "Eight-pillar code review framework: simplification, type drift, duplication, design patterns, security, test quality, ownership/observability, and dead code elimination. " + "Covers AI-generated code review with focus on maintainability and tech debt prevention.",
|
|
76112
76134
|
linkedSkillId: "code-review"
|
|
76113
76135
|
},
|
|
76114
|
-
{
|
|
76115
|
-
term: "development-workflow",
|
|
76116
|
-
definition: "Manages the development and release flow: creating release branches, updating versions, raising PRs, and managing feature branches. " + "Use this skill for coordinating complex release and development processes.",
|
|
76117
|
-
linkedSkillId: "development-workflow"
|
|
76118
|
-
},
|
|
76119
76136
|
{
|
|
76120
76137
|
term: "structural-decisions",
|
|
76121
76138
|
definition: "Meta-level architectural choices that persist in the codebase and influence consistency: " + "folder structure, file naming, interface definitions, and key abstraction names/locations " + "(e.g., Repository/Service layers)."
|
|
@@ -76191,7 +76208,7 @@ var claudeCapabilities;
|
|
|
76191
76208
|
var init_claude_config = __esm(() => {
|
|
76192
76209
|
claudeCapabilities = {
|
|
76193
76210
|
runtimeKind: "cli",
|
|
76194
|
-
|
|
76211
|
+
supportsDaemonMemoryResume: false,
|
|
76195
76212
|
supportsNativeIntegration: false,
|
|
76196
76213
|
lifecycle: {
|
|
76197
76214
|
turnCompleted: false,
|
|
@@ -76207,7 +76224,7 @@ var commandcodeCapabilities;
|
|
|
76207
76224
|
var init_commandcode_config = __esm(() => {
|
|
76208
76225
|
commandcodeCapabilities = {
|
|
76209
76226
|
runtimeKind: "cli",
|
|
76210
|
-
|
|
76227
|
+
supportsDaemonMemoryResume: false,
|
|
76211
76228
|
supportsNativeIntegration: false,
|
|
76212
76229
|
lifecycle: {
|
|
76213
76230
|
turnCompleted: true,
|
|
@@ -76223,7 +76240,7 @@ var copilotCapabilities;
|
|
|
76223
76240
|
var init_copilot_config = __esm(() => {
|
|
76224
76241
|
copilotCapabilities = {
|
|
76225
76242
|
runtimeKind: "cli",
|
|
76226
|
-
|
|
76243
|
+
supportsDaemonMemoryResume: false,
|
|
76227
76244
|
supportsNativeIntegration: false,
|
|
76228
76245
|
lifecycle: {
|
|
76229
76246
|
turnCompleted: true,
|
|
@@ -76239,7 +76256,7 @@ var cursorSdkCapabilities;
|
|
|
76239
76256
|
var init_cursor_sdk_config = __esm(() => {
|
|
76240
76257
|
cursorSdkCapabilities = {
|
|
76241
76258
|
runtimeKind: "sdk",
|
|
76242
|
-
|
|
76259
|
+
supportsDaemonMemoryResume: true,
|
|
76243
76260
|
supportsNativeIntegration: true,
|
|
76244
76261
|
lifecycle: {
|
|
76245
76262
|
turnCompleted: true,
|
|
@@ -76255,7 +76272,7 @@ var cursorCapabilities;
|
|
|
76255
76272
|
var init_cursor_config = __esm(() => {
|
|
76256
76273
|
cursorCapabilities = {
|
|
76257
76274
|
runtimeKind: "cli",
|
|
76258
|
-
|
|
76275
|
+
supportsDaemonMemoryResume: false,
|
|
76259
76276
|
supportsNativeIntegration: false,
|
|
76260
76277
|
lifecycle: {
|
|
76261
76278
|
turnCompleted: true,
|
|
@@ -76271,7 +76288,7 @@ var opencodeSdkCapabilities;
|
|
|
76271
76288
|
var init_opencode_sdk_config = __esm(() => {
|
|
76272
76289
|
opencodeSdkCapabilities = {
|
|
76273
76290
|
runtimeKind: "sdk",
|
|
76274
|
-
|
|
76291
|
+
supportsDaemonMemoryResume: true,
|
|
76275
76292
|
supportsNativeIntegration: true,
|
|
76276
76293
|
lifecycle: {
|
|
76277
76294
|
turnCompleted: true,
|
|
@@ -76287,7 +76304,7 @@ var opencodeCapabilities;
|
|
|
76287
76304
|
var init_opencode_config = __esm(() => {
|
|
76288
76305
|
opencodeCapabilities = {
|
|
76289
76306
|
runtimeKind: "cli",
|
|
76290
|
-
|
|
76307
|
+
supportsDaemonMemoryResume: false,
|
|
76291
76308
|
supportsNativeIntegration: false,
|
|
76292
76309
|
lifecycle: {
|
|
76293
76310
|
turnCompleted: false,
|
|
@@ -76303,7 +76320,7 @@ var piSdkCapabilities;
|
|
|
76303
76320
|
var init_pi_sdk_config = __esm(() => {
|
|
76304
76321
|
piSdkCapabilities = {
|
|
76305
76322
|
runtimeKind: "sdk",
|
|
76306
|
-
|
|
76323
|
+
supportsDaemonMemoryResume: false,
|
|
76307
76324
|
supportsNativeIntegration: true,
|
|
76308
76325
|
lifecycle: {
|
|
76309
76326
|
turnCompleted: true,
|
|
@@ -76319,7 +76336,7 @@ var piCapabilities;
|
|
|
76319
76336
|
var init_pi_config = __esm(() => {
|
|
76320
76337
|
piCapabilities = {
|
|
76321
76338
|
runtimeKind: "cli",
|
|
76322
|
-
|
|
76339
|
+
supportsDaemonMemoryResume: false,
|
|
76323
76340
|
supportsNativeIntegration: false,
|
|
76324
76341
|
lifecycle: {
|
|
76325
76342
|
turnCompleted: true,
|
|
@@ -76372,43 +76389,6 @@ var init_types = __esm(() => {
|
|
|
76372
76389
|
});
|
|
76373
76390
|
// ../../services/backend/prompts/review-guidelines/index.ts
|
|
76374
76391
|
var init_review_guidelines = () => {};
|
|
76375
|
-
// ../../services/backend/prompts/cli/resume-session/message.ts
|
|
76376
|
-
function composeResumeMessage(params) {
|
|
76377
|
-
const { chatroomId, role, convexUrl, supportsNativeIntegration } = params;
|
|
76378
|
-
const cliEnvPrefix = getCliEnvPrefix(convexUrl);
|
|
76379
|
-
const contextRead = `${cliEnvPrefix}chatroom context read --chatroom-id="${chatroomId}" --role="${role}"`;
|
|
76380
|
-
if (supportsNativeIntegration) {
|
|
76381
|
-
return [
|
|
76382
|
-
"Your previous turn has ended. Your session stays active.",
|
|
76383
|
-
"The next chatroom task will be injected automatically when ready.",
|
|
76384
|
-
"",
|
|
76385
|
-
"If you need context on what you were doing, run:",
|
|
76386
|
-
` ${contextRead}`
|
|
76387
|
-
].join(`
|
|
76388
|
-
`);
|
|
76389
|
-
}
|
|
76390
|
-
const getNextTask2 = getNextTaskCommand({
|
|
76391
|
-
chatroomId,
|
|
76392
|
-
role,
|
|
76393
|
-
cliEnvPrefix
|
|
76394
|
-
});
|
|
76395
|
-
return [
|
|
76396
|
-
"Your previous turn has ended. A pending chatroom task may already be waiting.",
|
|
76397
|
-
"You MUST immediately run this command as a foreground blocking bash tool call (not in background):",
|
|
76398
|
-
` ${getNextTask2}`,
|
|
76399
|
-
"",
|
|
76400
|
-
"Do not reply with text only — run the command first. The harness delivers tasks only while get-next-task blocks.",
|
|
76401
|
-
"",
|
|
76402
|
-
"If you need context on what you were doing, run:",
|
|
76403
|
-
` ${contextRead}`
|
|
76404
|
-
].join(`
|
|
76405
|
-
`);
|
|
76406
|
-
}
|
|
76407
|
-
var init_message = __esm(() => {
|
|
76408
|
-
init_env();
|
|
76409
|
-
init_command();
|
|
76410
|
-
});
|
|
76411
|
-
|
|
76412
76392
|
// ../../services/backend/prompts/generator.ts
|
|
76413
76393
|
function generateHandoffOutput(params) {
|
|
76414
76394
|
const { role, nextRole, chatroomId, convexUrl, supportsNativeIntegration } = params;
|
|
@@ -76431,7 +76411,6 @@ var init_generator = __esm(() => {
|
|
|
76431
76411
|
init_command();
|
|
76432
76412
|
init_reminder();
|
|
76433
76413
|
init_fromContext();
|
|
76434
|
-
init_handoff_templates_preview();
|
|
76435
76414
|
init_classification_guide();
|
|
76436
76415
|
init_commands_reference();
|
|
76437
76416
|
init_current_classification();
|
|
@@ -76447,7 +76426,6 @@ var init_generator = __esm(() => {
|
|
|
76447
76426
|
init_utils3();
|
|
76448
76427
|
init_types();
|
|
76449
76428
|
init_review_guidelines();
|
|
76450
|
-
init_message();
|
|
76451
76429
|
});
|
|
76452
76430
|
|
|
76453
76431
|
// src/commands/handoff/index.ts
|
|
@@ -77439,6 +77417,52 @@ function readFileContent(filePath, optionName) {
|
|
|
77439
77417
|
}
|
|
77440
77418
|
var init_file_content = () => {};
|
|
77441
77419
|
|
|
77420
|
+
// ../../services/backend/prompts/attachments/render-delivery-attachments.ts
|
|
77421
|
+
function renderSnippetAttachment(snippet) {
|
|
77422
|
+
return [
|
|
77423
|
+
` <attachment reference="${snippet.reference}">`,
|
|
77424
|
+
` <snippet file-source="${snippet.fileSource}">`,
|
|
77425
|
+
` <user-selected-content>`,
|
|
77426
|
+
snippet.selectedContent,
|
|
77427
|
+
` </user-selected-content>`,
|
|
77428
|
+
` </snippet>`,
|
|
77429
|
+
` </attachment>`
|
|
77430
|
+
];
|
|
77431
|
+
}
|
|
77432
|
+
function renderBacklogAttachments(items, ctx) {
|
|
77433
|
+
const lines = [];
|
|
77434
|
+
for (const item of items) {
|
|
77435
|
+
lines.push(` <attachment type="backlog-item">`);
|
|
77436
|
+
lines.push(` - [${item.status.toUpperCase()}] ${item.content}`);
|
|
77437
|
+
lines.push(` ID: ${item._id}`);
|
|
77438
|
+
lines.push(` <hint>Work on this item. When done: chatroom backlog mark-for-review --chatroom-id="${ctx.chatroomId}" --role="${ctx.role}" --backlog-item-id=${item._id}</hint>`);
|
|
77439
|
+
lines.push(` </attachment>`);
|
|
77440
|
+
}
|
|
77441
|
+
return lines;
|
|
77442
|
+
}
|
|
77443
|
+
function renderSnippetAttachments(snippets) {
|
|
77444
|
+
const lines = [];
|
|
77445
|
+
for (const snippet of snippets) {
|
|
77446
|
+
lines.push(...renderSnippetAttachment(snippet));
|
|
77447
|
+
}
|
|
77448
|
+
return lines;
|
|
77449
|
+
}
|
|
77450
|
+
function renderDeliveryAttachmentsBlock(input, ctx) {
|
|
77451
|
+
const backlogLines = input.attachedBacklogItems?.length ? DELIVERY_ATTACHMENT_RENDERERS.backlog(input.attachedBacklogItems, ctx) : [];
|
|
77452
|
+
const snippetLines = input.attachedSnippets?.length ? DELIVERY_ATTACHMENT_RENDERERS.snippet(input.attachedSnippets, ctx) : [];
|
|
77453
|
+
if (backlogLines.length === 0 && snippetLines.length === 0)
|
|
77454
|
+
return [];
|
|
77455
|
+
return ["", "<attachments>", ...backlogLines, ...snippetLines, "</attachments>"];
|
|
77456
|
+
}
|
|
77457
|
+
var DELIVERY_ATTACHMENT_RENDERERS;
|
|
77458
|
+
var init_render_delivery_attachments = __esm(() => {
|
|
77459
|
+
DELIVERY_ATTACHMENT_RENDERERS = {
|
|
77460
|
+
backlog: renderBacklogAttachments,
|
|
77461
|
+
snippet: renderSnippetAttachments,
|
|
77462
|
+
message: () => []
|
|
77463
|
+
};
|
|
77464
|
+
});
|
|
77465
|
+
|
|
77442
77466
|
// src/commands/task/read/render.ts
|
|
77443
77467
|
function detectBacklogDivergence(contextContent, attachedIds) {
|
|
77444
77468
|
if (!contextContent || attachedIds.length === 0) {
|
|
@@ -77447,19 +77471,10 @@ function detectBacklogDivergence(contextContent, attachedIds) {
|
|
|
77447
77471
|
return attachedIds.filter((id3) => !contextContent.includes(id3));
|
|
77448
77472
|
}
|
|
77449
77473
|
function renderAttachments(input, chatroomId, role) {
|
|
77450
|
-
|
|
77451
|
-
|
|
77452
|
-
|
|
77453
|
-
|
|
77454
|
-
for (const item of input.attachedBacklogItems) {
|
|
77455
|
-
lines.push(` <attachment type="backlog-item">`);
|
|
77456
|
-
lines.push(` - [${item.status.toUpperCase()}] ${item.content}`);
|
|
77457
|
-
lines.push(` ID: ${item._id}`);
|
|
77458
|
-
lines.push(` <hint>Work on this item. When done: chatroom backlog mark-for-review --chatroom-id="${chatroomId}" --role="${role}" --backlog-item-id=${item._id}</hint>`);
|
|
77459
|
-
lines.push(` </attachment>`);
|
|
77460
|
-
}
|
|
77461
|
-
lines.push("</attachments>");
|
|
77462
|
-
return lines;
|
|
77474
|
+
return renderDeliveryAttachmentsBlock({
|
|
77475
|
+
attachedBacklogItems: input.attachedBacklogItems,
|
|
77476
|
+
attachedSnippets: input.attachedSnippets
|
|
77477
|
+
}, { chatroomId, role, mode: "task-read" });
|
|
77463
77478
|
}
|
|
77464
77479
|
function renderDivergenceWarnings(input) {
|
|
77465
77480
|
const ctx = input.context;
|
|
@@ -77514,6 +77529,9 @@ ${content}`);
|
|
|
77514
77529
|
return lines.join(`
|
|
77515
77530
|
`);
|
|
77516
77531
|
}
|
|
77532
|
+
var init_render = __esm(() => {
|
|
77533
|
+
init_render_delivery_attachments();
|
|
77534
|
+
});
|
|
77517
77535
|
|
|
77518
77536
|
// src/commands/task/read/index.ts
|
|
77519
77537
|
var exports_read = {};
|
|
@@ -77541,6 +77559,18 @@ function validateTaskId(taskId) {
|
|
|
77541
77559
|
}
|
|
77542
77560
|
return exports_Effect.void;
|
|
77543
77561
|
}
|
|
77562
|
+
function buildTaskPromptFromReadResult(result, chatroomId, role) {
|
|
77563
|
+
return renderTaskPrompt({
|
|
77564
|
+
taskId: result.taskId,
|
|
77565
|
+
status: result.status,
|
|
77566
|
+
content: result.content,
|
|
77567
|
+
chatroomId,
|
|
77568
|
+
role,
|
|
77569
|
+
context: result.context && typeof result.context === "object" ? result.context : undefined,
|
|
77570
|
+
attachedBacklogItems: Array.isArray(result.attachedBacklogItems) ? result.attachedBacklogItems : undefined,
|
|
77571
|
+
attachedSnippets: Array.isArray(result.attachedSnippets) ? result.attachedSnippets : undefined
|
|
77572
|
+
});
|
|
77573
|
+
}
|
|
77544
77574
|
function handleTaskReadError(err) {
|
|
77545
77575
|
return exports_Effect.sync(() => {
|
|
77546
77576
|
const handler = taskReadErrorHandlers[err._tag];
|
|
@@ -77573,19 +77603,12 @@ var taskReadEffect = (chatroomId, options) => exports_Effect.gen(function* () {
|
|
|
77573
77603
|
taskId
|
|
77574
77604
|
}).pipe(exports_Effect.mapError((cause3) => ({ _tag: "MutationFailed", cause: cause3 })));
|
|
77575
77605
|
yield* exports_Effect.sync(() => {
|
|
77576
|
-
console.log(
|
|
77577
|
-
taskId: result.taskId,
|
|
77578
|
-
status: result.status,
|
|
77579
|
-
content: result.content,
|
|
77580
|
-
chatroomId,
|
|
77581
|
-
role,
|
|
77582
|
-
context: result.context && typeof result.context === "object" ? result.context : undefined,
|
|
77583
|
-
attachedBacklogItems: Array.isArray(result.attachedBacklogItems) ? result.attachedBacklogItems : undefined
|
|
77584
|
-
}));
|
|
77606
|
+
console.log(buildTaskPromptFromReadResult(result, chatroomId, role));
|
|
77585
77607
|
});
|
|
77586
77608
|
}), taskReadErrorHandlers;
|
|
77587
77609
|
var init_read = __esm(() => {
|
|
77588
77610
|
init_esm();
|
|
77611
|
+
init_render();
|
|
77589
77612
|
init_api3();
|
|
77590
77613
|
init_storage();
|
|
77591
77614
|
init_client2();
|
|
@@ -82717,161 +82740,311 @@ var init_commit_detail_sync = __esm(() => {
|
|
|
82717
82740
|
seenShas = new Map;
|
|
82718
82741
|
});
|
|
82719
82742
|
|
|
82720
|
-
// src/
|
|
82721
|
-
|
|
82722
|
-
const { publisher, machineId } = deps;
|
|
82723
|
-
const { harness, workspace } = input;
|
|
82724
|
-
const [agents, providers] = await Promise.all([
|
|
82725
|
-
harness.listAgents(),
|
|
82726
|
-
harness.listProviders()
|
|
82727
|
-
]);
|
|
82728
|
-
await publisher.publish({
|
|
82729
|
-
machineId,
|
|
82730
|
-
lastSeenAt: Date.now(),
|
|
82731
|
-
workspaces: [
|
|
82732
|
-
{
|
|
82733
|
-
workspaceId: workspace.workspaceId,
|
|
82734
|
-
cwd: workspace.cwd,
|
|
82735
|
-
name: workspace.name,
|
|
82736
|
-
harnesses: [
|
|
82737
|
-
{
|
|
82738
|
-
name: harness.type,
|
|
82739
|
-
displayName: harness.displayName,
|
|
82740
|
-
agents: [...agents],
|
|
82741
|
-
providers: [...providers]
|
|
82742
|
-
}
|
|
82743
|
-
]
|
|
82744
|
-
}
|
|
82745
|
-
]
|
|
82746
|
-
});
|
|
82747
|
-
}
|
|
82743
|
+
// src/infrastructure/harnesses/cursor-sdk/cursor-session.ts
|
|
82744
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
82748
82745
|
|
|
82749
|
-
|
|
82750
|
-
|
|
82751
|
-
|
|
82752
|
-
|
|
82753
|
-
|
|
82754
|
-
|
|
82755
|
-
|
|
82756
|
-
|
|
82746
|
+
class CursorSdkSession {
|
|
82747
|
+
opencodeSessionId;
|
|
82748
|
+
_sessionTitle;
|
|
82749
|
+
get sessionTitle() {
|
|
82750
|
+
return this._sessionTitle;
|
|
82751
|
+
}
|
|
82752
|
+
agent;
|
|
82753
|
+
onClose;
|
|
82754
|
+
listeners = new Set;
|
|
82755
|
+
closed = false;
|
|
82756
|
+
turnCount = 0;
|
|
82757
|
+
constructor(options) {
|
|
82758
|
+
this.agent = options.agent;
|
|
82759
|
+
this.opencodeSessionId = options.opencodeSessionId;
|
|
82760
|
+
this._sessionTitle = options.sessionTitle;
|
|
82761
|
+
this.onClose = options.onClose;
|
|
82762
|
+
}
|
|
82763
|
+
setTitle(title) {
|
|
82764
|
+
this._sessionTitle = title;
|
|
82765
|
+
}
|
|
82766
|
+
async prompt(input) {
|
|
82767
|
+
if (this.closed)
|
|
82768
|
+
throw new Error("Session is closed");
|
|
82769
|
+
const text = input.parts.map((p) => p.text).join(`
|
|
82770
|
+
`);
|
|
82771
|
+
const messageId = randomUUID3();
|
|
82772
|
+
const isFirstTurn = this.turnCount === 0;
|
|
82773
|
+
this.turnCount += 1;
|
|
82774
|
+
const modelId = input.model ? resolveModelFromPrompt(input.model.providerID, input.model.modelID) : undefined;
|
|
82775
|
+
const run3 = await withTimeout(this.agent.send(text, {
|
|
82776
|
+
local: { force: isFirstTurn },
|
|
82777
|
+
idempotencyKey: randomUUID3(),
|
|
82778
|
+
...modelId ? { model: { id: modelId } } : {}
|
|
82779
|
+
}), SEND_TIMEOUT_MS2, "agent.send");
|
|
82780
|
+
for await (const message of run3.stream()) {
|
|
82781
|
+
if (this.closed)
|
|
82782
|
+
break;
|
|
82783
|
+
this.emitFromSdkMessage(message, messageId);
|
|
82784
|
+
}
|
|
82785
|
+
const result = await withTimeout(run3.wait(), RUN_WAIT_TIMEOUT_MS2, "run.wait");
|
|
82786
|
+
if (result.status === "error") {
|
|
82787
|
+
const detail = typeof result.result === "string" && result.result.trim().length > 0 ? result.result.trim() : `run ${result.id} failed`;
|
|
82788
|
+
throw new Error(detail);
|
|
82789
|
+
}
|
|
82790
|
+
this.emit({ type: "session.idle", payload: {}, timestamp: Date.now() });
|
|
82791
|
+
}
|
|
82792
|
+
onEvent(listener) {
|
|
82793
|
+
this.listeners.add(listener);
|
|
82794
|
+
return () => {
|
|
82795
|
+
this.listeners.delete(listener);
|
|
82796
|
+
};
|
|
82797
|
+
}
|
|
82798
|
+
async close() {
|
|
82799
|
+
if (this.closed)
|
|
82757
82800
|
return;
|
|
82801
|
+
this.closed = true;
|
|
82802
|
+
try {
|
|
82803
|
+
this.agent.close();
|
|
82804
|
+
} catch {}
|
|
82805
|
+
this.onClose?.(this.opencodeSessionId);
|
|
82806
|
+
this.listeners.clear();
|
|
82807
|
+
}
|
|
82808
|
+
emit(event) {
|
|
82809
|
+
for (const listener of this.listeners) {
|
|
82810
|
+
listener(event);
|
|
82758
82811
|
}
|
|
82759
|
-
|
|
82760
|
-
|
|
82761
|
-
|
|
82762
|
-
|
|
82763
|
-
|
|
82764
|
-
|
|
82812
|
+
}
|
|
82813
|
+
emitDelta(messageId, delta, partType) {
|
|
82814
|
+
if (!delta)
|
|
82815
|
+
return;
|
|
82816
|
+
this.emit({
|
|
82817
|
+
type: "message.part.delta",
|
|
82818
|
+
payload: { messageID: messageId, delta, partType },
|
|
82819
|
+
timestamp: Date.now()
|
|
82765
82820
|
});
|
|
82766
|
-
};
|
|
82767
|
-
const unsub = wsClient2.onUpdate(api.daemon.directHarness.commands.listPendingCommands, { sessionId: session2.sessionId, machineId: session2.machineId }, () => runDrain(), (err) => {
|
|
82768
|
-
console.warn("[direct-harness] Command subscription error:", err instanceof Error ? err.message : String(err));
|
|
82769
|
-
});
|
|
82770
|
-
return { stop: unsub };
|
|
82771
|
-
}
|
|
82772
|
-
async function dispatchPendingCommand(session2, deps, cmd) {
|
|
82773
|
-
switch (cmd.type) {
|
|
82774
|
-
case "refreshCapabilities":
|
|
82775
|
-
await handleRefreshCapabilities(session2, deps, cmd);
|
|
82776
|
-
break;
|
|
82777
|
-
case "refreshSessionTitle":
|
|
82778
|
-
await handleRefreshSessionTitle(session2, deps, cmd);
|
|
82779
|
-
break;
|
|
82780
|
-
default:
|
|
82781
|
-
await markFailed(session2, cmd._id, `Unknown command type: ${cmd.type}`);
|
|
82782
82821
|
}
|
|
82783
|
-
|
|
82784
|
-
|
|
82785
|
-
|
|
82786
|
-
|
|
82787
|
-
|
|
82788
|
-
|
|
82822
|
+
emitFromSdkMessage(message, messageId) {
|
|
82823
|
+
switch (message.type) {
|
|
82824
|
+
case "assistant":
|
|
82825
|
+
for (const block of message.message.content) {
|
|
82826
|
+
if (block.type === "text" && block.text) {
|
|
82827
|
+
this.emitDelta(messageId, block.text, "text");
|
|
82828
|
+
}
|
|
82829
|
+
}
|
|
82830
|
+
break;
|
|
82831
|
+
case "thinking":
|
|
82832
|
+
if (message.text) {
|
|
82833
|
+
this.emitDelta(messageId, message.text, "reasoning");
|
|
82834
|
+
}
|
|
82835
|
+
break;
|
|
82836
|
+
default:
|
|
82837
|
+
break;
|
|
82838
|
+
}
|
|
82789
82839
|
}
|
|
82790
|
-
await dispatchPendingCommand(session2, deps, cmd);
|
|
82791
82840
|
}
|
|
82792
|
-
|
|
82793
|
-
|
|
82794
|
-
|
|
82795
|
-
|
|
82796
|
-
|
|
82797
|
-
|
|
82798
|
-
|
|
82799
|
-
|
|
82800
|
-
|
|
82801
|
-
|
|
82802
|
-
|
|
82803
|
-
|
|
82804
|
-
|
|
82805
|
-
|
|
82806
|
-
|
|
82807
|
-
|
|
82841
|
+
function resolveModelFromPrompt(providerID, modelID) {
|
|
82842
|
+
if (providerID === "cursor")
|
|
82843
|
+
return resolveCursorSdkModel(modelID);
|
|
82844
|
+
return resolveCursorSdkModel(`${providerID}/${modelID}`);
|
|
82845
|
+
}
|
|
82846
|
+
var SEND_TIMEOUT_MS2 = 60000, RUN_WAIT_TIMEOUT_MS2 = 3600000;
|
|
82847
|
+
var init_cursor_session = () => {};
|
|
82848
|
+
|
|
82849
|
+
// src/infrastructure/harnesses/cursor-sdk/cursor-harness.ts
|
|
82850
|
+
async function loadSdk3() {
|
|
82851
|
+
if (_sdkCache3)
|
|
82852
|
+
return _sdkCache3;
|
|
82853
|
+
if (_sdkLoadError3)
|
|
82854
|
+
throw _sdkLoadError3;
|
|
82855
|
+
try {
|
|
82856
|
+
_sdkCache3 = await importBundledCursorSdk();
|
|
82857
|
+
return _sdkCache3;
|
|
82858
|
+
} catch (err) {
|
|
82859
|
+
_sdkLoadError3 = err;
|
|
82860
|
+
throw err;
|
|
82808
82861
|
}
|
|
82809
82862
|
}
|
|
82810
|
-
|
|
82811
|
-
|
|
82812
|
-
|
|
82813
|
-
|
|
82814
|
-
|
|
82815
|
-
|
|
82816
|
-
|
|
82817
|
-
|
|
82818
|
-
|
|
82819
|
-
|
|
82863
|
+
|
|
82864
|
+
class CursorSdkHarness {
|
|
82865
|
+
type = "cursor-sdk";
|
|
82866
|
+
displayName = "Cursor (SDK)";
|
|
82867
|
+
cwd;
|
|
82868
|
+
closed = false;
|
|
82869
|
+
sessions = new Map;
|
|
82870
|
+
constructor(cwd) {
|
|
82871
|
+
this.cwd = cwd;
|
|
82872
|
+
}
|
|
82873
|
+
async models() {
|
|
82874
|
+
const providers = await this.listProviders();
|
|
82875
|
+
const models = [];
|
|
82876
|
+
for (const provider of providers) {
|
|
82877
|
+
for (const model of provider.models) {
|
|
82878
|
+
models.push({
|
|
82879
|
+
id: `${provider.providerID}/${model.modelID}`,
|
|
82880
|
+
name: model.name,
|
|
82881
|
+
provider: provider.name
|
|
82882
|
+
});
|
|
82883
|
+
}
|
|
82820
82884
|
}
|
|
82821
|
-
|
|
82822
|
-
await session2.backend.mutation(api.daemon.directHarness.commands.updateCommandStatus, {
|
|
82823
|
-
sessionId: session2.sessionId,
|
|
82824
|
-
commandId: cmd._id,
|
|
82825
|
-
status: "done"
|
|
82826
|
-
});
|
|
82827
|
-
console.log(`[direct-harness] Capabilities refreshed for workspace=${cmd.workspaceId}`);
|
|
82828
|
-
}
|
|
82829
|
-
async function handleRefreshSessionTitle(session2, deps, cmd) {
|
|
82830
|
-
const { harnessSessionId } = cmd.refreshSessionTitle ?? {};
|
|
82831
|
-
if (!harnessSessionId) {
|
|
82832
|
-
await markFailed(session2, cmd._id, "refreshSessionTitle: missing harnessSessionId");
|
|
82833
|
-
return;
|
|
82885
|
+
return models;
|
|
82834
82886
|
}
|
|
82835
|
-
|
|
82836
|
-
|
|
82837
|
-
}
|
|
82838
|
-
|
|
82839
|
-
|
|
82840
|
-
|
|
82841
|
-
|
|
82842
|
-
|
|
82887
|
+
async listAgents() {
|
|
82888
|
+
return [{ name: "builder", mode: "primary" }];
|
|
82889
|
+
}
|
|
82890
|
+
async listProviders() {
|
|
82891
|
+
const apiKey = process.env.CURSOR_API_KEY?.trim();
|
|
82892
|
+
if (!apiKey)
|
|
82893
|
+
return [];
|
|
82894
|
+
const { Cursor } = await loadSdk3();
|
|
82895
|
+
const listed = await withTimeout(Cursor.models.list({ apiKey }), MODELS_LIST_TIMEOUT_MS2, "Cursor.models.list");
|
|
82896
|
+
const modelIds = normalizeCursorSdkListedModels(listed.map((m) => m.id).filter((id3) => id3.length > 0));
|
|
82897
|
+
return [
|
|
82898
|
+
{
|
|
82899
|
+
providerID: "cursor",
|
|
82900
|
+
name: "Cursor",
|
|
82901
|
+
models: modelIds.map((modelID) => ({ modelID, name: modelID }))
|
|
82902
|
+
}
|
|
82903
|
+
];
|
|
82904
|
+
}
|
|
82905
|
+
async newSession(config3) {
|
|
82906
|
+
if (this.closed)
|
|
82907
|
+
throw new Error("Harness is closed");
|
|
82908
|
+
const apiKey = process.env.CURSOR_API_KEY?.trim();
|
|
82909
|
+
if (!apiKey)
|
|
82910
|
+
throw new Error("CURSOR_API_KEY is not set");
|
|
82911
|
+
const modelId = resolveCursorSdkModel(config3.model ?? DEFAULT_MODEL2);
|
|
82912
|
+
const { Agent } = await loadSdk3();
|
|
82913
|
+
const agent = await withTimeout(Agent.create({
|
|
82914
|
+
apiKey,
|
|
82915
|
+
model: { id: modelId },
|
|
82916
|
+
local: { cwd: this.cwd, settingSources: [] }
|
|
82917
|
+
}), AGENT_CREATE_TIMEOUT_MS2, "Agent.create");
|
|
82918
|
+
const session2 = new CursorSdkSession({
|
|
82919
|
+
agent,
|
|
82920
|
+
opencodeSessionId: agent.agentId,
|
|
82921
|
+
sessionTitle: config3.title ?? "",
|
|
82922
|
+
onClose: (id3) => this.sessions.delete(id3)
|
|
82843
82923
|
});
|
|
82844
|
-
|
|
82924
|
+
this.sessions.set(agent.agentId, session2);
|
|
82925
|
+
return session2;
|
|
82845
82926
|
}
|
|
82846
|
-
|
|
82847
|
-
|
|
82848
|
-
|
|
82849
|
-
|
|
82850
|
-
|
|
82851
|
-
|
|
82852
|
-
|
|
82927
|
+
async resumeSession(sessionId, _options) {
|
|
82928
|
+
if (this.closed)
|
|
82929
|
+
throw new Error("Harness is closed");
|
|
82930
|
+
const existing = this.sessions.get(sessionId);
|
|
82931
|
+
if (existing)
|
|
82932
|
+
return existing;
|
|
82933
|
+
const apiKey = process.env.CURSOR_API_KEY?.trim();
|
|
82934
|
+
if (!apiKey)
|
|
82935
|
+
throw new Error("CURSOR_API_KEY is not set");
|
|
82936
|
+
const { Agent } = await loadSdk3();
|
|
82937
|
+
const agent = await withTimeout(Agent.resume(sessionId, {
|
|
82938
|
+
apiKey,
|
|
82939
|
+
model: { id: DEFAULT_MODEL2 },
|
|
82940
|
+
local: { cwd: this.cwd, settingSources: [] }
|
|
82941
|
+
}), AGENT_CREATE_TIMEOUT_MS2, "Agent.resume");
|
|
82942
|
+
const session2 = new CursorSdkSession({
|
|
82943
|
+
agent,
|
|
82944
|
+
opencodeSessionId: agent.agentId,
|
|
82945
|
+
sessionTitle: "",
|
|
82946
|
+
onClose: (id3) => this.sessions.delete(id3)
|
|
82853
82947
|
});
|
|
82854
|
-
|
|
82948
|
+
this.sessions.set(agent.agentId, session2);
|
|
82949
|
+
return session2;
|
|
82950
|
+
}
|
|
82951
|
+
async fetchSessionTitle(_opencodeSessionId) {
|
|
82952
|
+
return;
|
|
82953
|
+
}
|
|
82954
|
+
isAlive() {
|
|
82955
|
+
return !this.closed;
|
|
82956
|
+
}
|
|
82957
|
+
async close() {
|
|
82958
|
+
if (this.closed)
|
|
82959
|
+
return;
|
|
82960
|
+
this.closed = true;
|
|
82961
|
+
const closing = [...this.sessions.values()].map((s) => s.close().catch(() => {}));
|
|
82962
|
+
await Promise.all(closing);
|
|
82963
|
+
this.sessions.clear();
|
|
82855
82964
|
}
|
|
82856
|
-
await session2.backend.mutation(api.daemon.directHarness.commands.updateCommandStatus, {
|
|
82857
|
-
sessionId: session2.sessionId,
|
|
82858
|
-
commandId: cmd._id,
|
|
82859
|
-
status: "done"
|
|
82860
|
-
});
|
|
82861
82965
|
}
|
|
82862
|
-
|
|
82863
|
-
|
|
82864
|
-
|
|
82865
|
-
|
|
82866
|
-
|
|
82867
|
-
|
|
82868
|
-
|
|
82966
|
+
var DEFAULT_MODEL2 = "composer-2.5", MODELS_LIST_TIMEOUT_MS2 = 60000, AGENT_CREATE_TIMEOUT_MS2 = 60000, _sdkCache3, _sdkLoadError3, startCursorSdkHarness = async (config3) => {
|
|
82967
|
+
try {
|
|
82968
|
+
await loadSdk3();
|
|
82969
|
+
} catch (err) {
|
|
82970
|
+
throw new Error(`cursor-sdk unavailable: ${formatCursorSdkLoadError(err)}`);
|
|
82971
|
+
}
|
|
82972
|
+
if (!process.env.CURSOR_API_KEY?.trim()) {
|
|
82973
|
+
throw new Error("CURSOR_API_KEY is not set");
|
|
82974
|
+
}
|
|
82975
|
+
return new CursorSdkHarness(config3.workingDir);
|
|
82976
|
+
};
|
|
82977
|
+
var init_cursor_harness = __esm(() => {
|
|
82978
|
+
init_cursor_session();
|
|
82979
|
+
init_cursor_sdk_package();
|
|
82980
|
+
});
|
|
82981
|
+
|
|
82982
|
+
// src/infrastructure/harnesses/shared-chunk-extractor.ts
|
|
82983
|
+
function createStandardSdkChunkExtractor() {
|
|
82984
|
+
return function extract(event) {
|
|
82985
|
+
if (event.type !== "message.part.delta")
|
|
82986
|
+
return null;
|
|
82987
|
+
const payload = event.payload;
|
|
82988
|
+
const delta = payload?.delta;
|
|
82989
|
+
if (!delta || delta.length === 0)
|
|
82990
|
+
return null;
|
|
82991
|
+
const messageId = payload?.messageID;
|
|
82992
|
+
if (!messageId)
|
|
82993
|
+
return null;
|
|
82994
|
+
return {
|
|
82995
|
+
content: delta,
|
|
82996
|
+
messageId,
|
|
82997
|
+
partType: payload?.partType ?? "text"
|
|
82998
|
+
};
|
|
82999
|
+
};
|
|
82869
83000
|
}
|
|
82870
|
-
|
|
82871
|
-
|
|
82872
|
-
|
|
83001
|
+
|
|
83002
|
+
// src/infrastructure/harnesses/cursor-sdk/event-extractor.ts
|
|
83003
|
+
function createCursorSdkChunkExtractor() {
|
|
83004
|
+
return createStandardSdkChunkExtractor();
|
|
83005
|
+
}
|
|
83006
|
+
var init_event_extractor = () => {};
|
|
83007
|
+
|
|
83008
|
+
// src/infrastructure/harnesses/cursor-sdk/index.ts
|
|
83009
|
+
var init_cursor_sdk2 = __esm(() => {
|
|
83010
|
+
init_cursor_harness();
|
|
83011
|
+
init_cursor_session();
|
|
83012
|
+
init_event_extractor();
|
|
82873
83013
|
});
|
|
82874
83014
|
|
|
83015
|
+
// src/infrastructure/harnesses/opencode-sdk/event-extractor.ts
|
|
83016
|
+
function createOpencodeSdkChunkExtractor() {
|
|
83017
|
+
const partMap = new Map;
|
|
83018
|
+
return function extract(event) {
|
|
83019
|
+
if (event.type === "message.part.updated") {
|
|
83020
|
+
const payload = event.payload;
|
|
83021
|
+
const part = payload?.part;
|
|
83022
|
+
if (part?.id && part?.messageID) {
|
|
83023
|
+
const partType = part.type === "reasoning" ? "reasoning" : "text";
|
|
83024
|
+
partMap.set(part.id, { messageId: part.messageID, partType });
|
|
83025
|
+
const delta = payload?.delta;
|
|
83026
|
+
if (delta && delta.length > 0) {
|
|
83027
|
+
return { content: delta, messageId: part.messageID, partType };
|
|
83028
|
+
}
|
|
83029
|
+
}
|
|
83030
|
+
return null;
|
|
83031
|
+
}
|
|
83032
|
+
if (event.type === "message.part.delta") {
|
|
83033
|
+
const payload = event.payload;
|
|
83034
|
+
const delta = payload?.delta;
|
|
83035
|
+
if (!delta || delta.length === 0)
|
|
83036
|
+
return null;
|
|
83037
|
+
const messageId = payload?.messageID;
|
|
83038
|
+
if (!messageId)
|
|
83039
|
+
return null;
|
|
83040
|
+
const partID = payload?.partID;
|
|
83041
|
+
const partType = (partID ? partMap.get(partID)?.partType : undefined) ?? "text";
|
|
83042
|
+
return { content: delta, messageId, partType };
|
|
83043
|
+
}
|
|
83044
|
+
return null;
|
|
83045
|
+
};
|
|
83046
|
+
}
|
|
83047
|
+
|
|
82875
83048
|
// src/infrastructure/harnesses/opencode-sdk/sse-event-buffer.ts
|
|
82876
83049
|
var SseEventBuffer;
|
|
82877
83050
|
var init_sse_event_buffer = __esm(() => {
|
|
@@ -83369,44 +83542,560 @@ var init_opencode_harness = __esm(() => {
|
|
|
83369
83542
|
init_spawn_env();
|
|
83370
83543
|
});
|
|
83371
83544
|
|
|
83372
|
-
// src/infrastructure/harnesses/
|
|
83373
|
-
|
|
83374
|
-
|
|
83375
|
-
|
|
83376
|
-
|
|
83377
|
-
|
|
83378
|
-
|
|
83379
|
-
|
|
83380
|
-
|
|
83381
|
-
|
|
83382
|
-
|
|
83383
|
-
|
|
83384
|
-
|
|
83385
|
-
|
|
83386
|
-
|
|
83387
|
-
|
|
83545
|
+
// src/infrastructure/harnesses/pi-sdk/pi-session.ts
|
|
83546
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
83547
|
+
|
|
83548
|
+
class PiSdkSession {
|
|
83549
|
+
opencodeSessionId;
|
|
83550
|
+
_sessionTitle;
|
|
83551
|
+
get sessionTitle() {
|
|
83552
|
+
return this._sessionTitle;
|
|
83553
|
+
}
|
|
83554
|
+
session;
|
|
83555
|
+
onClose;
|
|
83556
|
+
listeners = new Set;
|
|
83557
|
+
closed = false;
|
|
83558
|
+
unsubscribe;
|
|
83559
|
+
constructor(options) {
|
|
83560
|
+
this.session = options.session;
|
|
83561
|
+
this.opencodeSessionId = options.opencodeSessionId;
|
|
83562
|
+
this._sessionTitle = options.sessionTitle;
|
|
83563
|
+
this.onClose = options.onClose;
|
|
83564
|
+
}
|
|
83565
|
+
setTitle(title) {
|
|
83566
|
+
this._sessionTitle = title;
|
|
83567
|
+
}
|
|
83568
|
+
async prompt(input) {
|
|
83569
|
+
if (this.closed)
|
|
83570
|
+
throw new Error("Session is closed");
|
|
83571
|
+
const text = input.parts.map((p) => p.text).join(`
|
|
83572
|
+
`);
|
|
83573
|
+
const messageId = randomUUID4();
|
|
83574
|
+
const onSessionEvent = (event) => {
|
|
83575
|
+
if (this.closed)
|
|
83576
|
+
return;
|
|
83577
|
+
this.emitFromPiEvent(event, messageId);
|
|
83578
|
+
};
|
|
83579
|
+
this.unsubscribe?.();
|
|
83580
|
+
this.unsubscribe = this.session.subscribe(onSessionEvent);
|
|
83581
|
+
await withTimeout(this.session.prompt(text), PROMPT_TIMEOUT_MS2, "session.prompt");
|
|
83582
|
+
this.emit({ type: "session.idle", payload: {}, timestamp: Date.now() });
|
|
83583
|
+
}
|
|
83584
|
+
onEvent(listener) {
|
|
83585
|
+
this.listeners.add(listener);
|
|
83586
|
+
return () => {
|
|
83587
|
+
this.listeners.delete(listener);
|
|
83588
|
+
};
|
|
83589
|
+
}
|
|
83590
|
+
async close() {
|
|
83591
|
+
if (this.closed)
|
|
83592
|
+
return;
|
|
83593
|
+
this.closed = true;
|
|
83594
|
+
this.unsubscribe?.();
|
|
83595
|
+
try {
|
|
83596
|
+
await this.session.abort();
|
|
83597
|
+
} catch {}
|
|
83598
|
+
try {
|
|
83599
|
+
this.session.dispose();
|
|
83600
|
+
} catch {}
|
|
83601
|
+
this.onClose?.(this.opencodeSessionId);
|
|
83602
|
+
this.listeners.clear();
|
|
83603
|
+
}
|
|
83604
|
+
emit(event) {
|
|
83605
|
+
for (const listener of this.listeners) {
|
|
83606
|
+
listener(event);
|
|
83388
83607
|
}
|
|
83389
|
-
|
|
83390
|
-
|
|
83391
|
-
|
|
83392
|
-
|
|
83393
|
-
|
|
83394
|
-
|
|
83395
|
-
|
|
83396
|
-
|
|
83397
|
-
|
|
83398
|
-
|
|
83399
|
-
|
|
83608
|
+
}
|
|
83609
|
+
emitDelta(messageId, delta, partType) {
|
|
83610
|
+
if (!delta)
|
|
83611
|
+
return;
|
|
83612
|
+
this.emit({
|
|
83613
|
+
type: "message.part.delta",
|
|
83614
|
+
payload: { messageID: messageId, delta, partType },
|
|
83615
|
+
timestamp: Date.now()
|
|
83616
|
+
});
|
|
83617
|
+
}
|
|
83618
|
+
emitFromPiEvent(event, messageId) {
|
|
83619
|
+
if (event.type !== "message_update")
|
|
83620
|
+
return;
|
|
83621
|
+
const assistantEvent = event.assistantMessageEvent;
|
|
83622
|
+
if (assistantEvent.type === "text_delta") {
|
|
83623
|
+
this.emitDelta(messageId, assistantEvent.delta, "text");
|
|
83624
|
+
} else if (assistantEvent.type === "thinking_delta") {
|
|
83625
|
+
this.emitDelta(messageId, assistantEvent.delta, "reasoning");
|
|
83400
83626
|
}
|
|
83401
|
-
|
|
83402
|
-
|
|
83627
|
+
}
|
|
83628
|
+
}
|
|
83629
|
+
var PROMPT_TIMEOUT_MS2 = 3600000;
|
|
83630
|
+
var init_pi_session = () => {};
|
|
83631
|
+
|
|
83632
|
+
// src/infrastructure/harnesses/pi-sdk/pi-harness.ts
|
|
83633
|
+
async function loadSdk4() {
|
|
83634
|
+
if (_sdkCache4)
|
|
83635
|
+
return _sdkCache4;
|
|
83636
|
+
if (_sdkLoadError4)
|
|
83637
|
+
throw _sdkLoadError4;
|
|
83638
|
+
try {
|
|
83639
|
+
_sdkCache4 = await importBundledPiSdk();
|
|
83640
|
+
return _sdkCache4;
|
|
83641
|
+
} catch (err) {
|
|
83642
|
+
_sdkLoadError4 = err;
|
|
83643
|
+
throw err;
|
|
83644
|
+
}
|
|
83645
|
+
}
|
|
83646
|
+
function resolveModel2(modelRegistry, model) {
|
|
83647
|
+
if (model) {
|
|
83648
|
+
const slash = model.indexOf("/");
|
|
83649
|
+
if (slash === -1) {
|
|
83650
|
+
return modelRegistry.getAll().find((entry) => entry.id === model);
|
|
83651
|
+
}
|
|
83652
|
+
const provider = model.slice(0, slash);
|
|
83653
|
+
const modelId = model.slice(slash + 1);
|
|
83654
|
+
return modelRegistry.find(provider, modelId);
|
|
83655
|
+
}
|
|
83656
|
+
return modelRegistry.getAvailable()[0];
|
|
83403
83657
|
}
|
|
83404
83658
|
|
|
83405
|
-
|
|
83406
|
-
|
|
83659
|
+
class PiSdkHarness {
|
|
83660
|
+
type = "pi-sdk";
|
|
83661
|
+
displayName = "Pi (SDK)";
|
|
83662
|
+
cwd;
|
|
83663
|
+
closed = false;
|
|
83664
|
+
sessions = new Map;
|
|
83665
|
+
modelRegistry;
|
|
83666
|
+
authStorage;
|
|
83667
|
+
constructor(cwd, modelRegistry, authStorage) {
|
|
83668
|
+
this.cwd = cwd;
|
|
83669
|
+
this.modelRegistry = modelRegistry;
|
|
83670
|
+
this.authStorage = authStorage;
|
|
83671
|
+
}
|
|
83672
|
+
async models() {
|
|
83673
|
+
return this.modelRegistry.getAvailable().map((entry) => ({
|
|
83674
|
+
id: `${entry.provider}/${entry.id}`,
|
|
83675
|
+
name: entry.id,
|
|
83676
|
+
provider: entry.provider
|
|
83677
|
+
}));
|
|
83678
|
+
}
|
|
83679
|
+
async listAgents() {
|
|
83680
|
+
return [{ name: "builder", mode: "primary" }];
|
|
83681
|
+
}
|
|
83682
|
+
async listProviders() {
|
|
83683
|
+
const byProvider = new Map;
|
|
83684
|
+
for (const entry of this.modelRegistry.getAvailable()) {
|
|
83685
|
+
const models = byProvider.get(entry.provider) ?? [];
|
|
83686
|
+
models.push({ modelID: entry.id, name: entry.id });
|
|
83687
|
+
byProvider.set(entry.provider, models);
|
|
83688
|
+
}
|
|
83689
|
+
return [...byProvider.entries()].map(([providerID, models]) => ({
|
|
83690
|
+
providerID,
|
|
83691
|
+
name: providerID,
|
|
83692
|
+
models
|
|
83693
|
+
}));
|
|
83694
|
+
}
|
|
83695
|
+
async newSession(config3) {
|
|
83696
|
+
if (this.closed)
|
|
83697
|
+
throw new Error("Harness is closed");
|
|
83698
|
+
const session2 = await this.createAgentSession(config3.systemPrompt ?? "", config3.model);
|
|
83699
|
+
const piSession = new PiSdkSession({
|
|
83700
|
+
session: session2,
|
|
83701
|
+
opencodeSessionId: session2.sessionId,
|
|
83702
|
+
sessionTitle: config3.title ?? "",
|
|
83703
|
+
onClose: (id3) => this.sessions.delete(id3)
|
|
83704
|
+
});
|
|
83705
|
+
this.sessions.set(session2.sessionId, piSession);
|
|
83706
|
+
return piSession;
|
|
83707
|
+
}
|
|
83708
|
+
async resumeSession(sessionId, _options) {
|
|
83709
|
+
if (this.closed)
|
|
83710
|
+
throw new Error("Harness is closed");
|
|
83711
|
+
const existing = this.sessions.get(sessionId);
|
|
83712
|
+
if (existing)
|
|
83713
|
+
return existing;
|
|
83714
|
+
const { createAgentSession, DefaultResourceLoader, getAgentDir, SessionManager } = await loadSdk4();
|
|
83715
|
+
const sessions = await SessionManager.list(this.cwd, getPiSessionDir(this.cwd));
|
|
83716
|
+
const match17 = sessions.find((s) => s.id === sessionId);
|
|
83717
|
+
if (!match17) {
|
|
83718
|
+
throw new Error(`Session ${sessionId} not found on the harness`);
|
|
83719
|
+
}
|
|
83720
|
+
const resourceLoader = new DefaultResourceLoader({
|
|
83721
|
+
cwd: this.cwd,
|
|
83722
|
+
agentDir: getAgentDir(),
|
|
83723
|
+
systemPromptOverride: () => ""
|
|
83724
|
+
});
|
|
83725
|
+
await resourceLoader.reload();
|
|
83726
|
+
const resolvedModel = resolveModel2(this.modelRegistry);
|
|
83727
|
+
if (!resolvedModel) {
|
|
83728
|
+
throw new Error("No Pi model available");
|
|
83729
|
+
}
|
|
83730
|
+
const { session: session2 } = await withTimeout(createAgentSession({
|
|
83731
|
+
cwd: this.cwd,
|
|
83732
|
+
model: resolvedModel,
|
|
83733
|
+
sessionManager: SessionManager.open(match17.path, getPiSessionDir(this.cwd)),
|
|
83734
|
+
authStorage: this.authStorage,
|
|
83735
|
+
modelRegistry: this.modelRegistry,
|
|
83736
|
+
resourceLoader
|
|
83737
|
+
}), SESSION_CREATE_TIMEOUT_MS3, "createAgentSession");
|
|
83738
|
+
const piSession = new PiSdkSession({
|
|
83739
|
+
session: session2,
|
|
83740
|
+
opencodeSessionId: session2.sessionId,
|
|
83741
|
+
sessionTitle: match17.name ?? "",
|
|
83742
|
+
onClose: (id3) => this.sessions.delete(id3)
|
|
83743
|
+
});
|
|
83744
|
+
this.sessions.set(session2.sessionId, piSession);
|
|
83745
|
+
return piSession;
|
|
83746
|
+
}
|
|
83747
|
+
async fetchSessionTitle(_opencodeSessionId) {
|
|
83748
|
+
return;
|
|
83749
|
+
}
|
|
83750
|
+
isAlive() {
|
|
83751
|
+
return !this.closed;
|
|
83752
|
+
}
|
|
83753
|
+
async close() {
|
|
83754
|
+
if (this.closed)
|
|
83755
|
+
return;
|
|
83756
|
+
this.closed = true;
|
|
83757
|
+
const closing = [...this.sessions.values()].map((s) => s.close().catch(() => {}));
|
|
83758
|
+
await Promise.all(closing);
|
|
83759
|
+
this.sessions.clear();
|
|
83760
|
+
}
|
|
83761
|
+
async createAgentSession(systemPrompt, model) {
|
|
83762
|
+
const { createAgentSession, DefaultResourceLoader, getAgentDir, SessionManager } = await loadSdk4();
|
|
83763
|
+
const resolvedModel = resolveModel2(this.modelRegistry, model ?? DEFAULT_MODEL3);
|
|
83764
|
+
if (!resolvedModel) {
|
|
83765
|
+
throw new Error("No Pi model available — configure provider credentials in ~/.pi/agent/auth.json");
|
|
83766
|
+
}
|
|
83767
|
+
const resourceLoader = new DefaultResourceLoader({
|
|
83768
|
+
cwd: this.cwd,
|
|
83769
|
+
agentDir: getAgentDir(),
|
|
83770
|
+
systemPromptOverride: () => systemPrompt
|
|
83771
|
+
});
|
|
83772
|
+
await resourceLoader.reload();
|
|
83773
|
+
const { session: session2 } = await withTimeout(createAgentSession({
|
|
83774
|
+
cwd: this.cwd,
|
|
83775
|
+
model: resolvedModel,
|
|
83776
|
+
sessionManager: SessionManager.create(getPiSessionDir(this.cwd)),
|
|
83777
|
+
authStorage: this.authStorage,
|
|
83778
|
+
modelRegistry: this.modelRegistry,
|
|
83779
|
+
resourceLoader
|
|
83780
|
+
}), SESSION_CREATE_TIMEOUT_MS3, "createAgentSession");
|
|
83781
|
+
return session2;
|
|
83782
|
+
}
|
|
83783
|
+
}
|
|
83784
|
+
var SESSION_CREATE_TIMEOUT_MS3 = 60000, DEFAULT_MODEL3 = "opencode/big-pickle", _sdkCache4, _sdkLoadError4, startPiSdkHarness = async (config3) => {
|
|
83785
|
+
try {
|
|
83786
|
+
const { AuthStorage, ModelRegistry } = await loadSdk4();
|
|
83787
|
+
const authStorage = AuthStorage.create();
|
|
83788
|
+
const modelRegistry = ModelRegistry.create(authStorage);
|
|
83789
|
+
if (modelRegistry.getAvailable().length === 0) {
|
|
83790
|
+
throw new Error("No Pi models available");
|
|
83791
|
+
}
|
|
83792
|
+
return new PiSdkHarness(config3.workingDir, modelRegistry, authStorage);
|
|
83793
|
+
} catch (err) {
|
|
83794
|
+
throw new Error(`pi-sdk unavailable: ${formatPiSdkLoadError(err)}`);
|
|
83795
|
+
}
|
|
83796
|
+
};
|
|
83797
|
+
var init_pi_harness = __esm(() => {
|
|
83798
|
+
init_pi_session();
|
|
83799
|
+
init_pi_agent_service();
|
|
83800
|
+
init_pi_sdk_package();
|
|
83801
|
+
});
|
|
83802
|
+
|
|
83803
|
+
// src/infrastructure/harnesses/pi-sdk/event-extractor.ts
|
|
83804
|
+
function createPiSdkChunkExtractor() {
|
|
83805
|
+
return createStandardSdkChunkExtractor();
|
|
83806
|
+
}
|
|
83807
|
+
var init_event_extractor2 = () => {};
|
|
83808
|
+
|
|
83809
|
+
// src/infrastructure/harnesses/pi-sdk/index.ts
|
|
83810
|
+
var init_pi_sdk2 = __esm(() => {
|
|
83811
|
+
init_pi_harness();
|
|
83812
|
+
init_pi_session();
|
|
83813
|
+
init_event_extractor2();
|
|
83814
|
+
});
|
|
83815
|
+
|
|
83816
|
+
// src/infrastructure/harnesses/registry.ts
|
|
83817
|
+
import { execSync as execSync2 } from "node:child_process";
|
|
83818
|
+
async function startBoundHarness(config3) {
|
|
83819
|
+
switch (config3.harnessName) {
|
|
83820
|
+
case "opencode-sdk":
|
|
83821
|
+
return startOpencodeSdkHarness(config3);
|
|
83822
|
+
case "cursor-sdk":
|
|
83823
|
+
return startCursorSdkHarness(config3);
|
|
83824
|
+
case "pi-sdk":
|
|
83825
|
+
return startPiSdkHarness(config3);
|
|
83826
|
+
default: {
|
|
83827
|
+
const _exhaustive = config3.harnessName;
|
|
83828
|
+
throw new Error(`Unsupported direct harness: ${String(_exhaustive)}`);
|
|
83829
|
+
}
|
|
83830
|
+
}
|
|
83831
|
+
}
|
|
83832
|
+
function createChunkExtractor(harnessName) {
|
|
83833
|
+
switch (harnessName) {
|
|
83834
|
+
case "opencode-sdk":
|
|
83835
|
+
return createOpencodeSdkChunkExtractor();
|
|
83836
|
+
case "cursor-sdk":
|
|
83837
|
+
return createCursorSdkChunkExtractor();
|
|
83838
|
+
case "pi-sdk":
|
|
83839
|
+
return createPiSdkChunkExtractor();
|
|
83840
|
+
default:
|
|
83841
|
+
return createStandardSdkChunkExtractor();
|
|
83842
|
+
}
|
|
83843
|
+
}
|
|
83844
|
+
function opencodeOnPath() {
|
|
83845
|
+
try {
|
|
83846
|
+
execSync2("opencode --version", { stdio: "pipe" });
|
|
83847
|
+
return true;
|
|
83848
|
+
} catch {
|
|
83849
|
+
return false;
|
|
83850
|
+
}
|
|
83851
|
+
}
|
|
83852
|
+
async function isCursorSdkInstalled() {
|
|
83853
|
+
if (!process.env.CURSOR_API_KEY?.trim())
|
|
83854
|
+
return false;
|
|
83855
|
+
try {
|
|
83856
|
+
const { importBundledCursorSdk: importBundledCursorSdk2 } = await Promise.resolve().then(() => (init_cursor_sdk_package(), exports_cursor_sdk_package));
|
|
83857
|
+
await importBundledCursorSdk2();
|
|
83858
|
+
return true;
|
|
83859
|
+
} catch {
|
|
83860
|
+
return false;
|
|
83861
|
+
}
|
|
83862
|
+
}
|
|
83863
|
+
async function isPiSdkInstalled() {
|
|
83864
|
+
try {
|
|
83865
|
+
const { importBundledPiSdk: importBundledPiSdk2 } = await Promise.resolve().then(() => (init_pi_sdk_package(), exports_pi_sdk_package));
|
|
83866
|
+
const { ModelRegistry, AuthStorage } = await importBundledPiSdk2();
|
|
83867
|
+
const authStorage = AuthStorage.create();
|
|
83868
|
+
const modelRegistry = ModelRegistry.create(authStorage);
|
|
83869
|
+
return modelRegistry.getAvailable().length > 0;
|
|
83870
|
+
} catch {
|
|
83871
|
+
return false;
|
|
83872
|
+
}
|
|
83873
|
+
}
|
|
83874
|
+
async function listInstalledNativeDirectHarnesses() {
|
|
83875
|
+
const installed2 = [];
|
|
83876
|
+
if (opencodeOnPath())
|
|
83877
|
+
installed2.push("opencode-sdk");
|
|
83878
|
+
if (await isCursorSdkInstalled())
|
|
83879
|
+
installed2.push("cursor-sdk");
|
|
83880
|
+
if (await isPiSdkInstalled())
|
|
83881
|
+
installed2.push("pi-sdk");
|
|
83882
|
+
return installed2;
|
|
83883
|
+
}
|
|
83884
|
+
var init_registry4 = __esm(() => {
|
|
83885
|
+
init_cursor_sdk2();
|
|
83407
83886
|
init_opencode_harness();
|
|
83887
|
+
init_pi_sdk2();
|
|
83408
83888
|
});
|
|
83409
83889
|
|
|
83890
|
+
// src/commands/machine/daemon-start/direct-harness/command-subscriber.ts
|
|
83891
|
+
function startCommandSubscriber(session2, wsClient2, deps) {
|
|
83892
|
+
const processed = new Set;
|
|
83893
|
+
let processing = false;
|
|
83894
|
+
let pendingDrain = false;
|
|
83895
|
+
const runDrain = () => {
|
|
83896
|
+
if (processing) {
|
|
83897
|
+
pendingDrain = true;
|
|
83898
|
+
return;
|
|
83899
|
+
}
|
|
83900
|
+
processing = true;
|
|
83901
|
+
pendingDrain = false;
|
|
83902
|
+
drain(session2, deps, processed).finally(() => {
|
|
83903
|
+
processing = false;
|
|
83904
|
+
if (pendingDrain)
|
|
83905
|
+
runDrain();
|
|
83906
|
+
});
|
|
83907
|
+
};
|
|
83908
|
+
const unsub = wsClient2.onUpdate(api.daemon.directHarness.commands.listPendingCommands, { sessionId: session2.sessionId, machineId: session2.machineId }, () => runDrain(), (err) => {
|
|
83909
|
+
console.warn("[direct-harness] Command subscription error:", err instanceof Error ? err.message : String(err));
|
|
83910
|
+
});
|
|
83911
|
+
return { stop: unsub };
|
|
83912
|
+
}
|
|
83913
|
+
async function dispatchPendingCommand(session2, deps, cmd) {
|
|
83914
|
+
switch (cmd.type) {
|
|
83915
|
+
case "refreshCapabilities":
|
|
83916
|
+
await handleRefreshCapabilities(session2, deps, cmd);
|
|
83917
|
+
break;
|
|
83918
|
+
case "refreshSessionTitle":
|
|
83919
|
+
await handleRefreshSessionTitle(session2, deps, cmd);
|
|
83920
|
+
break;
|
|
83921
|
+
case "closeSession":
|
|
83922
|
+
await handleCloseSession(session2, deps, cmd);
|
|
83923
|
+
break;
|
|
83924
|
+
default:
|
|
83925
|
+
await markFailed(session2, cmd._id, `Unknown command type: ${cmd.type}`);
|
|
83926
|
+
}
|
|
83927
|
+
}
|
|
83928
|
+
async function processPendingCommand(session2, deps, cmd, now) {
|
|
83929
|
+
if (now - cmd.createdAt > DIRECT_HARNESS_COMMAND_TTL_MS) {
|
|
83930
|
+
console.log(`[direct-harness] Discarding stale command ${cmd._id} (type=${cmd.type}, age=${now - cmd.createdAt}ms)`);
|
|
83931
|
+
await markFailed(session2, cmd._id, "Command expired (TTL)");
|
|
83932
|
+
return;
|
|
83933
|
+
}
|
|
83934
|
+
await dispatchPendingCommand(session2, deps, cmd);
|
|
83935
|
+
}
|
|
83936
|
+
async function drain(session2, deps, processed) {
|
|
83937
|
+
const pending3 = await session2.backend.query(api.daemon.directHarness.commands.listPendingCommands, { sessionId: session2.sessionId, machineId: session2.machineId });
|
|
83938
|
+
if (!pending3 || pending3.length === 0)
|
|
83939
|
+
return;
|
|
83940
|
+
const now = Date.now();
|
|
83941
|
+
for (const cmd of pending3) {
|
|
83942
|
+
if (processed.has(cmd._id))
|
|
83943
|
+
continue;
|
|
83944
|
+
processed.add(cmd._id);
|
|
83945
|
+
try {
|
|
83946
|
+
await processPendingCommand(session2, deps, cmd, now);
|
|
83947
|
+
} catch (err) {
|
|
83948
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
83949
|
+
console.warn(`[direct-harness] Command ${cmd._id} failed: ${message}`);
|
|
83950
|
+
await markFailed(session2, cmd._id, message).catch(() => {});
|
|
83951
|
+
}
|
|
83952
|
+
}
|
|
83953
|
+
}
|
|
83954
|
+
async function handleRefreshCapabilities(session2, deps, cmd) {
|
|
83955
|
+
const payload = cmd.refreshCapabilities;
|
|
83956
|
+
console.log(`[direct-harness] Processing refreshCapabilities for workspace=${cmd.workspaceId}` + (payload ? ` (initiatedBy=${payload.initiatedBy})` : ""));
|
|
83957
|
+
const installed2 = await listInstalledNativeDirectHarnesses();
|
|
83958
|
+
const harnessEntries = [];
|
|
83959
|
+
let cwd = "";
|
|
83960
|
+
for (const harnessName of installed2) {
|
|
83961
|
+
const harness = await deps.lifecycleManager.getOrStart(cmd.workspaceId, harnessName);
|
|
83962
|
+
cwd = harness.cwd;
|
|
83963
|
+
const [agents, providers] = await Promise.all([harness.listAgents(), harness.listProviders()]);
|
|
83964
|
+
harnessEntries.push({
|
|
83965
|
+
name: harness.type,
|
|
83966
|
+
displayName: harness.displayName,
|
|
83967
|
+
agents: [...agents],
|
|
83968
|
+
providers: [...providers]
|
|
83969
|
+
});
|
|
83970
|
+
}
|
|
83971
|
+
const existing = await session2.backend.query(api.daemon.directHarness.capabilities.getForMachine, { sessionId: session2.sessionId, machineId: session2.machineId });
|
|
83972
|
+
const updatedWorkspace = {
|
|
83973
|
+
workspaceId: cmd.workspaceId,
|
|
83974
|
+
cwd,
|
|
83975
|
+
name: cwd,
|
|
83976
|
+
harnesses: harnessEntries
|
|
83977
|
+
};
|
|
83978
|
+
const merged = [
|
|
83979
|
+
...(existing?.workspaces ?? []).filter((ws) => ws.workspaceId !== cmd.workspaceId),
|
|
83980
|
+
updatedWorkspace
|
|
83981
|
+
];
|
|
83982
|
+
await deps.publisher.publish({
|
|
83983
|
+
machineId: session2.machineId,
|
|
83984
|
+
lastSeenAt: Date.now(),
|
|
83985
|
+
workspaces: merged
|
|
83986
|
+
});
|
|
83987
|
+
await session2.backend.mutation(api.daemon.directHarness.commands.updateCommandStatus, {
|
|
83988
|
+
sessionId: session2.sessionId,
|
|
83989
|
+
commandId: cmd._id,
|
|
83990
|
+
status: "done"
|
|
83991
|
+
});
|
|
83992
|
+
console.log(`[direct-harness] Capabilities refreshed for workspace=${cmd.workspaceId}`);
|
|
83993
|
+
}
|
|
83994
|
+
async function handleRefreshSessionTitle(session2, deps, cmd) {
|
|
83995
|
+
const { harnessSessionId } = cmd.refreshSessionTitle ?? {};
|
|
83996
|
+
if (!harnessSessionId) {
|
|
83997
|
+
await markFailed(session2, cmd._id, "refreshSessionTitle: missing harnessSessionId");
|
|
83998
|
+
return;
|
|
83999
|
+
}
|
|
84000
|
+
const sessionRow = await session2.backend.query(api.daemon.directHarness.sessions.getSession, {
|
|
84001
|
+
harnessSessionId
|
|
84002
|
+
});
|
|
84003
|
+
if (!sessionRow?.opencodeSessionId) {
|
|
84004
|
+
await session2.backend.mutation(api.daemon.directHarness.commands.updateCommandStatus, {
|
|
84005
|
+
sessionId: session2.sessionId,
|
|
84006
|
+
commandId: cmd._id,
|
|
84007
|
+
status: "done"
|
|
84008
|
+
});
|
|
84009
|
+
return;
|
|
84010
|
+
}
|
|
84011
|
+
const harnessName = sessionRow.harnessName ?? "opencode-sdk";
|
|
84012
|
+
const harness = await deps.lifecycleManager.getOrStart(sessionRow.workspaceId ?? cmd.workspaceId, harnessName);
|
|
84013
|
+
const newTitle = await harness.fetchSessionTitle(sessionRow.opencodeSessionId);
|
|
84014
|
+
if (newTitle) {
|
|
84015
|
+
await session2.backend.mutation(api.daemon.directHarness.sessions.updateSessionTitle, {
|
|
84016
|
+
sessionId: session2.sessionId,
|
|
84017
|
+
harnessSessionId,
|
|
84018
|
+
sessionTitle: newTitle
|
|
84019
|
+
});
|
|
84020
|
+
console.log(`[direct-harness] Refreshed title for session ${harnessSessionId}: "${newTitle}"`);
|
|
84021
|
+
}
|
|
84022
|
+
await session2.backend.mutation(api.daemon.directHarness.commands.updateCommandStatus, {
|
|
84023
|
+
sessionId: session2.sessionId,
|
|
84024
|
+
commandId: cmd._id,
|
|
84025
|
+
status: "done"
|
|
84026
|
+
});
|
|
84027
|
+
}
|
|
84028
|
+
async function closeDisconnectedHarnessSession(deps, sessionRow, harnessSessionId) {
|
|
84029
|
+
if (!sessionRow.opencodeSessionId) {
|
|
84030
|
+
await deps.sessionRepository.markClosed(harnessSessionId);
|
|
84031
|
+
return;
|
|
84032
|
+
}
|
|
84033
|
+
const harnessName = sessionRow.harnessName ?? "opencode-sdk";
|
|
84034
|
+
const harness = await deps.lifecycleManager.getOrStart(sessionRow.workspaceId ?? "", harnessName);
|
|
84035
|
+
const liveSession = await harness.resumeSession(sessionRow.opencodeSessionId, {
|
|
84036
|
+
harnessSessionId
|
|
84037
|
+
});
|
|
84038
|
+
await liveSession.close();
|
|
84039
|
+
await deps.sessionRepository.markClosed(harnessSessionId);
|
|
84040
|
+
}
|
|
84041
|
+
async function closeHarnessSession(session2, deps, harnessSessionId) {
|
|
84042
|
+
const sessionRow = await session2.backend.query(api.daemon.directHarness.sessions.getSession, {
|
|
84043
|
+
harnessSessionId
|
|
84044
|
+
});
|
|
84045
|
+
if (!sessionRow) {
|
|
84046
|
+
throw new Error(`Harness session ${harnessSessionId} not found`);
|
|
84047
|
+
}
|
|
84048
|
+
if (sessionRow.status === "closed" || sessionRow.status === "failed") {
|
|
84049
|
+
return;
|
|
84050
|
+
}
|
|
84051
|
+
const handle = deps.activeSessions.get(harnessSessionId);
|
|
84052
|
+
if (handle) {
|
|
84053
|
+
await handle.close();
|
|
84054
|
+
deps.activeSessions.delete(harnessSessionId);
|
|
84055
|
+
return;
|
|
84056
|
+
}
|
|
84057
|
+
await closeDisconnectedHarnessSession(deps, sessionRow, harnessSessionId);
|
|
84058
|
+
}
|
|
84059
|
+
async function handleCloseSession(session2, deps, cmd) {
|
|
84060
|
+
const { harnessSessionId } = cmd.closeSession ?? {};
|
|
84061
|
+
if (!harnessSessionId) {
|
|
84062
|
+
await markFailed(session2, cmd._id, "closeSession: missing harnessSessionId");
|
|
84063
|
+
return;
|
|
84064
|
+
}
|
|
84065
|
+
console.log(`[direct-harness] Processing closeSession for harnessSessionId=${harnessSessionId}`);
|
|
84066
|
+
await closeHarnessSession(session2, deps, harnessSessionId);
|
|
84067
|
+
await session2.backend.mutation(api.daemon.directHarness.commands.updateCommandStatus, {
|
|
84068
|
+
sessionId: session2.sessionId,
|
|
84069
|
+
commandId: cmd._id,
|
|
84070
|
+
status: "done"
|
|
84071
|
+
});
|
|
84072
|
+
console.log(`[direct-harness] Closed session ${harnessSessionId}`);
|
|
84073
|
+
}
|
|
84074
|
+
async function markFailed(session2, commandId, errorMessage) {
|
|
84075
|
+
await session2.backend.mutation(api.daemon.directHarness.commands.updateCommandStatus, {
|
|
84076
|
+
sessionId: session2.sessionId,
|
|
84077
|
+
commandId,
|
|
84078
|
+
status: "failed",
|
|
84079
|
+
errorMessage
|
|
84080
|
+
});
|
|
84081
|
+
}
|
|
84082
|
+
var DIRECT_HARNESS_COMMAND_TTL_MS = 60000;
|
|
84083
|
+
var init_command_subscriber = __esm(() => {
|
|
84084
|
+
init_api3();
|
|
84085
|
+
init_registry4();
|
|
84086
|
+
});
|
|
84087
|
+
|
|
84088
|
+
// src/infrastructure/harnesses/harness-key.ts
|
|
84089
|
+
function makeHarnessKey(workspaceId, harnessName) {
|
|
84090
|
+
return `${workspaceId}:${harnessName}`;
|
|
84091
|
+
}
|
|
84092
|
+
function parseHarnessKey(key) {
|
|
84093
|
+
const idx = key.indexOf(":");
|
|
84094
|
+
if (idx === -1)
|
|
84095
|
+
throw new Error(`Invalid harness key: ${key}`);
|
|
84096
|
+
return { workspaceId: key.slice(0, idx), harnessName: key.slice(idx + 1) };
|
|
84097
|
+
}
|
|
84098
|
+
|
|
83410
84099
|
// src/commands/machine/daemon-start/direct-harness/harness-lifecycle-manager.ts
|
|
83411
84100
|
class HarnessLifecycleManager {
|
|
83412
84101
|
harnesses;
|
|
@@ -83421,10 +84110,15 @@ class HarnessLifecycleManager {
|
|
|
83421
84110
|
this.resolveWorkspace = resolveWorkspace;
|
|
83422
84111
|
this.resolvedConvexUrl = resolvedConvexUrl;
|
|
83423
84112
|
}
|
|
83424
|
-
getOrStartHarnessEffect(workspaceId) {
|
|
83425
|
-
const
|
|
83426
|
-
|
|
84113
|
+
getOrStartHarnessEffect(workspaceId, harnessName) {
|
|
84114
|
+
const key = makeHarnessKey(workspaceId, harnessName);
|
|
84115
|
+
const existing = this.harnesses.get(key);
|
|
84116
|
+
if (existing?.isAlive())
|
|
83427
84117
|
return exports_Effect.succeed(existing);
|
|
84118
|
+
if (existing) {
|
|
84119
|
+
existing.close().catch(() => {});
|
|
84120
|
+
this.harnesses.delete(key);
|
|
84121
|
+
}
|
|
83428
84122
|
return exports_Effect.gen(this, function* () {
|
|
83429
84123
|
const workspace = yield* exports_Effect.tryPromise({
|
|
83430
84124
|
try: () => this.resolveWorkspace(workspaceId),
|
|
@@ -83433,23 +84127,23 @@ class HarnessLifecycleManager {
|
|
|
83433
84127
|
if (!workspace) {
|
|
83434
84128
|
return yield* exports_Effect.fail(new Error(`Workspace ${workspaceId} not found — cannot start harness`));
|
|
83435
84129
|
}
|
|
83436
|
-
console.log(`[${formatTimestamp()}] \uD83D\uDD27 Auto-starting
|
|
84130
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDD27 Auto-starting ${harnessName} for workspace=${workspaceId} (${workspace.workingDir})`);
|
|
83437
84131
|
const harness = yield* exports_Effect.tryPromise({
|
|
83438
|
-
try: () =>
|
|
83439
|
-
|
|
84132
|
+
try: () => startBoundHarness({
|
|
84133
|
+
harnessName,
|
|
83440
84134
|
workingDir: workspace.workingDir,
|
|
83441
84135
|
workspaceId,
|
|
83442
84136
|
resolvedConvexUrl: this.resolvedConvexUrl
|
|
83443
84137
|
}),
|
|
83444
84138
|
catch: (e) => e instanceof Error ? e : new Error(String(e))
|
|
83445
84139
|
});
|
|
83446
|
-
this.harnesses.set(
|
|
83447
|
-
this.idleSince.set(
|
|
84140
|
+
this.harnesses.set(key, harness);
|
|
84141
|
+
this.idleSince.set(key, Date.now());
|
|
83448
84142
|
return harness;
|
|
83449
84143
|
});
|
|
83450
84144
|
}
|
|
83451
|
-
async getOrStart(workspaceId) {
|
|
83452
|
-
return exports_Effect.runPromise(this.getOrStartHarnessEffect(workspaceId));
|
|
84145
|
+
async getOrStart(workspaceId, harnessName) {
|
|
84146
|
+
return exports_Effect.runPromise(this.getOrStartHarnessEffect(workspaceId, harnessName));
|
|
83453
84147
|
}
|
|
83454
84148
|
startMonitoring() {
|
|
83455
84149
|
if (this.monitorTimer)
|
|
@@ -83465,28 +84159,30 @@ class HarnessLifecycleManager {
|
|
|
83465
84159
|
}
|
|
83466
84160
|
checkInactivity() {
|
|
83467
84161
|
const now = Date.now();
|
|
83468
|
-
for (const
|
|
83469
|
-
const
|
|
84162
|
+
for (const key of this.harnesses.keys()) {
|
|
84163
|
+
const { workspaceId, harnessName } = parseHarnessKey(key);
|
|
84164
|
+
const hasActiveSessions = this.hasSessionsForHarnessKey(workspaceId, harnessName);
|
|
83470
84165
|
if (hasActiveSessions) {
|
|
83471
|
-
this.idleSince.delete(
|
|
84166
|
+
this.idleSince.delete(key);
|
|
83472
84167
|
} else {
|
|
83473
|
-
const idleStart = this.idleSince.get(
|
|
84168
|
+
const idleStart = this.idleSince.get(key);
|
|
83474
84169
|
if (idleStart === undefined) {
|
|
83475
|
-
this.idleSince.set(
|
|
84170
|
+
this.idleSince.set(key, now);
|
|
83476
84171
|
} else if (now - idleStart >= INACTIVITY_TTL_MS) {
|
|
83477
84172
|
const idleMinutes = Math.round((now - idleStart) / 60000);
|
|
83478
|
-
console.log(`[${formatTimestamp()}] \uD83D\uDD2A Killing idle harness for workspace=${workspaceId} (idle ${idleMinutes}min)`);
|
|
83479
|
-
this.harnesses.get(
|
|
83480
|
-
this.harnesses.delete(
|
|
83481
|
-
this.idleSince.delete(
|
|
84173
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDD2A Killing idle harness ${harnessName} for workspace=${workspaceId} (idle ${idleMinutes}min)`);
|
|
84174
|
+
this.harnesses.get(key)?.close().catch(() => {});
|
|
84175
|
+
this.harnesses.delete(key);
|
|
84176
|
+
this.idleSince.delete(key);
|
|
83482
84177
|
}
|
|
83483
84178
|
}
|
|
83484
84179
|
}
|
|
83485
84180
|
}
|
|
83486
|
-
|
|
84181
|
+
hasSessionsForHarnessKey(workspaceId, harnessName) {
|
|
83487
84182
|
for (const handle of this.activeSessions.values()) {
|
|
83488
|
-
if (handle.workspaceId === workspaceId)
|
|
84183
|
+
if (handle.workspaceId === workspaceId && handle.harnessName === harnessName) {
|
|
83489
84184
|
return true;
|
|
84185
|
+
}
|
|
83490
84186
|
}
|
|
83491
84187
|
return false;
|
|
83492
84188
|
}
|
|
@@ -83494,7 +84190,7 @@ class HarnessLifecycleManager {
|
|
|
83494
84190
|
var INACTIVITY_TTL_MS, CHECK_INTERVAL_MS;
|
|
83495
84191
|
var init_harness_lifecycle_manager = __esm(() => {
|
|
83496
84192
|
init_esm();
|
|
83497
|
-
|
|
84193
|
+
init_registry4();
|
|
83498
84194
|
INACTIVITY_TTL_MS = 15 * 60 * 1000;
|
|
83499
84195
|
CHECK_INTERVAL_MS = 60 * 1000;
|
|
83500
84196
|
});
|
|
@@ -83589,6 +84285,7 @@ async function resumeSession(deps, input) {
|
|
|
83589
84285
|
let closed = false;
|
|
83590
84286
|
const handle = {
|
|
83591
84287
|
harnessSessionId,
|
|
84288
|
+
harnessName: input.harnessName,
|
|
83592
84289
|
opencodeSessionId,
|
|
83593
84290
|
workspaceId: input.workspaceId ?? "",
|
|
83594
84291
|
session: session2,
|
|
@@ -83653,14 +84350,16 @@ async function resumeSessionHandle(session2, deps, rowId, info) {
|
|
|
83653
84350
|
return null;
|
|
83654
84351
|
}
|
|
83655
84352
|
const workspaceId = info.workspaceId;
|
|
84353
|
+
const harnessName = info.harnessName;
|
|
83656
84354
|
if (!workspaceId) {
|
|
83657
84355
|
console.warn(`[direct-harness] Cannot resume session ${rowId}: no workspace info`);
|
|
83658
84356
|
return null;
|
|
83659
84357
|
}
|
|
83660
|
-
|
|
84358
|
+
const key = makeHarnessKey(workspaceId, harnessName);
|
|
84359
|
+
let harness = deps.harnesses.get(key);
|
|
83661
84360
|
if (harness && !harness.isAlive()) {
|
|
83662
84361
|
harness.close().catch(() => {});
|
|
83663
|
-
deps.harnesses.delete(
|
|
84362
|
+
deps.harnesses.delete(key);
|
|
83664
84363
|
harness = undefined;
|
|
83665
84364
|
}
|
|
83666
84365
|
if (!harness) {
|
|
@@ -83672,20 +84371,20 @@ async function resumeSessionHandle(session2, deps, rowId, info) {
|
|
|
83672
84371
|
console.warn(`[direct-harness] Cannot resume session ${rowId}: workspace not found`);
|
|
83673
84372
|
return null;
|
|
83674
84373
|
}
|
|
83675
|
-
harness = await
|
|
83676
|
-
|
|
84374
|
+
harness = await startBoundHarness({
|
|
84375
|
+
harnessName,
|
|
83677
84376
|
workingDir: workspace.workingDir,
|
|
83678
84377
|
workspaceId,
|
|
83679
84378
|
resolvedConvexUrl: session2.convexUrl
|
|
83680
84379
|
});
|
|
83681
|
-
deps.harnesses.set(
|
|
84380
|
+
deps.harnesses.set(key, harness);
|
|
83682
84381
|
}
|
|
83683
84382
|
try {
|
|
83684
84383
|
return await resumeSession({
|
|
83685
84384
|
harness,
|
|
83686
84385
|
journalFactory: deps.journalFactory,
|
|
83687
|
-
chunkExtractor:
|
|
83688
|
-
}, { harnessSessionId: rowId, opencodeSessionId, workspaceId });
|
|
84386
|
+
chunkExtractor: createChunkExtractor(harness.type)
|
|
84387
|
+
}, { harnessSessionId: rowId, opencodeSessionId, workspaceId, harnessName });
|
|
83689
84388
|
} catch (err) {
|
|
83690
84389
|
const message = err instanceof Error ? err.message : String(err);
|
|
83691
84390
|
console.warn(`[direct-harness] Cannot resume session ${rowId}: ${message}`);
|
|
@@ -83731,8 +84430,9 @@ async function deliverPendingMessages(handle, deps, rowId, messages, info) {
|
|
|
83731
84430
|
console.warn(`[direct-harness] Prompt failed for session ${rowId} seq=${msg.seq}: ${message}`);
|
|
83732
84431
|
await deps.sessionRepository.markIdle(rowId).catch(() => {});
|
|
83733
84432
|
deps.activeSessions.delete(rowId);
|
|
83734
|
-
if (info?.workspaceId)
|
|
83735
|
-
deps.harnesses.delete(info.workspaceId);
|
|
84433
|
+
if (info?.workspaceId && info.harnessName) {
|
|
84434
|
+
deps.harnesses.delete(makeHarnessKey(info.workspaceId, info.harnessName));
|
|
84435
|
+
}
|
|
83736
84436
|
return;
|
|
83737
84437
|
}
|
|
83738
84438
|
}
|
|
@@ -83759,7 +84459,7 @@ var init_prompt_subscriber = __esm(() => {
|
|
|
83759
84459
|
init_idle_handler();
|
|
83760
84460
|
init_api3();
|
|
83761
84461
|
init_resume_session();
|
|
83762
|
-
|
|
84462
|
+
init_registry4();
|
|
83763
84463
|
});
|
|
83764
84464
|
|
|
83765
84465
|
// src/commands/machine/daemon-start/direct-harness/session-subscriber.ts
|
|
@@ -83784,21 +84484,23 @@ function startSessionSubscriber(daemonSession, wsClient2, deps) {
|
|
|
83784
84484
|
return { stop: unsub };
|
|
83785
84485
|
}
|
|
83786
84486
|
async function getOrCreateHarness(daemonSession, deps, session2, workspace) {
|
|
83787
|
-
|
|
84487
|
+
const harnessName = session2.opencode?.harnessName ?? "opencode-sdk";
|
|
84488
|
+
const key = makeHarnessKey(session2.workspaceId, harnessName);
|
|
84489
|
+
let harness = deps.harnesses.get(key);
|
|
83788
84490
|
if (harness && !harness.isAlive()) {
|
|
83789
|
-
console.warn(`[direct-harness] Harness for workspace ${session2.workspaceId} is no longer alive — restarting`);
|
|
84491
|
+
console.warn(`[direct-harness] Harness ${harnessName} for workspace ${session2.workspaceId} is no longer alive — restarting`);
|
|
83790
84492
|
harness.close().catch(() => {});
|
|
83791
|
-
deps.harnesses.delete(
|
|
84493
|
+
deps.harnesses.delete(key);
|
|
83792
84494
|
harness = undefined;
|
|
83793
84495
|
}
|
|
83794
84496
|
if (!harness) {
|
|
83795
|
-
harness = await
|
|
83796
|
-
|
|
84497
|
+
harness = await startBoundHarness({
|
|
84498
|
+
harnessName,
|
|
83797
84499
|
workingDir: workspace.workingDir,
|
|
83798
84500
|
workspaceId: session2.workspaceId,
|
|
83799
84501
|
resolvedConvexUrl: daemonSession.convexUrl
|
|
83800
84502
|
});
|
|
83801
|
-
deps.harnesses.set(
|
|
84503
|
+
deps.harnesses.set(key, harness);
|
|
83802
84504
|
}
|
|
83803
84505
|
return harness;
|
|
83804
84506
|
}
|
|
@@ -83850,13 +84552,17 @@ async function processOne(daemonSession, deps, session2) {
|
|
|
83850
84552
|
await deps.sessionRepository.markFailed(rowId);
|
|
83851
84553
|
return;
|
|
83852
84554
|
}
|
|
84555
|
+
const harnessName = session2.opencode?.harnessName ?? "opencode-sdk";
|
|
83853
84556
|
const harness = await getOrCreateHarness(daemonSession, deps, session2, workspace);
|
|
84557
|
+
const modelConfig = session2.opencode?.lastUsedConfig.model;
|
|
84558
|
+
const model = modelConfig ? `${modelConfig.providerID}/${modelConfig.modelID}` : undefined;
|
|
83854
84559
|
const liveSession = await harness.newSession({
|
|
83855
84560
|
agent: session2.opencode?.lastUsedConfig.agent ?? "build",
|
|
84561
|
+
model,
|
|
83856
84562
|
harnessSessionId: rowId
|
|
83857
84563
|
});
|
|
83858
84564
|
const journal = deps.journalFactory.create(rowId);
|
|
83859
|
-
const extractChunk =
|
|
84565
|
+
const extractChunk = createChunkExtractor(harness.type);
|
|
83860
84566
|
const idleConfig = {
|
|
83861
84567
|
agent: session2.opencode?.lastUsedConfig.agent ?? "build",
|
|
83862
84568
|
model: session2.opencode?.lastUsedConfig.model
|
|
@@ -83871,9 +84577,11 @@ async function processOne(daemonSession, deps, session2) {
|
|
|
83871
84577
|
await journal.commit();
|
|
83872
84578
|
await liveSession.close();
|
|
83873
84579
|
await deps.sessionRepository.markClosed(rowId);
|
|
84580
|
+
deps.activeSessions.delete(rowId);
|
|
83874
84581
|
};
|
|
83875
84582
|
const handle = {
|
|
83876
84583
|
harnessSessionId: rowId,
|
|
84584
|
+
harnessName,
|
|
83877
84585
|
opencodeSessionId: liveSession.opencodeSessionId,
|
|
83878
84586
|
workspaceId: session2.workspaceId,
|
|
83879
84587
|
session: liveSession,
|
|
@@ -83911,7 +84619,61 @@ async function processOne(daemonSession, deps, session2) {
|
|
|
83911
84619
|
var init_session_subscriber = __esm(() => {
|
|
83912
84620
|
init_idle_handler();
|
|
83913
84621
|
init_api3();
|
|
83914
|
-
|
|
84622
|
+
init_registry4();
|
|
84623
|
+
});
|
|
84624
|
+
|
|
84625
|
+
// src/commands/machine/daemon-start/direct-harness/shutdown-sessions.ts
|
|
84626
|
+
async function listHarnessSessionIdsForShutdown(session2) {
|
|
84627
|
+
const ids3 = new Set;
|
|
84628
|
+
const managed = await session2.backend.query(api.daemon.directHarness.turns.getMachineHarnessSessions, {
|
|
84629
|
+
sessionId: session2.sessionId,
|
|
84630
|
+
machineId: session2.machineId
|
|
84631
|
+
});
|
|
84632
|
+
for (const row of managed) {
|
|
84633
|
+
ids3.add(row.harnessSessionId);
|
|
84634
|
+
}
|
|
84635
|
+
const pending3 = await session2.backend.query(api.daemon.directHarness.sessions.listPendingSessionsForMachine, {
|
|
84636
|
+
sessionId: session2.sessionId,
|
|
84637
|
+
machineId: session2.machineId
|
|
84638
|
+
});
|
|
84639
|
+
for (const row of pending3) {
|
|
84640
|
+
ids3.add(row._id);
|
|
84641
|
+
}
|
|
84642
|
+
return [...ids3];
|
|
84643
|
+
}
|
|
84644
|
+
async function closeAllMachineHarnessSessionsOnShutdown(session2, deps) {
|
|
84645
|
+
const commandDeps = {
|
|
84646
|
+
lifecycleManager: deps.lifecycleManager,
|
|
84647
|
+
publisher: {},
|
|
84648
|
+
activeSessions: deps.activeSessions,
|
|
84649
|
+
sessionRepository: deps.sessionRepository
|
|
84650
|
+
};
|
|
84651
|
+
const harnessSessionIds = await listHarnessSessionIdsForShutdown(session2);
|
|
84652
|
+
if (harnessSessionIds.length === 0)
|
|
84653
|
+
return;
|
|
84654
|
+
console.log(`[direct-harness] Closing ${harnessSessionIds.length} harness session(s) on daemon shutdown...`);
|
|
84655
|
+
for (const harnessSessionId of harnessSessionIds) {
|
|
84656
|
+
try {
|
|
84657
|
+
await session2.backend.mutation(api.daemon.directHarness.turns.markOrphanTurnsFailed, {
|
|
84658
|
+
sessionId: session2.sessionId,
|
|
84659
|
+
machineId: session2.machineId,
|
|
84660
|
+
harnessSessionId
|
|
84661
|
+
});
|
|
84662
|
+
} catch {}
|
|
84663
|
+
try {
|
|
84664
|
+
await closeHarnessSession(session2, commandDeps, harnessSessionId);
|
|
84665
|
+
} catch (err) {
|
|
84666
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
84667
|
+
console.warn(`[direct-harness] Failed to close session ${harnessSessionId} on shutdown: ${message}`);
|
|
84668
|
+
try {
|
|
84669
|
+
await deps.sessionRepository.markClosed(harnessSessionId);
|
|
84670
|
+
} catch {}
|
|
84671
|
+
}
|
|
84672
|
+
}
|
|
84673
|
+
}
|
|
84674
|
+
var init_shutdown_sessions = __esm(() => {
|
|
84675
|
+
init_command_subscriber();
|
|
84676
|
+
init_api3();
|
|
83915
84677
|
});
|
|
83916
84678
|
|
|
83917
84679
|
// src/infrastructure/repos/convex-capabilities-publisher.ts
|
|
@@ -84202,13 +84964,20 @@ function startDirectHarnessSubscriptions(session2, wsClient2, activeSessions, ha
|
|
|
84202
84964
|
publisher: new ConvexCapabilitiesPublisher({
|
|
84203
84965
|
backend: session2.backend,
|
|
84204
84966
|
sessionId: session2.sessionId
|
|
84205
|
-
})
|
|
84967
|
+
}),
|
|
84968
|
+
activeSessions,
|
|
84969
|
+
sessionRepository
|
|
84206
84970
|
});
|
|
84207
84971
|
return {
|
|
84208
84972
|
pendingPromptSubscriptionHandle,
|
|
84209
84973
|
pendingHarnessSessionSubscriptionHandle,
|
|
84210
84974
|
commandSubscriptionHandle,
|
|
84211
|
-
lifecycleManager
|
|
84975
|
+
lifecycleManager,
|
|
84976
|
+
closeSessionsOnShutdown: () => closeAllMachineHarnessSessionsOnShutdown(session2, {
|
|
84977
|
+
lifecycleManager,
|
|
84978
|
+
activeSessions,
|
|
84979
|
+
sessionRepository
|
|
84980
|
+
})
|
|
84212
84981
|
};
|
|
84213
84982
|
}
|
|
84214
84983
|
var init_start_subscriptions = __esm(() => {
|
|
@@ -84216,6 +84985,7 @@ var init_start_subscriptions = __esm(() => {
|
|
|
84216
84985
|
init_harness_lifecycle_manager();
|
|
84217
84986
|
init_prompt_subscriber();
|
|
84218
84987
|
init_session_subscriber();
|
|
84988
|
+
init_shutdown_sessions();
|
|
84219
84989
|
init_api3();
|
|
84220
84990
|
init_convex_capabilities_publisher();
|
|
84221
84991
|
init_convex_output_repository();
|
|
@@ -84935,16 +85705,6 @@ function createTurnCompletedBackend(deps) {
|
|
|
84935
85705
|
machineId: deps.machineId,
|
|
84936
85706
|
...args2
|
|
84937
85707
|
}),
|
|
84938
|
-
emitSessionResumed: (args2) => deps.backend.mutation(api.machines.emitSessionResumed, {
|
|
84939
|
-
sessionId: deps.sessionId,
|
|
84940
|
-
machineId: deps.machineId,
|
|
84941
|
-
...args2
|
|
84942
|
-
}),
|
|
84943
|
-
emitSessionResumeFailed: (args2) => deps.backend.mutation(api.machines.emitSessionResumeFailed, {
|
|
84944
|
-
sessionId: deps.sessionId,
|
|
84945
|
-
machineId: deps.machineId,
|
|
84946
|
-
...args2
|
|
84947
|
-
}),
|
|
84948
85708
|
emitAgentStartFailed: (args2) => deps.backend.mutation(api.machines.emitAgentStartFailed, {
|
|
84949
85709
|
sessionId: deps.sessionId,
|
|
84950
85710
|
machineId: deps.machineId,
|
|
@@ -85239,12 +85999,13 @@ class NativeTaskDeliveryCoordinator {
|
|
|
85239
85999
|
}
|
|
85240
86000
|
}
|
|
85241
86001
|
reconcileAssignedTasks(params) {
|
|
85242
|
-
const { tasks, runtime: runtime4, effectContext: effectContext2, agentMgr, sessionDeps } = params;
|
|
85243
|
-
|
|
85244
|
-
|
|
86002
|
+
const { tasks, runtime: runtime4, effectContext: effectContext2, agentMgr, sessionDeps, machineId } = params;
|
|
86003
|
+
const ledger = this.ledger;
|
|
86004
|
+
for (const row of tasks) {
|
|
86005
|
+
const slot = agentMgr.getSlot(row.chatroomId, row.agentConfig.role);
|
|
85245
86006
|
const harnessSessionId = slot?.harnessSessionId;
|
|
85246
|
-
if (!shouldDeliverNativeTask(
|
|
85247
|
-
ledger
|
|
86007
|
+
if (!shouldDeliverNativeTask(row, {
|
|
86008
|
+
ledger,
|
|
85248
86009
|
harnessSessionId
|
|
85249
86010
|
})) {
|
|
85250
86011
|
continue;
|
|
@@ -85252,14 +86013,24 @@ class NativeTaskDeliveryCoordinator {
|
|
|
85252
86013
|
if (!harnessSessionId) {
|
|
85253
86014
|
continue;
|
|
85254
86015
|
}
|
|
85255
|
-
exports_Runtime.runFork(runtime4)(
|
|
85256
|
-
|
|
85257
|
-
|
|
85258
|
-
|
|
85259
|
-
|
|
85260
|
-
|
|
85261
|
-
|
|
85262
|
-
|
|
86016
|
+
exports_Runtime.runFork(runtime4)(exports_Effect.gen(function* () {
|
|
86017
|
+
const full = yield* exports_Effect.tryPromise(() => sessionDeps.backend.query(api.machines.getAssignedTaskForAction, {
|
|
86018
|
+
sessionId: sessionDeps.sessionId,
|
|
86019
|
+
machineId,
|
|
86020
|
+
taskId: row.taskId,
|
|
86021
|
+
role: row.agentConfig.role
|
|
86022
|
+
}));
|
|
86023
|
+
if (!full)
|
|
86024
|
+
return;
|
|
86025
|
+
yield* runNativeInjectionEffect(full, harnessSessionId, {
|
|
86026
|
+
sessionId: sessionDeps.sessionId,
|
|
86027
|
+
backend: sessionDeps.backend,
|
|
86028
|
+
agentMgr: {
|
|
86029
|
+
resumeTurnForSlot: (args2) => exports_Effect.runPromise(agentMgr.resumeTurnForSlot(args2))
|
|
86030
|
+
},
|
|
86031
|
+
convexUrl: sessionDeps.convexUrl
|
|
86032
|
+
}, ledger);
|
|
86033
|
+
}).pipe(exports_Effect.provide(effectContext2), exports_Effect.catchAll((err) => exports_Effect.sync(() => console.warn(`[NativeTaskDelivery] delivery failed for ${row.agentConfig.role}@${row.chatroomId}: ${getErrorMessage(err)}`)))));
|
|
85263
86034
|
}
|
|
85264
86035
|
}
|
|
85265
86036
|
}
|
|
@@ -85275,6 +86046,7 @@ var init_native_task_delivery_coordinator = __esm(() => {
|
|
|
85275
86046
|
init_esm();
|
|
85276
86047
|
init_native_task_injector_logic();
|
|
85277
86048
|
init_native_task_injector();
|
|
86049
|
+
init_api3();
|
|
85278
86050
|
init_convex_error();
|
|
85279
86051
|
});
|
|
85280
86052
|
|
|
@@ -85570,9 +86342,6 @@ async function tryAbortResumeStorm(deps, input, slot) {
|
|
|
85570
86342
|
return false;
|
|
85571
86343
|
}
|
|
85572
86344
|
deps.resumeStormTracker.reset(input.chatroomId, input.role);
|
|
85573
|
-
if (slot) {
|
|
85574
|
-
slot.resumeInFlight = false;
|
|
85575
|
-
}
|
|
85576
86345
|
try {
|
|
85577
86346
|
await deps.backend.emitResumeStormAborted({
|
|
85578
86347
|
chatroomId: input.chatroomId,
|
|
@@ -85608,11 +86377,11 @@ function appendRecentLogLine(slot, line) {
|
|
|
85608
86377
|
}
|
|
85609
86378
|
var RECENT_LOG_LINE_CAP2 = 100;
|
|
85610
86379
|
|
|
86380
|
+
// src/domain/agent-lifecycle/policies/cursor-sdk-session-reopen-retry.ts
|
|
86381
|
+
var CURSOR_SDK_SESSION_REOPEN_MAX_ATTEMPTS = 20, CURSOR_SDK_SESSION_REOPEN_INTERVAL_MS = 5000, CURSOR_SDK_SESSION_REOPEN_REASON = "platform.cursor_sdk_session_reopen";
|
|
86382
|
+
|
|
85611
86383
|
// src/domain/agent-lifecycle/use-cases/handle-turn-completed.ts
|
|
85612
86384
|
async function handleTurnCompleted(deps, input, slot) {
|
|
85613
|
-
if (slot?.resumeInFlight) {
|
|
85614
|
-
return { outcome: "skipped_duplicate" };
|
|
85615
|
-
}
|
|
85616
86385
|
if (await tryAbortResumeStorm(deps, input, slot)) {
|
|
85617
86386
|
return { outcome: "storm_aborted" };
|
|
85618
86387
|
}
|
|
@@ -85631,35 +86400,6 @@ async function handleTurnCompleted(deps, input, slot) {
|
|
|
85631
86400
|
deps.killProcess(input.pid);
|
|
85632
86401
|
return { outcome: "killed_terminal_provider_error" };
|
|
85633
86402
|
}
|
|
85634
|
-
if (input.supportsSessionResume && input.wantResume) {
|
|
85635
|
-
if (slot) {
|
|
85636
|
-
slot.resumeInFlight = true;
|
|
85637
|
-
}
|
|
85638
|
-
try {
|
|
85639
|
-
await deps.resumeTurn(input.pid, deps.composeResumePrompt({ chatroomId: input.chatroomId, role: input.role }));
|
|
85640
|
-
try {
|
|
85641
|
-
await deps.backend.emitSessionResumed({
|
|
85642
|
-
chatroomId: input.chatroomId,
|
|
85643
|
-
role: input.role,
|
|
85644
|
-
...slot?.harnessSessionId ? { harnessSessionId: slot.harnessSessionId } : {}
|
|
85645
|
-
});
|
|
85646
|
-
} catch {}
|
|
85647
|
-
return { outcome: "resumed" };
|
|
85648
|
-
} catch (err) {
|
|
85649
|
-
try {
|
|
85650
|
-
await deps.backend.emitSessionResumeFailed({
|
|
85651
|
-
chatroomId: input.chatroomId,
|
|
85652
|
-
role: input.role,
|
|
85653
|
-
reason: err.message,
|
|
85654
|
-
...slot?.harnessSessionId ? { harnessSessionId: slot.harnessSessionId } : {}
|
|
85655
|
-
});
|
|
85656
|
-
} catch {}
|
|
85657
|
-
} finally {
|
|
85658
|
-
if (slot) {
|
|
85659
|
-
slot.resumeInFlight = false;
|
|
85660
|
-
}
|
|
85661
|
-
}
|
|
85662
|
-
}
|
|
85663
86403
|
deps.killProcess(input.pid);
|
|
85664
86404
|
return { outcome: "killed" };
|
|
85665
86405
|
}
|
|
@@ -86039,6 +86779,7 @@ class AgentProcessManager {
|
|
|
86039
86779
|
deps;
|
|
86040
86780
|
slots = new Map;
|
|
86041
86781
|
lastHarnessSessions = new Map;
|
|
86782
|
+
sessionReopenRetryInFlight = new Set;
|
|
86042
86783
|
exitRetryQueue = [];
|
|
86043
86784
|
exitRetryTimer = null;
|
|
86044
86785
|
turnEndQueue = new TurnEndQueue;
|
|
@@ -86070,7 +86811,6 @@ class AgentProcessManager {
|
|
|
86070
86811
|
model: slot.model,
|
|
86071
86812
|
workingDir: slot.workingDir,
|
|
86072
86813
|
startedAt: slot.startedAt,
|
|
86073
|
-
resumeInFlight: slot.resumeInFlight,
|
|
86074
86814
|
recentLogLines: slot.recentLogLines,
|
|
86075
86815
|
wantResume: slot.wantResume
|
|
86076
86816
|
});
|
|
@@ -86176,9 +86916,7 @@ class AgentProcessManager {
|
|
|
86176
86916
|
}
|
|
86177
86917
|
async runHandleAgentEnd(opts) {
|
|
86178
86918
|
const slot = this.slots.get(agentKey3(opts.chatroomId, opts.role));
|
|
86179
|
-
const service3 = this.deps.agentServices.get(opts.harness);
|
|
86180
86919
|
const capabilities = getHarnessCapabilities(opts.harness);
|
|
86181
|
-
const supportsSessionResume = capabilities.supportsSessionResume && typeof service3?.resumeTurn === "function";
|
|
86182
86920
|
this.updateSlotsMirror(opts.chatroomId, opts.role, {
|
|
86183
86921
|
state: slot?.state ?? "idle",
|
|
86184
86922
|
pid: slot?.pid,
|
|
@@ -86187,11 +86925,10 @@ class AgentProcessManager {
|
|
|
86187
86925
|
model: slot?.model,
|
|
86188
86926
|
workingDir: slot?.workingDir,
|
|
86189
86927
|
startedAt: slot?.startedAt,
|
|
86190
|
-
resumeInFlight: slot?.resumeInFlight,
|
|
86191
86928
|
recentLogLines: slot?.recentLogLines,
|
|
86192
86929
|
wantResume: slot?.wantResume
|
|
86193
86930
|
});
|
|
86194
|
-
console.log(`[AgentProcessManager] lifecycle.turn.completed: role=${opts.role} pid=${opts.pid} harness=${opts.harness}
|
|
86931
|
+
console.log(`[AgentProcessManager] lifecycle.turn.completed: role=${opts.role} pid=${opts.pid} harness=${opts.harness}`);
|
|
86195
86932
|
if (capabilities.supportsNativeIntegration) {
|
|
86196
86933
|
await this.runHandleNativeTurnEnd(opts, slot);
|
|
86197
86934
|
return;
|
|
@@ -86200,18 +86937,6 @@ class AgentProcessManager {
|
|
|
86200
86937
|
resumeStormTracker: this.deps.resumeStormTracker,
|
|
86201
86938
|
backend: createTurnCompletedBackend(this.deps),
|
|
86202
86939
|
now: () => this.deps.clock.now(),
|
|
86203
|
-
composeResumePrompt: ({ chatroomId, role }) => composeResumeMessage({
|
|
86204
|
-
chatroomId,
|
|
86205
|
-
role,
|
|
86206
|
-
convexUrl: this.deps.convexUrl,
|
|
86207
|
-
supportsNativeIntegration: capabilities.supportsNativeIntegration
|
|
86208
|
-
}),
|
|
86209
|
-
resumeTurn: async (pid, prompt) => {
|
|
86210
|
-
if (!service3?.resumeTurn) {
|
|
86211
|
-
throw new Error("Harness does not support resumeTurn");
|
|
86212
|
-
}
|
|
86213
|
-
await service3.resumeTurn(pid, prompt);
|
|
86214
|
-
},
|
|
86215
86940
|
killProcess: (pid) => {
|
|
86216
86941
|
try {
|
|
86217
86942
|
this.deps.processes.kill(-pid, "SIGTERM");
|
|
@@ -86221,27 +86946,17 @@ class AgentProcessManager {
|
|
|
86221
86946
|
}, {
|
|
86222
86947
|
chatroomId: opts.chatroomId,
|
|
86223
86948
|
role: opts.role,
|
|
86224
|
-
pid: opts.pid
|
|
86225
|
-
supportsSessionResume,
|
|
86226
|
-
wantResume: slot?.wantResume ?? true
|
|
86949
|
+
pid: opts.pid
|
|
86227
86950
|
}, slot);
|
|
86228
|
-
if (result.outcome === "
|
|
86229
|
-
console.log(`[AgentProcessManager] lifecycle.turn.completed: skipping duplicate resume for ${opts.role} (resume already in flight)`);
|
|
86230
|
-
} else if (result.outcome === "storm_aborted") {
|
|
86951
|
+
if (result.outcome === "storm_aborted") {
|
|
86231
86952
|
console.log(`[AgentProcessManager] ✅ Handled rapid resume storm for ${opts.role}`);
|
|
86232
|
-
} else if (result.outcome === "resumed") {
|
|
86233
|
-
console.log(`[AgentProcessManager] ✅ Emitted agent.sessionResumed for ${opts.role}`);
|
|
86234
86953
|
} else if (result.outcome === "killed") {
|
|
86235
|
-
console.log(`[AgentProcessManager] lifecycle.turn.completed: killed process for ${opts.role}
|
|
86954
|
+
console.log(`[AgentProcessManager] lifecycle.turn.completed: killed process for ${opts.role}`);
|
|
86236
86955
|
} else if (result.outcome === "killed_terminal_provider_error") {
|
|
86237
86956
|
console.log(`[AgentProcessManager] ⛔ Terminal provider error for ${opts.role} — emitted agent.startFailed`);
|
|
86238
86957
|
}
|
|
86239
86958
|
}
|
|
86240
86959
|
async runHandleNativeTurnEnd(opts, slot) {
|
|
86241
|
-
if (slot?.resumeInFlight) {
|
|
86242
|
-
console.log(`[AgentProcessManager] lifecycle.turn.completed: skipping duplicate native turn-end for ${opts.role}`);
|
|
86243
|
-
return;
|
|
86244
|
-
}
|
|
86245
86960
|
if (await tryAbortResumeStorm({
|
|
86246
86961
|
resumeStormTracker: this.deps.resumeStormTracker,
|
|
86247
86962
|
backend: createTurnCompletedBackend(this.deps),
|
|
@@ -86250,9 +86965,7 @@ class AgentProcessManager {
|
|
|
86250
86965
|
}, {
|
|
86251
86966
|
chatroomId: opts.chatroomId,
|
|
86252
86967
|
role: opts.role,
|
|
86253
|
-
pid: opts.pid
|
|
86254
|
-
supportsSessionResume: false,
|
|
86255
|
-
wantResume: false
|
|
86968
|
+
pid: opts.pid
|
|
86256
86969
|
}, slot)) {
|
|
86257
86970
|
console.log(`[AgentProcessManager] ✅ Handled rapid resume storm for ${opts.role}`);
|
|
86258
86971
|
return;
|
|
@@ -86416,6 +87129,10 @@ class AgentProcessManager {
|
|
|
86416
87129
|
return;
|
|
86417
87130
|
}
|
|
86418
87131
|
const coldRestartAfterRunError = this.clearHarnessSessionAfterRunError(key, logs);
|
|
87132
|
+
if (harness === "cursor-sdk") {
|
|
87133
|
+
this.retryCursorSdkSessionReopen(opts, ctx, coldRestartAfterRunError);
|
|
87134
|
+
return;
|
|
87135
|
+
}
|
|
86419
87136
|
this.ensureRunning({
|
|
86420
87137
|
chatroomId: opts.chatroomId,
|
|
86421
87138
|
role: opts.role,
|
|
@@ -86433,6 +87150,49 @@ class AgentProcessManager {
|
|
|
86433
87150
|
this.emitStartFailedEvent(opts.role, opts.chatroomId, err.message);
|
|
86434
87151
|
});
|
|
86435
87152
|
}
|
|
87153
|
+
async retryCursorSdkSessionReopen(opts, ctx, coldRestartAfterRunError) {
|
|
87154
|
+
const key = agentKey3(opts.chatroomId, opts.role);
|
|
87155
|
+
if (this.sessionReopenRetryInFlight.has(key)) {
|
|
87156
|
+
return;
|
|
87157
|
+
}
|
|
87158
|
+
this.sessionReopenRetryInFlight.add(key);
|
|
87159
|
+
const harness = ctx.harness;
|
|
87160
|
+
const model = ctx.model;
|
|
87161
|
+
const workingDir = ctx.workingDir;
|
|
87162
|
+
const wantResume = coldRestartAfterRunError ? false : ctx.wantResume ?? true;
|
|
87163
|
+
const storedSessionId = this.lastHarnessSessions.get(key)?.harnessSessionId;
|
|
87164
|
+
let lastError = "unknown";
|
|
87165
|
+
try {
|
|
87166
|
+
for (let attempt = 1;attempt <= CURSOR_SDK_SESSION_REOPEN_MAX_ATTEMPTS; attempt++) {
|
|
87167
|
+
await this.emitSessionReopenRetry(opts.chatroomId, opts.role, attempt, attempt > 1 ? lastError : undefined, storedSessionId);
|
|
87168
|
+
const result = await this.ensureRunning({
|
|
87169
|
+
chatroomId: opts.chatroomId,
|
|
87170
|
+
role: opts.role,
|
|
87171
|
+
agentHarness: harness,
|
|
87172
|
+
model,
|
|
87173
|
+
workingDir,
|
|
87174
|
+
reason: CURSOR_SDK_SESSION_REOPEN_REASON,
|
|
87175
|
+
wantResume
|
|
87176
|
+
});
|
|
87177
|
+
if (result.success) {
|
|
87178
|
+
return;
|
|
87179
|
+
}
|
|
87180
|
+
lastError = result.error ?? "unknown";
|
|
87181
|
+
if (attempt < CURSOR_SDK_SESSION_REOPEN_MAX_ATTEMPTS) {
|
|
87182
|
+
await this.deps.clock.delay(CURSOR_SDK_SESSION_REOPEN_INTERVAL_MS);
|
|
87183
|
+
}
|
|
87184
|
+
}
|
|
87185
|
+
const failureMessage = `cursor-sdk session reopen failed after ${CURSOR_SDK_SESSION_REOPEN_MAX_ATTEMPTS} attempts: ${lastError}`;
|
|
87186
|
+
console.log(`[AgentProcessManager] ⛔ ${failureMessage}`);
|
|
87187
|
+
this.emitStartFailedEvent(opts.role, opts.chatroomId, failureMessage);
|
|
87188
|
+
} catch (err) {
|
|
87189
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
87190
|
+
console.log(` ⚠️ cursor-sdk session reopen retry loop failed: ${message}`);
|
|
87191
|
+
this.emitStartFailedEvent(opts.role, opts.chatroomId, message);
|
|
87192
|
+
} finally {
|
|
87193
|
+
this.sessionReopenRetryInFlight.delete(key);
|
|
87194
|
+
}
|
|
87195
|
+
}
|
|
86436
87196
|
handlePermanentFailureForRestart(opts, recentLogLines, startFailedAlreadyEmitted) {
|
|
86437
87197
|
const error = isTerminalProviderFailureInLogs(recentLogLines ?? []) ? formatTerminalProviderFailureMessage(recentLogLines ?? []) : formatPermanentHarnessFailureMessage(recentLogLines ?? []);
|
|
86438
87198
|
console.log(`[AgentProcessManager] ⛔ Skipping restart — ${error}`);
|
|
@@ -86652,12 +87412,12 @@ class AgentProcessManager {
|
|
|
86652
87412
|
if (!stored) {
|
|
86653
87413
|
return null;
|
|
86654
87414
|
}
|
|
86655
|
-
|
|
86656
|
-
if (!resumeFromDaemonMemory) {
|
|
87415
|
+
if (!opts.service.resumeFromDaemonMemory) {
|
|
86657
87416
|
return null;
|
|
86658
87417
|
}
|
|
86659
87418
|
try {
|
|
86660
|
-
|
|
87419
|
+
await this.emitSessionResumeRequested(opts.chatroomId, opts.role, opts.agentHarness, stored.harnessSessionId);
|
|
87420
|
+
const spawnResult = await opts.service.resumeFromDaemonMemory({
|
|
86661
87421
|
workingDir: stored.workingDir,
|
|
86662
87422
|
prompt: createSpawnPrompt(opts.initPrompt),
|
|
86663
87423
|
systemPrompt: opts.systemPrompt,
|
|
@@ -86704,6 +87464,21 @@ class AgentProcessManager {
|
|
|
86704
87464
|
}
|
|
86705
87465
|
return null;
|
|
86706
87466
|
}
|
|
87467
|
+
async emitSessionResumeRequested(chatroomId, role, agentHarness, harnessSessionId) {
|
|
87468
|
+
try {
|
|
87469
|
+
await this.deps.backend.mutation(api.machines.emitSessionResumeRequested, {
|
|
87470
|
+
sessionId: this.deps.sessionId,
|
|
87471
|
+
machineId: this.deps.machineId,
|
|
87472
|
+
chatroomId,
|
|
87473
|
+
role,
|
|
87474
|
+
agentHarness,
|
|
87475
|
+
...harnessSessionId ? { harnessSessionId } : {}
|
|
87476
|
+
});
|
|
87477
|
+
console.log(`[AgentProcessManager] ✅ Emitted agent.sessionResumeRequested for ${role}`);
|
|
87478
|
+
} catch (err) {
|
|
87479
|
+
console.log(` ⚠️ Failed to emit sessionResumeRequested event: ${err.message}`);
|
|
87480
|
+
}
|
|
87481
|
+
}
|
|
86707
87482
|
async emitSessionResumed(chatroomId, role, harnessSessionId) {
|
|
86708
87483
|
try {
|
|
86709
87484
|
await this.deps.backend.mutation(api.machines.emitSessionResumed, {
|
|
@@ -86733,6 +87508,23 @@ class AgentProcessManager {
|
|
|
86733
87508
|
console.log(` ⚠️ Failed to emit sessionResumeFailed event: ${err.message}`);
|
|
86734
87509
|
}
|
|
86735
87510
|
}
|
|
87511
|
+
async emitSessionReopenRetry(chatroomId, role, attempt, error, harnessSessionId) {
|
|
87512
|
+
try {
|
|
87513
|
+
await this.deps.backend.mutation(api.machines.emitSessionReopenRetry, {
|
|
87514
|
+
sessionId: this.deps.sessionId,
|
|
87515
|
+
machineId: this.deps.machineId,
|
|
87516
|
+
chatroomId,
|
|
87517
|
+
role,
|
|
87518
|
+
attempt,
|
|
87519
|
+
maxAttempts: CURSOR_SDK_SESSION_REOPEN_MAX_ATTEMPTS,
|
|
87520
|
+
...error ? { error } : {},
|
|
87521
|
+
...harnessSessionId ? { harnessSessionId } : {}
|
|
87522
|
+
});
|
|
87523
|
+
console.log(`[AgentProcessManager] ✅ Emitted agent.sessionReopenRetry for ${role} (attempt ${attempt}/${CURSOR_SDK_SESSION_REOPEN_MAX_ATTEMPTS})`);
|
|
87524
|
+
} catch (err) {
|
|
87525
|
+
console.log(` ⚠️ Failed to emit sessionReopenRetry event: ${err.message}`);
|
|
87526
|
+
}
|
|
87527
|
+
}
|
|
86736
87528
|
resetSlotIdle(slot) {
|
|
86737
87529
|
slot.state = "idle";
|
|
86738
87530
|
slot.pendingOperation = undefined;
|
|
@@ -87110,7 +87902,6 @@ class AgentProcessManager {
|
|
|
87110
87902
|
}
|
|
87111
87903
|
var AGENT_EXIT_RETRY_INTERVAL_MS = 1e4;
|
|
87112
87904
|
var init_agent_process_manager = __esm(() => {
|
|
87113
|
-
init_generator();
|
|
87114
87905
|
init_types();
|
|
87115
87906
|
init_participant();
|
|
87116
87907
|
init_esm();
|
|
@@ -87136,7 +87927,7 @@ class SpawnRateLimiter {
|
|
|
87136
87927
|
this.config = { ...DEFAULT_CONFIG2, ...config3 };
|
|
87137
87928
|
}
|
|
87138
87929
|
tryConsume(chatroomId, reason) {
|
|
87139
|
-
if (reason.startsWith("user.") || reason === "platform.auto_restart_on_new_context") {
|
|
87930
|
+
if (reason.startsWith("user.") || reason === "platform.auto_restart_on_new_context" || reason === "platform.cursor_sdk_session_reopen") {
|
|
87140
87931
|
return { allowed: true };
|
|
87141
87932
|
}
|
|
87142
87933
|
const bucket = this._getOrCreateBucket(chatroomId);
|
|
@@ -87163,13 +87954,16 @@ class SpawnRateLimiter {
|
|
|
87163
87954
|
};
|
|
87164
87955
|
}
|
|
87165
87956
|
_getOrCreateBucket(chatroomId) {
|
|
87166
|
-
|
|
87167
|
-
|
|
87168
|
-
|
|
87169
|
-
lastRefillAt: Date.now()
|
|
87170
|
-
});
|
|
87957
|
+
const existing = this.buckets.get(chatroomId);
|
|
87958
|
+
if (existing) {
|
|
87959
|
+
return existing;
|
|
87171
87960
|
}
|
|
87172
|
-
|
|
87961
|
+
const bucket = {
|
|
87962
|
+
tokens: this.config.initialTokens,
|
|
87963
|
+
lastRefillAt: Date.now()
|
|
87964
|
+
};
|
|
87965
|
+
this.buckets.set(chatroomId, bucket);
|
|
87966
|
+
return bucket;
|
|
87173
87967
|
}
|
|
87174
87968
|
_refill(bucket) {
|
|
87175
87969
|
const now = Date.now();
|
|
@@ -88056,6 +88850,432 @@ var init_task_monitor_logic = __esm(() => {
|
|
|
88056
88850
|
init_predicates();
|
|
88057
88851
|
});
|
|
88058
88852
|
|
|
88853
|
+
// src/infrastructure/incremental-sync/working-snapshot.ts
|
|
88854
|
+
class WorkingSnapshot {
|
|
88855
|
+
opts;
|
|
88856
|
+
rows = new Map;
|
|
88857
|
+
constructor(opts) {
|
|
88858
|
+
this.opts = opts;
|
|
88859
|
+
}
|
|
88860
|
+
replaceAll(rows) {
|
|
88861
|
+
this.rows.clear();
|
|
88862
|
+
for (const row of rows) {
|
|
88863
|
+
this.rows.set(this.opts.rowKey(row), row);
|
|
88864
|
+
}
|
|
88865
|
+
}
|
|
88866
|
+
getByKey(key) {
|
|
88867
|
+
return this.rows.get(key);
|
|
88868
|
+
}
|
|
88869
|
+
getBySignal(signal) {
|
|
88870
|
+
return this.rows.get(this.opts.signalKey(signal));
|
|
88871
|
+
}
|
|
88872
|
+
mergeSignal(signal) {
|
|
88873
|
+
const key = this.opts.signalKey(signal);
|
|
88874
|
+
const merged = this.opts.mergeSignal(this.rows.get(key), signal);
|
|
88875
|
+
if (!merged) {
|
|
88876
|
+
return;
|
|
88877
|
+
}
|
|
88878
|
+
this.rows.set(key, merged);
|
|
88879
|
+
return merged;
|
|
88880
|
+
}
|
|
88881
|
+
}
|
|
88882
|
+
|
|
88883
|
+
// src/commands/machine/daemon-start/task-monitor-snapshot.ts
|
|
88884
|
+
function taskSnapshotKey(taskId, role) {
|
|
88885
|
+
return `${taskId}:${role}`;
|
|
88886
|
+
}
|
|
88887
|
+
function mergeSignalIntoTaskSnapshot(existing, signal) {
|
|
88888
|
+
if (!existing) {
|
|
88889
|
+
return;
|
|
88890
|
+
}
|
|
88891
|
+
return {
|
|
88892
|
+
...existing,
|
|
88893
|
+
status: signal.status,
|
|
88894
|
+
agentConfig: {
|
|
88895
|
+
...existing.agentConfig,
|
|
88896
|
+
spawnedAgentPid: signal.spawnedAgentPid ?? existing.agentConfig.spawnedAgentPid,
|
|
88897
|
+
desiredState: signal.desiredState ?? existing.agentConfig.desiredState
|
|
88898
|
+
},
|
|
88899
|
+
participant: {
|
|
88900
|
+
lastSeenAction: signal.lastSeenAction ?? existing.participant?.lastSeenAction ?? null,
|
|
88901
|
+
lastSeenAt: existing.participant?.lastSeenAt ?? null,
|
|
88902
|
+
lastStatus: existing.participant?.lastStatus ?? null
|
|
88903
|
+
}
|
|
88904
|
+
};
|
|
88905
|
+
}
|
|
88906
|
+
function createTaskMonitorSnapshot() {
|
|
88907
|
+
return new WorkingSnapshot(taskMonitorSnapshotOptions);
|
|
88908
|
+
}
|
|
88909
|
+
var taskMonitorSnapshotOptions;
|
|
88910
|
+
var init_task_monitor_snapshot = __esm(() => {
|
|
88911
|
+
taskMonitorSnapshotOptions = {
|
|
88912
|
+
rowKey: (row) => taskSnapshotKey(row.taskId, row.agentConfig.role),
|
|
88913
|
+
signalKey: (signal) => taskSnapshotKey(signal.taskId, signal.role),
|
|
88914
|
+
mergeSignal: mergeSignalIntoTaskSnapshot
|
|
88915
|
+
};
|
|
88916
|
+
});
|
|
88917
|
+
|
|
88918
|
+
// src/infrastructure/incremental-sync/layers.ts
|
|
88919
|
+
var IntervalClock, IntervalClockLive;
|
|
88920
|
+
var init_layers = __esm(() => {
|
|
88921
|
+
init_esm();
|
|
88922
|
+
IntervalClock = class IntervalClock extends exports_Context.Tag("IntervalClock")() {
|
|
88923
|
+
};
|
|
88924
|
+
IntervalClockLive = exports_Layer.succeed(IntervalClock, {
|
|
88925
|
+
sleep: (ms) => exports_Effect.promise(() => new Promise((resolve5) => setTimeout(resolve5, ms)))
|
|
88926
|
+
});
|
|
88927
|
+
});
|
|
88928
|
+
|
|
88929
|
+
// src/infrastructure/incremental-sync/message-buffer.ts
|
|
88930
|
+
class MessageBuffer {
|
|
88931
|
+
keyOf;
|
|
88932
|
+
queue = [];
|
|
88933
|
+
inBuffer = new Set;
|
|
88934
|
+
inFlight = new Map;
|
|
88935
|
+
recentlyAcked = new Map;
|
|
88936
|
+
dedupe;
|
|
88937
|
+
dedupeTtlMs;
|
|
88938
|
+
maxSize;
|
|
88939
|
+
constructor(config3, keyOf) {
|
|
88940
|
+
this.keyOf = keyOf;
|
|
88941
|
+
this.dedupe = config3.dedupe ?? true;
|
|
88942
|
+
this.dedupeTtlMs = config3.dedupeTtlMs ?? 0;
|
|
88943
|
+
this.maxSize = config3.maxSize;
|
|
88944
|
+
}
|
|
88945
|
+
enqueue(items) {
|
|
88946
|
+
this.pruneRecentlyAcked();
|
|
88947
|
+
let enqueued = 0;
|
|
88948
|
+
for (const item of items) {
|
|
88949
|
+
const key = this.keyOf(item);
|
|
88950
|
+
if (this.dedupe && this.shouldSkip(key)) {
|
|
88951
|
+
continue;
|
|
88952
|
+
}
|
|
88953
|
+
this.queue.push({ key, item });
|
|
88954
|
+
this.inBuffer.add(key);
|
|
88955
|
+
enqueued++;
|
|
88956
|
+
}
|
|
88957
|
+
if (enqueued > 0) {
|
|
88958
|
+
this.queue.sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
|
|
88959
|
+
}
|
|
88960
|
+
this.enforceMaxSize();
|
|
88961
|
+
return enqueued;
|
|
88962
|
+
}
|
|
88963
|
+
dequeue() {
|
|
88964
|
+
this.pruneRecentlyAcked();
|
|
88965
|
+
const next4 = this.queue.shift();
|
|
88966
|
+
if (!next4)
|
|
88967
|
+
return;
|
|
88968
|
+
this.inBuffer.delete(next4.key);
|
|
88969
|
+
this.inFlight.set(next4.key, next4.item);
|
|
88970
|
+
return next4.item;
|
|
88971
|
+
}
|
|
88972
|
+
ack(key) {
|
|
88973
|
+
this.inFlight.delete(key);
|
|
88974
|
+
if (this.dedupe) {
|
|
88975
|
+
this.recentlyAcked.set(key, Date.now());
|
|
88976
|
+
}
|
|
88977
|
+
}
|
|
88978
|
+
nack(key, requeue = false) {
|
|
88979
|
+
const item = this.inFlight.get(key);
|
|
88980
|
+
this.inFlight.delete(key);
|
|
88981
|
+
if (requeue && item !== undefined) {
|
|
88982
|
+
this.enqueue([item]);
|
|
88983
|
+
}
|
|
88984
|
+
}
|
|
88985
|
+
size() {
|
|
88986
|
+
return this.queue.length;
|
|
88987
|
+
}
|
|
88988
|
+
highKeyOf(items) {
|
|
88989
|
+
if (items.length === 0)
|
|
88990
|
+
return null;
|
|
88991
|
+
let high = null;
|
|
88992
|
+
for (const item of items) {
|
|
88993
|
+
const key = this.keyOf(item);
|
|
88994
|
+
if (high === null || key > high) {
|
|
88995
|
+
high = key;
|
|
88996
|
+
}
|
|
88997
|
+
}
|
|
88998
|
+
return high;
|
|
88999
|
+
}
|
|
89000
|
+
shouldSkip(key) {
|
|
89001
|
+
if (this.inBuffer.has(key) || this.inFlight.has(key)) {
|
|
89002
|
+
return true;
|
|
89003
|
+
}
|
|
89004
|
+
if (this.dedupeTtlMs > 0) {
|
|
89005
|
+
const ackedAt = this.recentlyAcked.get(key);
|
|
89006
|
+
if (ackedAt !== undefined && Date.now() - ackedAt < this.dedupeTtlMs) {
|
|
89007
|
+
return true;
|
|
89008
|
+
}
|
|
89009
|
+
} else if (this.recentlyAcked.has(key)) {
|
|
89010
|
+
return true;
|
|
89011
|
+
}
|
|
89012
|
+
return false;
|
|
89013
|
+
}
|
|
89014
|
+
pruneRecentlyAcked() {
|
|
89015
|
+
if (this.dedupeTtlMs <= 0)
|
|
89016
|
+
return;
|
|
89017
|
+
const now = Date.now();
|
|
89018
|
+
for (const [key, ackedAt] of this.recentlyAcked) {
|
|
89019
|
+
if (now - ackedAt >= this.dedupeTtlMs) {
|
|
89020
|
+
this.recentlyAcked.delete(key);
|
|
89021
|
+
}
|
|
89022
|
+
}
|
|
89023
|
+
}
|
|
89024
|
+
enforceMaxSize() {
|
|
89025
|
+
while (this.queue.length > this.maxSize) {
|
|
89026
|
+
const dropped = this.queue.shift();
|
|
89027
|
+
if (dropped) {
|
|
89028
|
+
this.inBuffer.delete(dropped.key);
|
|
89029
|
+
console.warn(`[incremental-sync] Buffer full — dropped oldest unacked item (key=${dropped.key})`);
|
|
89030
|
+
}
|
|
89031
|
+
}
|
|
89032
|
+
}
|
|
89033
|
+
}
|
|
89034
|
+
|
|
89035
|
+
// src/infrastructure/incremental-sync/resolve-high-key.ts
|
|
89036
|
+
function resolveHighKey(def, buffer, page) {
|
|
89037
|
+
if (page.highKey !== null)
|
|
89038
|
+
return page.highKey;
|
|
89039
|
+
const fromItems = buffer.highKeyOf(page.items);
|
|
89040
|
+
if (fromItems !== null)
|
|
89041
|
+
return fromItems;
|
|
89042
|
+
if (def.itemToKey && page.items.length > 0) {
|
|
89043
|
+
let high = null;
|
|
89044
|
+
for (const item of page.items) {
|
|
89045
|
+
const key = def.itemToKey(item);
|
|
89046
|
+
if (high === null || key > high)
|
|
89047
|
+
high = key;
|
|
89048
|
+
}
|
|
89049
|
+
return high;
|
|
89050
|
+
}
|
|
89051
|
+
return null;
|
|
89052
|
+
}
|
|
89053
|
+
|
|
89054
|
+
// src/infrastructure/incremental-sync/subscribe-loop.ts
|
|
89055
|
+
function startSubscribeLoop(opts) {
|
|
89056
|
+
let afterKey = opts.initialAfterKey ?? null;
|
|
89057
|
+
let stopped = false;
|
|
89058
|
+
let unsubscribe;
|
|
89059
|
+
let drainInFlight = false;
|
|
89060
|
+
const subscribe = () => {
|
|
89061
|
+
if (stopped)
|
|
89062
|
+
return;
|
|
89063
|
+
unsubscribe?.();
|
|
89064
|
+
unsubscribe = opts.wsClient.onUpdate(opts.target.query, opts.target.buildArgs(opts.args, afterKey, opts.config.limit), (result) => {
|
|
89065
|
+
if (stopped)
|
|
89066
|
+
return;
|
|
89067
|
+
const page = opts.target.parsePage(result);
|
|
89068
|
+
drainPages(page);
|
|
89069
|
+
}, (err) => {
|
|
89070
|
+
opts.onError?.(err);
|
|
89071
|
+
});
|
|
89072
|
+
};
|
|
89073
|
+
const fetchPage = async (cursor) => {
|
|
89074
|
+
const result = await opts.wsClient.query(opts.target.query, opts.target.buildArgs(opts.args, cursor, opts.config.limit));
|
|
89075
|
+
return opts.target.parsePage(result);
|
|
89076
|
+
};
|
|
89077
|
+
const drainPages = async (initialPage) => {
|
|
89078
|
+
if (stopped || drainInFlight)
|
|
89079
|
+
return;
|
|
89080
|
+
drainInFlight = true;
|
|
89081
|
+
try {
|
|
89082
|
+
const cursorAtStart = afterKey;
|
|
89083
|
+
let page = initialPage;
|
|
89084
|
+
while (!stopped && page.items.length > 0) {
|
|
89085
|
+
opts.buffer.enqueue(page.items);
|
|
89086
|
+
const nextKey = resolveHighKey(opts.def, opts.buffer, page);
|
|
89087
|
+
if (nextKey === null) {
|
|
89088
|
+
break;
|
|
89089
|
+
}
|
|
89090
|
+
afterKey = nextKey;
|
|
89091
|
+
if (!page.hasMore) {
|
|
89092
|
+
break;
|
|
89093
|
+
}
|
|
89094
|
+
page = await fetchPage(afterKey);
|
|
89095
|
+
}
|
|
89096
|
+
if (!stopped && afterKey !== cursorAtStart) {
|
|
89097
|
+
subscribe();
|
|
89098
|
+
}
|
|
89099
|
+
} catch (err) {
|
|
89100
|
+
opts.onError?.(err);
|
|
89101
|
+
} finally {
|
|
89102
|
+
drainInFlight = false;
|
|
89103
|
+
}
|
|
89104
|
+
};
|
|
89105
|
+
subscribe();
|
|
89106
|
+
return {
|
|
89107
|
+
stop: () => {
|
|
89108
|
+
stopped = true;
|
|
89109
|
+
unsubscribe?.();
|
|
89110
|
+
unsubscribe = undefined;
|
|
89111
|
+
},
|
|
89112
|
+
getAfterKey: () => afterKey
|
|
89113
|
+
};
|
|
89114
|
+
}
|
|
89115
|
+
var init_subscribe_loop = () => {};
|
|
89116
|
+
|
|
89117
|
+
// src/infrastructure/incremental-sync/feed-runtime.ts
|
|
89118
|
+
function runWorkerLoop(feedName, buffer, keyOf, onItem) {
|
|
89119
|
+
return exports_Effect.gen(function* () {
|
|
89120
|
+
while (true) {
|
|
89121
|
+
const item = buffer.dequeue();
|
|
89122
|
+
if (item === undefined) {
|
|
89123
|
+
yield* exports_Effect.sleep("10 millis");
|
|
89124
|
+
continue;
|
|
89125
|
+
}
|
|
89126
|
+
const key = keyOf(item);
|
|
89127
|
+
const ctx = {
|
|
89128
|
+
item,
|
|
89129
|
+
feedName,
|
|
89130
|
+
ack: () => buffer.ack(key),
|
|
89131
|
+
nack: (opts) => buffer.nack(key, opts?.requeue ?? false)
|
|
89132
|
+
};
|
|
89133
|
+
yield* onItem(ctx).pipe(exports_Effect.catchAll(() => exports_Effect.void));
|
|
89134
|
+
}
|
|
89135
|
+
});
|
|
89136
|
+
}
|
|
89137
|
+
var runIncrementalSubscribeLive = (opts) => exports_Effect.gen(function* () {
|
|
89138
|
+
const buffer = new MessageBuffer(opts.buffer, opts.def.itemKey);
|
|
89139
|
+
const subscribeHandle = startSubscribeLoop({
|
|
89140
|
+
wsClient: opts.wsClient,
|
|
89141
|
+
target: opts.target,
|
|
89142
|
+
args: opts.args,
|
|
89143
|
+
buffer,
|
|
89144
|
+
def: opts.def,
|
|
89145
|
+
config: opts.subscribe,
|
|
89146
|
+
initialAfterKey: opts.initialAfterKey ?? null,
|
|
89147
|
+
onError: opts.onError
|
|
89148
|
+
});
|
|
89149
|
+
const workerFiber = yield* exports_Effect.forkDaemon(runWorkerLoop(opts.def.name, buffer, opts.def.itemKey, opts.onItem));
|
|
89150
|
+
return {
|
|
89151
|
+
buffer,
|
|
89152
|
+
stop: () => exports_Effect.gen(function* () {
|
|
89153
|
+
subscribeHandle.stop();
|
|
89154
|
+
yield* exports_Fiber.interrupt(workerFiber);
|
|
89155
|
+
})
|
|
89156
|
+
};
|
|
89157
|
+
}), runReconcilePoll = (opts) => exports_Effect.gen(function* () {
|
|
89158
|
+
const clock4 = yield* IntervalClock;
|
|
89159
|
+
const backoffCfg = opts.backoff ?? { initialMs: 1000, maxMs: 30000 };
|
|
89160
|
+
let backoffMs = opts.intervalMs;
|
|
89161
|
+
let stopped = false;
|
|
89162
|
+
const loopFiber = yield* exports_Effect.forkDaemon(exports_Effect.gen(function* () {
|
|
89163
|
+
while (!stopped) {
|
|
89164
|
+
const pollOutcome = yield* exports_Effect.either(exports_Effect.tryPromise(() => opts.poll(opts.args)));
|
|
89165
|
+
if (pollOutcome._tag === "Left") {
|
|
89166
|
+
backoffMs = Math.min(backoffMs === opts.intervalMs ? backoffCfg.initialMs : backoffMs * 2, backoffCfg.maxMs);
|
|
89167
|
+
yield* clock4.sleep(backoffMs);
|
|
89168
|
+
continue;
|
|
89169
|
+
}
|
|
89170
|
+
yield* opts.onResult(pollOutcome.right);
|
|
89171
|
+
backoffMs = opts.intervalMs;
|
|
89172
|
+
yield* clock4.sleep(opts.intervalMs);
|
|
89173
|
+
}
|
|
89174
|
+
}));
|
|
89175
|
+
return {
|
|
89176
|
+
stop: () => exports_Effect.gen(function* () {
|
|
89177
|
+
stopped = true;
|
|
89178
|
+
yield* exports_Fiber.interrupt(loopFiber);
|
|
89179
|
+
})
|
|
89180
|
+
};
|
|
89181
|
+
}), runReconcilePollLive = (opts) => runReconcilePoll(opts).pipe(exports_Effect.provide(IntervalClockLive));
|
|
89182
|
+
var init_feed_runtime = __esm(() => {
|
|
89183
|
+
init_esm();
|
|
89184
|
+
init_layers();
|
|
89185
|
+
init_subscribe_loop();
|
|
89186
|
+
});
|
|
89187
|
+
|
|
89188
|
+
// src/infrastructure/incremental-sync/dual-channel-feed.ts
|
|
89189
|
+
var runDualChannelFeedLive = (opts) => exports_Effect.gen(function* () {
|
|
89190
|
+
const initial = yield* exports_Effect.tryPromise(() => opts.fetchReconcile()).pipe(exports_Effect.orElseSucceed(() => null));
|
|
89191
|
+
if (initial !== null) {
|
|
89192
|
+
const rows = opts.extractReconcileRows(initial);
|
|
89193
|
+
opts.snapshot.replaceAll(rows);
|
|
89194
|
+
if (rows.length > 0) {
|
|
89195
|
+
yield* opts.onReconcileRows(rows).pipe(exports_Effect.catchAll(() => exports_Effect.void));
|
|
89196
|
+
}
|
|
89197
|
+
}
|
|
89198
|
+
const seedKey = yield* exports_Effect.tryPromise(() => opts.seedCursor()).pipe(exports_Effect.orElseSucceed(() => null));
|
|
89199
|
+
const hydrateFromReconcile = async () => {
|
|
89200
|
+
const result = await opts.fetchReconcile();
|
|
89201
|
+
opts.snapshot.replaceAll(opts.extractReconcileRows(result));
|
|
89202
|
+
};
|
|
89203
|
+
const resolveRowForSignal = async (signal) => {
|
|
89204
|
+
const merged = opts.snapshot.mergeSignal(signal);
|
|
89205
|
+
if (merged) {
|
|
89206
|
+
return merged;
|
|
89207
|
+
}
|
|
89208
|
+
await hydrateFromReconcile();
|
|
89209
|
+
return opts.snapshot.mergeSignal(signal) ?? opts.snapshot.getBySignal(signal);
|
|
89210
|
+
};
|
|
89211
|
+
const signalHandle = yield* runIncrementalSubscribeLive({
|
|
89212
|
+
wsClient: opts.wsClient,
|
|
89213
|
+
def: opts.def,
|
|
89214
|
+
target: opts.target,
|
|
89215
|
+
args: opts.args,
|
|
89216
|
+
buffer: opts.buffer,
|
|
89217
|
+
subscribe: opts.subscribe,
|
|
89218
|
+
initialAfterKey: seedKey,
|
|
89219
|
+
onError: opts.onSubscribeError,
|
|
89220
|
+
onItem: ({ item: signal, ack }) => exports_Effect.gen(function* () {
|
|
89221
|
+
ack();
|
|
89222
|
+
if (opts.isStopped()) {
|
|
89223
|
+
return;
|
|
89224
|
+
}
|
|
89225
|
+
const row = yield* exports_Effect.tryPromise(() => resolveRowForSignal(signal));
|
|
89226
|
+
if (!row) {
|
|
89227
|
+
return;
|
|
89228
|
+
}
|
|
89229
|
+
yield* opts.onSignalRow(row).pipe(exports_Effect.catchAll(() => exports_Effect.void));
|
|
89230
|
+
})
|
|
89231
|
+
});
|
|
89232
|
+
const reconcileHandle = yield* runReconcilePollLive({
|
|
89233
|
+
name: `${opts.name}-reconcile`,
|
|
89234
|
+
poll: () => opts.fetchReconcile(),
|
|
89235
|
+
args: undefined,
|
|
89236
|
+
intervalMs: opts.reconcileIntervalMs,
|
|
89237
|
+
onResult: (result) => exports_Effect.gen(function* () {
|
|
89238
|
+
const rows = opts.extractReconcileRows(result);
|
|
89239
|
+
opts.snapshot.replaceAll(rows);
|
|
89240
|
+
yield* opts.onReconcileRows(rows).pipe(exports_Effect.catchAll(() => exports_Effect.void));
|
|
89241
|
+
})
|
|
89242
|
+
});
|
|
89243
|
+
return {
|
|
89244
|
+
stop: () => exports_Effect.gen(function* () {
|
|
89245
|
+
yield* signalHandle.stop();
|
|
89246
|
+
yield* reconcileHandle.stop();
|
|
89247
|
+
})
|
|
89248
|
+
};
|
|
89249
|
+
});
|
|
89250
|
+
var init_dual_channel_feed = __esm(() => {
|
|
89251
|
+
init_esm();
|
|
89252
|
+
init_feed_runtime();
|
|
89253
|
+
});
|
|
89254
|
+
|
|
89255
|
+
// src/infrastructure/incremental-sync/feeds/assigned-task-signals.ts
|
|
89256
|
+
var assignedTaskSignalsFeedDef, assignedTaskSignalsSubscribeTarget, ASSIGNED_TASK_SIGNAL_FEED_LIMIT = 50, ASSIGNED_TASK_SIGNAL_FEED_BUFFER, ASSIGNED_TASK_RECONCILE_INTERVAL_MS = 15000;
|
|
89257
|
+
var init_assigned_task_signals = __esm(() => {
|
|
89258
|
+
init_api3();
|
|
89259
|
+
assignedTaskSignalsFeedDef = {
|
|
89260
|
+
name: "assigned-task-signals",
|
|
89261
|
+
itemKey: (item) => item.revisionKey
|
|
89262
|
+
};
|
|
89263
|
+
assignedTaskSignalsSubscribeTarget = {
|
|
89264
|
+
query: api.machines.subscribeAssignedTaskSignalsSince,
|
|
89265
|
+
buildArgs: (args2, afterKey, limit) => ({
|
|
89266
|
+
sessionId: args2.sessionId,
|
|
89267
|
+
machineId: args2.machineId,
|
|
89268
|
+
afterKey: afterKey ?? undefined,
|
|
89269
|
+
limit
|
|
89270
|
+
}),
|
|
89271
|
+
parsePage: (result) => result
|
|
89272
|
+
};
|
|
89273
|
+
ASSIGNED_TASK_SIGNAL_FEED_BUFFER = {
|
|
89274
|
+
maxSize: 200,
|
|
89275
|
+
dedupe: true
|
|
89276
|
+
};
|
|
89277
|
+
});
|
|
89278
|
+
|
|
88059
89279
|
// src/commands/machine/daemon-start/task-monitor.ts
|
|
88060
89280
|
function resolveTaskWantResume(task) {
|
|
88061
89281
|
return compressContextToWantResume(parseCompressContext(task.taskContent ?? ""));
|
|
@@ -88068,7 +89288,7 @@ function buildCliNudgeLogLine(task) {
|
|
|
88068
89288
|
const wantResume = resolveTaskWantResume(task);
|
|
88069
89289
|
return `[TaskMonitor] nudging ${role}@${chatroomId} — pending task ${task.taskId}, lastSeenAction=${lastSeenAction}, compress_context=${compressMode}, wantResume=${wantResume}`;
|
|
88070
89290
|
}
|
|
88071
|
-
function
|
|
89291
|
+
function resolveTaskRunnerContextFromFull(task) {
|
|
88072
89292
|
const { chatroomId, agentConfig } = task;
|
|
88073
89293
|
const { role } = agentConfig;
|
|
88074
89294
|
const workingDir = agentConfig.workingDir;
|
|
@@ -88083,7 +89303,7 @@ function resolveTaskRunnerContext(task) {
|
|
|
88083
89303
|
};
|
|
88084
89304
|
}
|
|
88085
89305
|
function executeCliNudge(task, runtime4, effectContext2, agentMgr) {
|
|
88086
|
-
const ctx =
|
|
89306
|
+
const ctx = resolveTaskRunnerContextFromFull(task);
|
|
88087
89307
|
if (!ctx)
|
|
88088
89308
|
return;
|
|
88089
89309
|
const { chatroomId, agentConfig, role, workingDir, wantResume } = ctx;
|
|
@@ -88101,7 +89321,7 @@ function executeCliNudge(task, runtime4, effectContext2, agentMgr) {
|
|
|
88101
89321
|
}).pipe(exports_Effect.provide(effectContext2), exports_Effect.catchAll((err) => exports_Effect.sync(() => console.warn(`[TaskMonitor] nudge failed for ${role}@${chatroomId}: ${getErrorMessage(err)}`)))));
|
|
88102
89322
|
}
|
|
88103
89323
|
function runNativeReviveEffect(task, runtime4, effectContext2, agentMgr) {
|
|
88104
|
-
const ctx =
|
|
89324
|
+
const ctx = resolveTaskRunnerContextFromFull(task);
|
|
88105
89325
|
if (!ctx)
|
|
88106
89326
|
return;
|
|
88107
89327
|
const { chatroomId, agentConfig, role, workingDir, wantResume } = ctx;
|
|
@@ -88118,63 +89338,124 @@ function runNativeReviveEffect(task, runtime4, effectContext2, agentMgr) {
|
|
|
88118
89338
|
});
|
|
88119
89339
|
}).pipe(exports_Effect.provide(effectContext2), exports_Effect.catchAll((err) => exports_Effect.sync(() => console.warn(`[TaskMonitor] native revive failed for ${role}@${chatroomId}: ${getErrorMessage(err)}`)))));
|
|
88120
89340
|
}
|
|
89341
|
+
async function fetchTaskForAction(sessionDeps, machineId, snapshotRow) {
|
|
89342
|
+
const result = await sessionDeps.backend.query(api.machines.getAssignedTaskForAction, {
|
|
89343
|
+
sessionId: sessionDeps.sessionId,
|
|
89344
|
+
machineId,
|
|
89345
|
+
taskId: snapshotRow.taskId,
|
|
89346
|
+
role: snapshotRow.agentConfig.role
|
|
89347
|
+
});
|
|
89348
|
+
return result;
|
|
89349
|
+
}
|
|
88121
89350
|
function runCliNudgeEffect(task, runtime4, effectContext2, agentMgr) {
|
|
88122
89351
|
console.log(buildCliNudgeLogLine(task));
|
|
88123
89352
|
executeCliNudge(task, runtime4, effectContext2, agentMgr);
|
|
88124
89353
|
}
|
|
88125
|
-
function nudgeStuckTasks(tasks, now, cooldown, runtime4, effectContext2, agentMgr) {
|
|
88126
|
-
for (const
|
|
88127
|
-
|
|
89354
|
+
async function nudgeStuckTasks(tasks, now, cooldown, runtime4, effectContext2, agentMgr, sessionDeps, machineId) {
|
|
89355
|
+
for (const row of listTasksReadyForNudge(tasks, now, cooldown)) {
|
|
89356
|
+
const full = await fetchTaskForAction(sessionDeps, machineId, row);
|
|
89357
|
+
if (!full)
|
|
89358
|
+
continue;
|
|
89359
|
+
runCliNudgeEffect(full, runtime4, effectContext2, agentMgr);
|
|
88128
89360
|
}
|
|
88129
89361
|
}
|
|
88130
|
-
function reviveNativeTasks(tasks, localHealth, now, cooldown, runtime4, effectContext2, agentMgr) {
|
|
88131
|
-
for (const
|
|
88132
|
-
|
|
89362
|
+
async function reviveNativeTasks(tasks, localHealth, now, cooldown, runtime4, effectContext2, agentMgr, sessionDeps, machineId) {
|
|
89363
|
+
for (const row of listNativeTasksNeedingRevive(tasks, localHealth, now, cooldown)) {
|
|
89364
|
+
const full = await fetchTaskForAction(sessionDeps, machineId, row);
|
|
89365
|
+
if (!full)
|
|
89366
|
+
continue;
|
|
89367
|
+
runNativeReviveEffect(full, runtime4, effectContext2, agentMgr);
|
|
88133
89368
|
}
|
|
88134
89369
|
}
|
|
88135
|
-
function processTasksUpdate(tasks, runtime4, effectContext2, cooldown, agentMgr, sessionDeps) {
|
|
89370
|
+
async function processTasksUpdate(tasks, runtime4, effectContext2, cooldown, agentMgr, sessionDeps, machineId, pass) {
|
|
89371
|
+
if (tasks.length === 0)
|
|
89372
|
+
return;
|
|
88136
89373
|
const now = Date.now();
|
|
88137
89374
|
const localHealth = {
|
|
88138
89375
|
getSlot: (chatroomId, role) => agentMgr.getSlot(chatroomId, role),
|
|
88139
89376
|
isPidAlive: (pid) => isProcessAlive((p) => process.kill(p, 0), pid)
|
|
88140
89377
|
};
|
|
88141
|
-
reviveNativeTasks(tasks, localHealth, now, cooldown, runtime4, effectContext2, agentMgr);
|
|
89378
|
+
await reviveNativeTasks(tasks, localHealth, now, cooldown, runtime4, effectContext2, agentMgr, sessionDeps, machineId);
|
|
88142
89379
|
getNativeTaskDeliveryCoordinator().reconcileAssignedTasks({
|
|
88143
89380
|
tasks,
|
|
88144
89381
|
runtime: runtime4,
|
|
88145
89382
|
effectContext: effectContext2,
|
|
88146
89383
|
agentMgr,
|
|
88147
|
-
sessionDeps
|
|
89384
|
+
sessionDeps,
|
|
89385
|
+
machineId
|
|
88148
89386
|
});
|
|
88149
|
-
|
|
89387
|
+
if (pass === "reconcile") {
|
|
89388
|
+
await nudgeStuckTasks(tasks, now, cooldown, runtime4, effectContext2, agentMgr, sessionDeps, machineId);
|
|
89389
|
+
}
|
|
88150
89390
|
}
|
|
88151
|
-
var
|
|
89391
|
+
var startTaskMonitorEffect = (wsClient2) => exports_Effect.gen(function* () {
|
|
88152
89392
|
const session2 = yield* DaemonSessionService;
|
|
88153
89393
|
const agentMgr = yield* DaemonAgentProcessManagerService;
|
|
88154
89394
|
const effectContext2 = yield* exports_Effect.context();
|
|
88155
89395
|
const runtime4 = yield* exports_Effect.runtime();
|
|
88156
|
-
console.log(`[${formatTimestamp()}] \uD83D\uDCCB Starting task-monitor
|
|
89396
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDCCB Starting task-monitor (incremental subscribe)`);
|
|
88157
89397
|
const cooldown = new NudgeCooldown;
|
|
89398
|
+
const snapshot = createTaskMonitorSnapshot();
|
|
88158
89399
|
let stopped = false;
|
|
89400
|
+
let monitorPassInFlight = false;
|
|
88159
89401
|
const sessionDeps = {
|
|
88160
89402
|
sessionId: session2.sessionId,
|
|
88161
89403
|
convexUrl: session2.convexUrl,
|
|
89404
|
+
machineId: session2.machineId,
|
|
88162
89405
|
backend: {
|
|
88163
89406
|
mutation: (fn2, args2) => session2.backend.mutation(fn2, args2),
|
|
88164
89407
|
query: (fn2, args2) => session2.backend.query(fn2, args2)
|
|
88165
89408
|
}
|
|
88166
89409
|
};
|
|
88167
|
-
const
|
|
88168
|
-
if (stopped ||
|
|
89410
|
+
const runMonitorPass = (tasks, pass) => {
|
|
89411
|
+
if (stopped || monitorPassInFlight || tasks.length === 0)
|
|
88169
89412
|
return;
|
|
88170
|
-
|
|
89413
|
+
monitorPassInFlight = true;
|
|
89414
|
+
processTasksUpdate(tasks, runtime4, effectContext2, cooldown, agentMgr, sessionDeps, session2.machineId, pass).finally(() => {
|
|
89415
|
+
monitorPassInFlight = false;
|
|
89416
|
+
});
|
|
88171
89417
|
};
|
|
88172
|
-
const
|
|
89418
|
+
const queryReconcileSnapshots = () => session2.backend.query(api.machines.listAssignedTasksForReconcile, {
|
|
89419
|
+
sessionId: session2.sessionId,
|
|
89420
|
+
machineId: session2.machineId
|
|
89421
|
+
});
|
|
89422
|
+
const feedHandle = yield* runDualChannelFeedLive({
|
|
89423
|
+
name: "assigned-tasks",
|
|
89424
|
+
wsClient: wsClient2,
|
|
89425
|
+
def: assignedTaskSignalsFeedDef,
|
|
89426
|
+
target: assignedTaskSignalsSubscribeTarget,
|
|
89427
|
+
args: {
|
|
89428
|
+
sessionId: session2.sessionId,
|
|
89429
|
+
machineId: session2.machineId
|
|
89430
|
+
},
|
|
89431
|
+
buffer: ASSIGNED_TASK_SIGNAL_FEED_BUFFER,
|
|
89432
|
+
subscribe: { limit: ASSIGNED_TASK_SIGNAL_FEED_LIMIT },
|
|
89433
|
+
snapshot,
|
|
89434
|
+
seedCursor: async () => {
|
|
89435
|
+
const seedPage = await session2.backend.query(api.machines.subscribeAssignedTaskSignalsSince, {
|
|
89436
|
+
sessionId: session2.sessionId,
|
|
89437
|
+
machineId: session2.machineId,
|
|
89438
|
+
limit: ASSIGNED_TASK_SIGNAL_FEED_LIMIT
|
|
89439
|
+
});
|
|
89440
|
+
return seedPage?.highKey ?? null;
|
|
89441
|
+
},
|
|
89442
|
+
fetchReconcile: () => queryReconcileSnapshots(),
|
|
89443
|
+
extractReconcileRows: (result) => result?.tasks ?? [],
|
|
89444
|
+
reconcileIntervalMs: ASSIGNED_TASK_RECONCILE_INTERVAL_MS,
|
|
89445
|
+
isStopped: () => stopped,
|
|
89446
|
+
onSubscribeError: (err) => console.warn(`[${formatTimestamp()}] ⚠️ Task signal subscription error: ${getErrorMessage(err)}`),
|
|
89447
|
+
onSignalRow: (row) => exports_Effect.sync(() => {
|
|
89448
|
+
runMonitorPass([row], "signal");
|
|
89449
|
+
}),
|
|
89450
|
+
onReconcileRows: (tasks) => exports_Effect.sync(() => {
|
|
89451
|
+
runMonitorPass([...tasks], "reconcile");
|
|
89452
|
+
})
|
|
89453
|
+
});
|
|
88173
89454
|
return {
|
|
88174
89455
|
stop() {
|
|
88175
89456
|
stopped = true;
|
|
88176
|
-
|
|
88177
|
-
console.log(`[${formatTimestamp()}] \uD83D\uDCCB Task-monitor
|
|
89457
|
+
exports_Effect.runPromise(feedHandle.stop());
|
|
89458
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDCCB Task-monitor stopped`);
|
|
88178
89459
|
}
|
|
88179
89460
|
};
|
|
88180
89461
|
});
|
|
@@ -88184,7 +89465,10 @@ var init_task_monitor = __esm(() => {
|
|
|
88184
89465
|
init_daemon_services();
|
|
88185
89466
|
init_native_task_delivery_coordinator();
|
|
88186
89467
|
init_task_monitor_logic();
|
|
89468
|
+
init_task_monitor_snapshot();
|
|
88187
89469
|
init_api3();
|
|
89470
|
+
init_dual_channel_feed();
|
|
89471
|
+
init_assigned_task_signals();
|
|
88188
89472
|
init_convex_error();
|
|
88189
89473
|
});
|
|
88190
89474
|
|
|
@@ -88387,6 +89671,11 @@ function handleRefreshCapabilitiesEffect(event, tracker) {
|
|
|
88387
89671
|
})));
|
|
88388
89672
|
});
|
|
88389
89673
|
}
|
|
89674
|
+
function forkDaemonSyncBatch(runtime4, effectContext2, failureLabel) {
|
|
89675
|
+
exports_Runtime.runFork(runtime4)(exports_Effect.all([pushGitStateEffect, pushCommandsEffect, syncCommitDetailsEffect()], {
|
|
89676
|
+
concurrency: "unbounded"
|
|
89677
|
+
}).pipe(exports_Effect.provide(effectContext2), exports_Effect.catchAll((err) => exports_Effect.sync(() => console.warn(`[${formatTimestamp()}] ⚠️ ${failureLabel}: ${getErrorMessage(err)}`)))));
|
|
89678
|
+
}
|
|
88390
89679
|
var GIT_PUSH_ACTIONS, commandEventHandlers, dispatchCommandEventEffect = (event, tracker) => {
|
|
88391
89680
|
const factory2 = commandEventHandlers[event.type];
|
|
88392
89681
|
return factory2 != null ? factory2(event, tracker) : exports_Effect.void;
|
|
@@ -88445,9 +89734,7 @@ var init_command_loop = __esm(() => {
|
|
|
88445
89734
|
heartbeatCount++;
|
|
88446
89735
|
console.log(`[${formatTimestamp()}] \uD83D\uDC93 Daemon heartbeat #${heartbeatCount} OK`);
|
|
88447
89736
|
if (!observedSyncEnabled) {
|
|
88448
|
-
|
|
88449
|
-
concurrency: "unbounded"
|
|
88450
|
-
}).pipe(exports_Effect.provide(effectContext2), exports_Effect.catchAll((err) => exports_Effect.sync(() => console.warn(`[${formatTimestamp()}] ⚠️ Heartbeat sync failed: ${getErrorMessage(err)}`)))));
|
|
89737
|
+
forkDaemonSyncBatch(runtime4, effectContext2, "Heartbeat sync failed");
|
|
88451
89738
|
}
|
|
88452
89739
|
}).catch((err) => {
|
|
88453
89740
|
console.warn(`[${formatTimestamp()}] ⚠️ Daemon heartbeat failed: ${getErrorMessage(err)}`);
|
|
@@ -88464,14 +89751,13 @@ var init_command_loop = __esm(() => {
|
|
|
88464
89751
|
let pendingHarnessSessionSubscriptionHandle = null;
|
|
88465
89752
|
let commandSubscriptionHandle = null;
|
|
88466
89753
|
let lifecycleManager = null;
|
|
89754
|
+
let closeDirectHarnessSessionsOnShutdown = null;
|
|
88467
89755
|
const activeSessions = new Map;
|
|
88468
89756
|
const harnesses = new Map;
|
|
88469
89757
|
if (observedSyncEnabled) {
|
|
88470
89758
|
console.log(`[${formatTimestamp()}] \uD83D\uDC41️ Observed-sync enabled, skipping immediate push`);
|
|
88471
89759
|
} else {
|
|
88472
|
-
|
|
88473
|
-
concurrency: "unbounded"
|
|
88474
|
-
}).pipe(exports_Effect.provide(effectContext2), exports_Effect.catchAll((err) => exports_Effect.sync(() => console.warn(`[${formatTimestamp()}] ⚠️ Startup sync failed: ${getErrorMessage(err)}`)))));
|
|
89760
|
+
forkDaemonSyncBatch(runtime4, effectContext2, "Startup sync failed");
|
|
88475
89761
|
}
|
|
88476
89762
|
const PROCESS_KILL_TIMEOUT_MS = 6000;
|
|
88477
89763
|
const CLOSE_TIMEOUT_MS = 3000;
|
|
@@ -88539,8 +89825,12 @@ var init_command_loop = __esm(() => {
|
|
|
88539
89825
|
await withTimeout2(exports_Effect.runPromise(onDaemonShutdownEffect.pipe(exports_Effect.provide(effectContext2))), PROCESS_KILL_TIMEOUT_MS);
|
|
88540
89826
|
};
|
|
88541
89827
|
const closeAllSessionsAndHarnesses = async () => {
|
|
88542
|
-
|
|
88543
|
-
await withTimeout2(
|
|
89828
|
+
if (closeDirectHarnessSessionsOnShutdown) {
|
|
89829
|
+
await withTimeout2(closeDirectHarnessSessionsOnShutdown(), PROCESS_KILL_TIMEOUT_MS);
|
|
89830
|
+
} else {
|
|
89831
|
+
for (const handle of activeSessions.values()) {
|
|
89832
|
+
await withTimeout2(handle.close(), CLOSE_TIMEOUT_MS);
|
|
89833
|
+
}
|
|
88544
89834
|
}
|
|
88545
89835
|
for (const harness of harnesses.values()) {
|
|
88546
89836
|
await withTimeout2(harness.close(), CLOSE_TIMEOUT_MS);
|
|
@@ -88570,7 +89860,7 @@ var init_command_loop = __esm(() => {
|
|
|
88570
89860
|
if (observedSyncEnabled) {
|
|
88571
89861
|
observedSyncSubscriptionHandle = yield* startObservedSyncSubscriptionEffect(wsClient2);
|
|
88572
89862
|
}
|
|
88573
|
-
const taskMonitorHandle = yield*
|
|
89863
|
+
const taskMonitorHandle = yield* startTaskMonitorEffect(wsClient2);
|
|
88574
89864
|
logObserverSubscriptionHandle = startLogObserverSubscription({ sessionId: session2.sessionId, machineId: session2.machineId }, wsClient2);
|
|
88575
89865
|
if (featureFlags.directHarnessWorkers) {
|
|
88576
89866
|
const handles = startDirectHarnessSubscriptions({
|
|
@@ -88583,6 +89873,7 @@ var init_command_loop = __esm(() => {
|
|
|
88583
89873
|
pendingHarnessSessionSubscriptionHandle = handles.pendingHarnessSessionSubscriptionHandle;
|
|
88584
89874
|
commandSubscriptionHandle = handles.commandSubscriptionHandle;
|
|
88585
89875
|
lifecycleManager = handles.lifecycleManager;
|
|
89876
|
+
closeDirectHarnessSessionsOnShutdown = handles.closeSessionsOnShutdown;
|
|
88586
89877
|
}
|
|
88587
89878
|
console.log(`
|
|
88588
89879
|
Listening for commands...`);
|
|
@@ -88769,8 +90060,8 @@ import * as os2 from "os";
|
|
|
88769
90060
|
import * as path4 from "path";
|
|
88770
90061
|
async function isChatroomInstalledDefault() {
|
|
88771
90062
|
try {
|
|
88772
|
-
const { execSync:
|
|
88773
|
-
|
|
90063
|
+
const { execSync: execSync3 } = await import("child_process");
|
|
90064
|
+
execSync3("chatroom --version", { stdio: "pipe" });
|
|
88774
90065
|
return true;
|
|
88775
90066
|
} catch {
|
|
88776
90067
|
return false;
|
|
@@ -89684,4 +90975,4 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
89684
90975
|
});
|
|
89685
90976
|
program2.parse();
|
|
89686
90977
|
|
|
89687
|
-
//# debugId=
|
|
90978
|
+
//# debugId=00A3989CD8BAD93D64756E2164756E21
|