@adhdev/daemon-core 0.9.82-rc.169 → 0.9.82-rc.170
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/cli-adapter-types.d.ts +3 -0
- package/dist/cli-adapters/provider-cli-adapter.d.ts +2 -0
- package/dist/cli-adapters/provider-cli-shared.d.ts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +474 -74
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +467 -74
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-events.d.ts +19 -0
- package/dist/providers/cli-provider-instance.d.ts +2 -1
- package/dist/providers/provider-instance.d.ts +3 -0
- package/dist/providers/spec/cli-adapter.d.ts +10 -0
- package/dist/providers/spec/driver.d.ts +1 -0
- package/dist/providers/types/interactive-prompt.d.ts +48 -0
- package/dist/shared-types.d.ts +3 -0
- package/package.json +1 -1
- package/src/cli-adapter-types.ts +3 -0
- package/src/cli-adapters/provider-cli-adapter.ts +6 -0
- package/src/cli-adapters/provider-cli-shared.ts +2 -0
- package/src/index.ts +15 -0
- package/src/mesh/mesh-events.ts +41 -0
- package/src/providers/cli-provider-instance.ts +61 -12
- package/src/providers/provider-instance.ts +3 -0
- package/src/providers/spec/cli-adapter.ts +109 -6
- package/src/providers/spec/driver.ts +4 -0
- package/src/providers/types/interactive-prompt.ts +297 -0
- package/src/shared-types.ts +3 -0
- package/src/status/builders.ts +1 -0
package/dist/index.js
CHANGED
|
@@ -682,7 +682,7 @@ var init_config = __esm({
|
|
|
682
682
|
function readObject(value) {
|
|
683
683
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
684
684
|
}
|
|
685
|
-
function
|
|
685
|
+
function readString2(value) {
|
|
686
686
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
687
687
|
}
|
|
688
688
|
function normalizeMeshDaemonRole(value) {
|
|
@@ -699,9 +699,9 @@ function resolveMeshHostStatus(mesh) {
|
|
|
699
699
|
canOwnQueue: role === "host",
|
|
700
700
|
defaulted: !raw
|
|
701
701
|
};
|
|
702
|
-
const hostDaemonId =
|
|
703
|
-
const hostNodeId =
|
|
704
|
-
const hostAddress =
|
|
702
|
+
const hostDaemonId = readString2(raw?.hostDaemonId);
|
|
703
|
+
const hostNodeId = readString2(raw?.hostNodeId);
|
|
704
|
+
const hostAddress = readString2(raw?.hostAddress);
|
|
705
705
|
if (hostDaemonId) normalized.hostDaemonId = hostDaemonId;
|
|
706
706
|
if (hostNodeId) normalized.hostNodeId = hostNodeId;
|
|
707
707
|
if (hostAddress) normalized.hostAddress = hostAddress;
|
|
@@ -709,11 +709,11 @@ function resolveMeshHostStatus(mesh) {
|
|
|
709
709
|
const status = pairing.status === "pairing" || pairing.status === "paired" || pairing.status === "rejected" || pairing.status === "revoked" ? pairing.status : "not_configured";
|
|
710
710
|
normalized.pairing = {
|
|
711
711
|
status,
|
|
712
|
-
...
|
|
713
|
-
...
|
|
714
|
-
...
|
|
715
|
-
...
|
|
716
|
-
...
|
|
712
|
+
...readString2(pairing.tokenId) ? { tokenId: readString2(pairing.tokenId) } : {},
|
|
713
|
+
...readString2(pairing.joinedAt) ? { joinedAt: readString2(pairing.joinedAt) } : {},
|
|
714
|
+
...readString2(pairing.lastPairedAt) ? { lastPairedAt: readString2(pairing.lastPairedAt) } : {},
|
|
715
|
+
...readString2(pairing.lastRejectedAt) ? { lastRejectedAt: readString2(pairing.lastRejectedAt) } : {},
|
|
716
|
+
...readString2(pairing.expiresAt) ? { expiresAt: readString2(pairing.expiresAt) } : {}
|
|
717
717
|
};
|
|
718
718
|
}
|
|
719
719
|
return normalized;
|
|
@@ -2115,7 +2115,7 @@ function compactLedger(meshId) {
|
|
|
2115
2115
|
function readNonEmptyString(value) {
|
|
2116
2116
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
2117
2117
|
}
|
|
2118
|
-
function
|
|
2118
|
+
function readStringArray2(value) {
|
|
2119
2119
|
if (!Array.isArray(value)) return [];
|
|
2120
2120
|
return value.map((item) => readNonEmptyString(item)).filter(Boolean);
|
|
2121
2121
|
}
|
|
@@ -2175,11 +2175,11 @@ function normalizeMeshWorkerResult(input, source = "explicit_metadata") {
|
|
|
2175
2175
|
return {
|
|
2176
2176
|
status,
|
|
2177
2177
|
...readNonEmptyString(raw.classification) ? { classification: readNonEmptyString(raw.classification) } : {},
|
|
2178
|
-
changedFiles:
|
|
2178
|
+
changedFiles: readStringArray2(raw.changedFiles),
|
|
2179
2179
|
validationResults: normalizeValidationResults(raw.validationResults),
|
|
2180
2180
|
...gitStatus ? { gitStatus } : {},
|
|
2181
2181
|
processArtifacts: normalizeProcessArtifacts(raw.processArtifacts),
|
|
2182
|
-
errors:
|
|
2182
|
+
errors: readStringArray2(raw.errors),
|
|
2183
2183
|
...readNonEmptyString(raw.nextAction) ? { nextAction: readNonEmptyString(raw.nextAction) } : {},
|
|
2184
2184
|
requiresUserAction: raw.requiresUserAction === true,
|
|
2185
2185
|
source
|
|
@@ -3665,6 +3665,21 @@ function isDuplicateMeshCompletionEvent(args) {
|
|
|
3665
3665
|
recordFingerprintSeen(fingerprint);
|
|
3666
3666
|
return false;
|
|
3667
3667
|
}
|
|
3668
|
+
function isDuplicateMeshApprovalEvent(args) {
|
|
3669
|
+
const modalButtons = Array.isArray(args.modalButtons) ? args.modalButtons.map((button) => String(button).trim()).filter(Boolean) : [];
|
|
3670
|
+
const approvalIdentity = Number.isFinite(args.timestamp) ? String(args.timestamp) : JSON.stringify({ message: args.modalMessage || "", buttons: modalButtons });
|
|
3671
|
+
if (!approvalIdentity || approvalIdentity === '{"message":"","buttons":[]}') return false;
|
|
3672
|
+
const fingerprint = [
|
|
3673
|
+
args.meshId,
|
|
3674
|
+
"agent:waiting_approval",
|
|
3675
|
+
args.sessionId,
|
|
3676
|
+
args.providerType || "",
|
|
3677
|
+
approvalIdentity
|
|
3678
|
+
].join("::");
|
|
3679
|
+
if (hasFingerprintSeen(fingerprint)) return true;
|
|
3680
|
+
recordFingerprintSeen(fingerprint);
|
|
3681
|
+
return false;
|
|
3682
|
+
}
|
|
3668
3683
|
function isDuplicateRefineTerminalEvent(meshId, eventName, metadataEvent) {
|
|
3669
3684
|
const fingerprint = buildRefineTerminalEventFingerprint(meshId, eventName, metadataEvent);
|
|
3670
3685
|
if (!fingerprint) return false;
|
|
@@ -4225,6 +4240,20 @@ function injectMeshSystemMessage(components, args) {
|
|
|
4225
4240
|
return { success: true, forwarded: 0, suppressed: true, duplicateRefineTerminalEvent: true };
|
|
4226
4241
|
}
|
|
4227
4242
|
const eventTimestamp = readEventTimestamp(args.metadataEvent.timestamp);
|
|
4243
|
+
if (args.event === "agent:waiting_approval" && eventSessionId) {
|
|
4244
|
+
const duplicateApproval = isDuplicateMeshApprovalEvent({
|
|
4245
|
+
meshId: args.meshId,
|
|
4246
|
+
sessionId: eventSessionId,
|
|
4247
|
+
providerType: readNonEmptyString2(args.metadataEvent.providerType) || void 0,
|
|
4248
|
+
timestamp: eventTimestamp,
|
|
4249
|
+
modalMessage: readNonEmptyString2(args.metadataEvent.modalMessage) || void 0,
|
|
4250
|
+
modalButtons: args.metadataEvent.modalButtons
|
|
4251
|
+
});
|
|
4252
|
+
if (duplicateApproval) {
|
|
4253
|
+
LOG.info("MeshEvents", `Suppressed duplicate approval event for mesh ${args.meshId} session ${eventSessionId}`);
|
|
4254
|
+
return { success: true, forwarded: 0, suppressed: true, duplicateApproval: true };
|
|
4255
|
+
}
|
|
4256
|
+
}
|
|
4228
4257
|
if (args.event === "agent:generating_completed" && eventSessionId) {
|
|
4229
4258
|
const terminal = findRecentTerminalLedgerEvidence({
|
|
4230
4259
|
meshId: args.meshId,
|
|
@@ -8794,6 +8823,8 @@ ${lastSnapshot}`;
|
|
|
8794
8823
|
}
|
|
8795
8824
|
await this.sendMessage(promptText);
|
|
8796
8825
|
}
|
|
8826
|
+
async setInteractivePromptResponse(_response) {
|
|
8827
|
+
}
|
|
8797
8828
|
isSubmitStuck(normalizedPromptSnippet) {
|
|
8798
8829
|
if (!this.ptyProcess || !this.engine.isWaitingForResponse || this.engine.submitRetryUsed) return false;
|
|
8799
8830
|
if (this.engine.hasActionableApproval()) return false;
|
|
@@ -12101,6 +12132,7 @@ __export(index_exports, {
|
|
|
12101
12132
|
buildChatMessage: () => buildChatMessage,
|
|
12102
12133
|
buildChatMessageSignature: () => buildChatMessageSignature,
|
|
12103
12134
|
buildChatTailDeliverySignature: () => buildChatTailDeliverySignature,
|
|
12135
|
+
buildClaudeInteractiveToolResult: () => buildClaudeInteractiveToolResult,
|
|
12104
12136
|
buildCompactStaleDirectWorkSummary: () => buildCompactStaleDirectWorkSummary,
|
|
12105
12137
|
buildCoordinatorSystemPrompt: () => buildCoordinatorSystemPrompt,
|
|
12106
12138
|
buildIpcStatusHttpResponse: () => buildIpcStatusHttpResponse,
|
|
@@ -12147,6 +12179,7 @@ __export(index_exports, {
|
|
|
12147
12179
|
deleteMesh: () => deleteMesh,
|
|
12148
12180
|
detectAllVersions: () => detectAllVersions,
|
|
12149
12181
|
detectCLIs: () => detectCLIs,
|
|
12182
|
+
detectClaudeAskUserQuestionPromptFromJson: () => detectClaudeAskUserQuestionPromptFromJson,
|
|
12150
12183
|
detectIDEs: () => detectIDEs,
|
|
12151
12184
|
drainPendingMeshCoordinatorEvents: () => drainPendingMeshCoordinatorEvents,
|
|
12152
12185
|
enqueueTask: () => enqueueTask,
|
|
@@ -12201,6 +12234,7 @@ __export(index_exports, {
|
|
|
12201
12234
|
insertDirectDispatch: () => insertDirectDispatch,
|
|
12202
12235
|
installExtensions: () => installExtensions,
|
|
12203
12236
|
installGlobalInterceptor: () => installGlobalInterceptor,
|
|
12237
|
+
interactivePromptFromClaudeAskUserQuestion: () => interactivePromptFromClaudeAskUserQuestion,
|
|
12204
12238
|
isActivityChatMessage: () => isActivityChatMessage,
|
|
12205
12239
|
isBuiltinChatMessageKind: () => isBuiltinChatMessageKind,
|
|
12206
12240
|
isCdpConnected: () => isCdpConnected,
|
|
@@ -12244,6 +12278,8 @@ __export(index_exports, {
|
|
|
12244
12278
|
normalizeGitOutput: () => normalizeGitOutput,
|
|
12245
12279
|
normalizeGitWorkspaceSubscriptionParams: () => normalizeGitWorkspaceSubscriptionParams,
|
|
12246
12280
|
normalizeInputEnvelope: () => normalizeInputEnvelope,
|
|
12281
|
+
normalizeInteractivePrompt: () => normalizeInteractivePrompt,
|
|
12282
|
+
normalizeInteractivePromptResponse: () => normalizeInteractivePromptResponse,
|
|
12247
12283
|
normalizeManagedStatus: () => normalizeManagedStatus,
|
|
12248
12284
|
normalizeMeshDaemonRole: () => normalizeMeshDaemonRole,
|
|
12249
12285
|
normalizeMeshTaskMode: () => normalizeMeshTaskMode,
|
|
@@ -12320,6 +12356,228 @@ __export(index_exports, {
|
|
|
12320
12356
|
withRawTerminalAttachment: () => withRawTerminalAttachment
|
|
12321
12357
|
});
|
|
12322
12358
|
module.exports = __toCommonJS(index_exports);
|
|
12359
|
+
|
|
12360
|
+
// src/providers/types/interactive-prompt.ts
|
|
12361
|
+
function readString(value) {
|
|
12362
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
12363
|
+
}
|
|
12364
|
+
function readStringArray(value) {
|
|
12365
|
+
return Array.isArray(value) ? value.map((item) => readString(item)).filter((item) => !!item) : [];
|
|
12366
|
+
}
|
|
12367
|
+
function normalizeOption(raw) {
|
|
12368
|
+
if (typeof raw === "string") {
|
|
12369
|
+
const label2 = raw.trim();
|
|
12370
|
+
return label2 ? { label: label2 } : null;
|
|
12371
|
+
}
|
|
12372
|
+
if (!raw || typeof raw !== "object") return null;
|
|
12373
|
+
const record = raw;
|
|
12374
|
+
const label = readString(record.label);
|
|
12375
|
+
if (!label) return null;
|
|
12376
|
+
const description = readString(record.description);
|
|
12377
|
+
const preview = readString(record.preview);
|
|
12378
|
+
return {
|
|
12379
|
+
label,
|
|
12380
|
+
...description ? { description } : {},
|
|
12381
|
+
...preview ? { preview } : {}
|
|
12382
|
+
};
|
|
12383
|
+
}
|
|
12384
|
+
function normalizeQuestion(raw, index) {
|
|
12385
|
+
if (!raw || typeof raw !== "object") return null;
|
|
12386
|
+
const record = raw;
|
|
12387
|
+
const question = readString(record.question);
|
|
12388
|
+
if (!question) return null;
|
|
12389
|
+
const questionId = readString(record.questionId) || readString(record.id) || `q${index + 1}`;
|
|
12390
|
+
const options = Array.isArray(record.options) ? record.options.map(normalizeOption).filter((item) => !!item) : [];
|
|
12391
|
+
const header = readString(record.header);
|
|
12392
|
+
return {
|
|
12393
|
+
questionId,
|
|
12394
|
+
question,
|
|
12395
|
+
...header ? { header } : {},
|
|
12396
|
+
multiSelect: record.multiSelect === true,
|
|
12397
|
+
options,
|
|
12398
|
+
...record.allowFreeform === true ? { allowFreeform: true } : {}
|
|
12399
|
+
};
|
|
12400
|
+
}
|
|
12401
|
+
function normalizeInteractivePrompt(raw) {
|
|
12402
|
+
if (!raw || typeof raw !== "object") return null;
|
|
12403
|
+
const record = raw;
|
|
12404
|
+
const promptId = readString(record.promptId);
|
|
12405
|
+
const providerType = readString(record.providerType);
|
|
12406
|
+
const origin = record.origin === "mcp" || record.origin === "agent" ? record.origin : "cli";
|
|
12407
|
+
const questions = Array.isArray(record.questions) ? record.questions.map(normalizeQuestion).filter((item) => !!item) : [];
|
|
12408
|
+
if (!promptId || !providerType || questions.length === 0) return null;
|
|
12409
|
+
const createdAt = typeof record.createdAt === "number" && Number.isFinite(record.createdAt) ? record.createdAt : Date.now();
|
|
12410
|
+
return { promptId, origin, providerType, createdAt, questions };
|
|
12411
|
+
}
|
|
12412
|
+
function normalizeInteractivePromptResponse(raw) {
|
|
12413
|
+
if (!raw || typeof raw !== "object") throw new Error("Interactive prompt response must be an object");
|
|
12414
|
+
const record = raw;
|
|
12415
|
+
const promptId = readString(record.promptId);
|
|
12416
|
+
if (!promptId) throw new Error("promptId must be a non-empty string");
|
|
12417
|
+
if (!record.answers || typeof record.answers !== "object" || Array.isArray(record.answers)) {
|
|
12418
|
+
throw new Error("answers must be an object");
|
|
12419
|
+
}
|
|
12420
|
+
const answers = {};
|
|
12421
|
+
for (const [questionId, answerRaw] of Object.entries(record.answers)) {
|
|
12422
|
+
if (!answerRaw || typeof answerRaw !== "object" || Array.isArray(answerRaw)) continue;
|
|
12423
|
+
const answer = answerRaw;
|
|
12424
|
+
const selectedLabels = readStringArray(answer.selectedLabels);
|
|
12425
|
+
const freeformText = readString(answer.freeformText);
|
|
12426
|
+
answers[questionId] = {
|
|
12427
|
+
selectedLabels,
|
|
12428
|
+
...freeformText ? { freeformText } : {}
|
|
12429
|
+
};
|
|
12430
|
+
}
|
|
12431
|
+
return { promptId, answers };
|
|
12432
|
+
}
|
|
12433
|
+
function buildClaudeInteractiveToolResult(response) {
|
|
12434
|
+
return JSON.stringify({
|
|
12435
|
+
type: "user",
|
|
12436
|
+
message: {
|
|
12437
|
+
role: "user",
|
|
12438
|
+
content: [{
|
|
12439
|
+
type: "tool_result",
|
|
12440
|
+
tool_use_id: response.promptId,
|
|
12441
|
+
content: JSON.stringify({ answers: response.answers }),
|
|
12442
|
+
is_error: false
|
|
12443
|
+
}]
|
|
12444
|
+
}
|
|
12445
|
+
});
|
|
12446
|
+
}
|
|
12447
|
+
function claudeTuiQuestionHeaders(screenText) {
|
|
12448
|
+
const navLine = screenText.split(/\r?\n/).find((line) => line.includes("\u2714 Submit") && /[☐☒]/.test(line));
|
|
12449
|
+
if (!navLine) return [];
|
|
12450
|
+
const headers = [];
|
|
12451
|
+
const pattern = /[☐☒]\s+(.+?)(?=\s+[☐☒]|\s+✔\s+Submit)/g;
|
|
12452
|
+
for (const match of navLine.matchAll(pattern)) {
|
|
12453
|
+
const header = readString(match[1]);
|
|
12454
|
+
if (header) headers.push(header);
|
|
12455
|
+
}
|
|
12456
|
+
return headers;
|
|
12457
|
+
}
|
|
12458
|
+
function parseClaudeInteractiveTuiQuestion(page, index) {
|
|
12459
|
+
const lines = page.screenText.split(/\r?\n/);
|
|
12460
|
+
let navIndex = -1;
|
|
12461
|
+
for (let i = lines.length - 1; i >= 0; i -= 1) {
|
|
12462
|
+
if (lines[i].includes("\u2714 Submit") && /[☐☒]/.test(lines[i])) {
|
|
12463
|
+
navIndex = i;
|
|
12464
|
+
break;
|
|
12465
|
+
}
|
|
12466
|
+
}
|
|
12467
|
+
if (navIndex < 0 || !page.screenText.includes("Enter to select")) return null;
|
|
12468
|
+
let question = "";
|
|
12469
|
+
let questionLineIndex = -1;
|
|
12470
|
+
for (let i = navIndex + 1; i < lines.length; i += 1) {
|
|
12471
|
+
const candidate = lines[i].trim();
|
|
12472
|
+
if (!candidate || /^─+$/.test(candidate)) continue;
|
|
12473
|
+
if (candidate === "Review your answers" || candidate === "Ready to submit your answers?") return null;
|
|
12474
|
+
question = candidate;
|
|
12475
|
+
questionLineIndex = i;
|
|
12476
|
+
break;
|
|
12477
|
+
}
|
|
12478
|
+
if (!question) return null;
|
|
12479
|
+
const options = [];
|
|
12480
|
+
let allowFreeform = false;
|
|
12481
|
+
const optionPattern = /^\s*(?:[❯›>]\s*)?(\d+)\.\s+(.+?)\s*$/;
|
|
12482
|
+
for (let i = questionLineIndex + 1; i < lines.length; i += 1) {
|
|
12483
|
+
const match = lines[i].match(optionPattern);
|
|
12484
|
+
if (!match) continue;
|
|
12485
|
+
const label = match[2].trim();
|
|
12486
|
+
if (/^Type something\.?$/i.test(label)) {
|
|
12487
|
+
allowFreeform = true;
|
|
12488
|
+
continue;
|
|
12489
|
+
}
|
|
12490
|
+
if (/^Chat about this$/i.test(label)) continue;
|
|
12491
|
+
let description;
|
|
12492
|
+
const nextLine = lines[i + 1]?.trim();
|
|
12493
|
+
if (nextLine && !optionPattern.test(lines[i + 1]) && !/^─+$/.test(nextLine) && !/^Enter to select\b/.test(nextLine)) {
|
|
12494
|
+
description = nextLine;
|
|
12495
|
+
}
|
|
12496
|
+
options.push({ label, ...description ? { description } : {} });
|
|
12497
|
+
}
|
|
12498
|
+
if (options.length === 0) return null;
|
|
12499
|
+
const header = readString(page.header);
|
|
12500
|
+
return {
|
|
12501
|
+
questionId: `q${index + 1}`,
|
|
12502
|
+
question,
|
|
12503
|
+
...header ? { header } : {},
|
|
12504
|
+
multiSelect: /Space to select|toggle selections/i.test(page.screenText),
|
|
12505
|
+
options,
|
|
12506
|
+
...allowFreeform ? { allowFreeform: true } : {}
|
|
12507
|
+
};
|
|
12508
|
+
}
|
|
12509
|
+
function detectClaudeAskUserQuestionPromptFromTuiPages(pages, options) {
|
|
12510
|
+
if (pages.length === 0) return null;
|
|
12511
|
+
const headers = claudeTuiQuestionHeaders(pages[0].screenText);
|
|
12512
|
+
const questions = pages.map((page, index) => parseClaudeInteractiveTuiQuestion({
|
|
12513
|
+
...page,
|
|
12514
|
+
header: page.header || headers[index]
|
|
12515
|
+
}, index)).filter((question) => !!question);
|
|
12516
|
+
if (questions.length !== pages.length) return null;
|
|
12517
|
+
return {
|
|
12518
|
+
promptId: options.promptId,
|
|
12519
|
+
origin: "cli",
|
|
12520
|
+
providerType: options.providerType || "claude-cli",
|
|
12521
|
+
createdAt: options.createdAt || Date.now(),
|
|
12522
|
+
questions
|
|
12523
|
+
};
|
|
12524
|
+
}
|
|
12525
|
+
function buildClaudeInteractiveTuiAnswerSteps(prompt, response) {
|
|
12526
|
+
if (response.promptId !== prompt.promptId) throw new Error("Interactive prompt response does not match active prompt");
|
|
12527
|
+
const steps = [];
|
|
12528
|
+
for (const question of prompt.questions) {
|
|
12529
|
+
if (question.multiSelect) throw new Error("Claude TUI multi-select prompts are not supported yet");
|
|
12530
|
+
const answer = response.answers[question.questionId];
|
|
12531
|
+
if (!answer) throw new Error(`Missing answer for ${question.questionId}`);
|
|
12532
|
+
if (answer.freeformText) throw new Error("Claude TUI freeform answers are not supported yet");
|
|
12533
|
+
if (answer.selectedLabels.length !== 1) throw new Error(`Expected one selected label for ${question.questionId}`);
|
|
12534
|
+
const selectedIndex = question.options.findIndex((option) => option.label === answer.selectedLabels[0]);
|
|
12535
|
+
if (selectedIndex < 0) throw new Error(`Unknown option for ${question.questionId}: ${answer.selectedLabels[0]}`);
|
|
12536
|
+
steps.push(`${"\x1B[B".repeat(selectedIndex)}\r`);
|
|
12537
|
+
}
|
|
12538
|
+
steps.push("\r");
|
|
12539
|
+
return steps;
|
|
12540
|
+
}
|
|
12541
|
+
function interactivePromptFromClaudeAskUserQuestion(input, options) {
|
|
12542
|
+
if (!input || typeof input !== "object") return null;
|
|
12543
|
+
const record = input;
|
|
12544
|
+
const questions = Array.isArray(record.questions) ? record.questions.map(normalizeQuestion).filter((item) => !!item) : [];
|
|
12545
|
+
if (questions.length === 0) return null;
|
|
12546
|
+
return {
|
|
12547
|
+
promptId: options.promptId,
|
|
12548
|
+
origin: options.origin || "cli",
|
|
12549
|
+
providerType: options.providerType,
|
|
12550
|
+
createdAt: options.createdAt || Date.now(),
|
|
12551
|
+
questions
|
|
12552
|
+
};
|
|
12553
|
+
}
|
|
12554
|
+
function detectClaudeAskUserQuestionPromptFromJson(value, providerType = "claude-cli") {
|
|
12555
|
+
if (!value || typeof value !== "object") return null;
|
|
12556
|
+
const record = value;
|
|
12557
|
+
const blocks = [];
|
|
12558
|
+
if (Array.isArray(record.content)) blocks.push(...record.content);
|
|
12559
|
+
const message = record.message;
|
|
12560
|
+
if (message && typeof message === "object" && Array.isArray(message.content)) {
|
|
12561
|
+
blocks.push(...message.content);
|
|
12562
|
+
}
|
|
12563
|
+
if (record.type === "tool_use") blocks.push(record);
|
|
12564
|
+
for (const block2 of blocks) {
|
|
12565
|
+
if (!block2 || typeof block2 !== "object") continue;
|
|
12566
|
+
const b = block2;
|
|
12567
|
+
const name = readString(b.name);
|
|
12568
|
+
if (b.type !== "tool_use" || name !== "AskUserQuestion") continue;
|
|
12569
|
+
const id = readString(b.id) || readString(record.id) || `ask-user-${Date.now()}`;
|
|
12570
|
+
const prompt = interactivePromptFromClaudeAskUserQuestion(b.input, {
|
|
12571
|
+
promptId: id,
|
|
12572
|
+
providerType,
|
|
12573
|
+
origin: "cli"
|
|
12574
|
+
});
|
|
12575
|
+
if (prompt) return prompt;
|
|
12576
|
+
}
|
|
12577
|
+
return null;
|
|
12578
|
+
}
|
|
12579
|
+
|
|
12580
|
+
// src/index.ts
|
|
12323
12581
|
init_repo_mesh_types();
|
|
12324
12582
|
|
|
12325
12583
|
// src/git/index.ts
|
|
@@ -15066,7 +15324,7 @@ init_mesh_work_queue();
|
|
|
15066
15324
|
// src/mesh/mesh-active-work.ts
|
|
15067
15325
|
var DIRECT_DISPATCH_VIA = /* @__PURE__ */ new Set(["p2p_direct", "local_direct", "mesh_send_task"]);
|
|
15068
15326
|
var TERMINAL_LEDGER_KINDS = /* @__PURE__ */ new Set(["task_completed", "task_failed", "task_stalled"]);
|
|
15069
|
-
function
|
|
15327
|
+
function readString3(value) {
|
|
15070
15328
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
15071
15329
|
}
|
|
15072
15330
|
function summarizeMessage(message) {
|
|
@@ -15081,7 +15339,7 @@ function elapsedSince(value, now) {
|
|
|
15081
15339
|
function sessionStatusFromNodes(nodes, nodeId, sessionId) {
|
|
15082
15340
|
if (!Array.isArray(nodes)) return {};
|
|
15083
15341
|
if (!nodeId) return { staleReason: "direct task has no node id" };
|
|
15084
|
-
const node = nodes.find((item) =>
|
|
15342
|
+
const node = nodes.find((item) => readString3(item?.id) === nodeId || readString3(item?.nodeId) === nodeId || readString3(item?.node_id) === nodeId);
|
|
15085
15343
|
if (!node) return { staleReason: "direct task node is no longer in the live mesh" };
|
|
15086
15344
|
if (!sessionId) return {};
|
|
15087
15345
|
const candidates = [];
|
|
@@ -15105,12 +15363,12 @@ function sessionStatusFromNodes(nodes, nodeId, sessionId) {
|
|
|
15105
15363
|
}
|
|
15106
15364
|
const session = candidates.find((item) => {
|
|
15107
15365
|
if (typeof item === "string") return item === sessionId;
|
|
15108
|
-
const id =
|
|
15366
|
+
const id = readString3(item?.id) || readString3(item?.sessionId) || readString3(item?.session_id) || readString3(item?.runtimeSessionId) || readString3(item?.instanceId);
|
|
15109
15367
|
return id === sessionId;
|
|
15110
15368
|
});
|
|
15111
15369
|
if (!session) return { staleReason: "direct task session is not present in live session records" };
|
|
15112
15370
|
if (typeof session === "string") return {};
|
|
15113
|
-
const raw = `${
|
|
15371
|
+
const raw = `${readString3(session.status) || ""} ${readString3(session.lifecycle) || ""} ${readString3(session.state) || ""} ${readString3(session.activeChat?.status) || ""}`.toLowerCase();
|
|
15114
15372
|
if (raw.includes("approval")) return { status: "awaiting_approval" };
|
|
15115
15373
|
if (raw.includes("generating") || raw.includes("running") || raw.includes("busy")) return { status: "generating" };
|
|
15116
15374
|
if (raw.includes("failed") || raw.includes("stopped") || raw.includes("terminated") || raw.includes("exited")) return { status: "failed" };
|
|
@@ -15121,14 +15379,14 @@ function isDirectDispatch(entry) {
|
|
|
15121
15379
|
if (entry.kind !== "task_dispatched") return false;
|
|
15122
15380
|
const payload = entry.payload || {};
|
|
15123
15381
|
if (payload.source === "direct") return true;
|
|
15124
|
-
const via =
|
|
15382
|
+
const via = readString3(payload.via);
|
|
15125
15383
|
return Boolean(via && DIRECT_DISPATCH_VIA.has(via) && payload.source !== "queue");
|
|
15126
15384
|
}
|
|
15127
15385
|
function directDispatchTaskId(entry) {
|
|
15128
|
-
return
|
|
15386
|
+
return readString3(entry.payload?.taskId) || entry.id;
|
|
15129
15387
|
}
|
|
15130
15388
|
function terminalMatchesDispatch(terminal, dispatch, taskId) {
|
|
15131
|
-
const terminalTaskId =
|
|
15389
|
+
const terminalTaskId = readString3(terminal.payload?.taskId);
|
|
15132
15390
|
if (terminalTaskId && terminalTaskId === taskId) return true;
|
|
15133
15391
|
if (terminalTaskId && terminalTaskId !== taskId) return false;
|
|
15134
15392
|
if (dispatch.sessionId && terminal.sessionId === dispatch.sessionId) return true;
|
|
@@ -15251,7 +15509,7 @@ function buildMeshActiveWork(opts) {
|
|
|
15251
15509
|
const isNoTransition = !terminalStatus && !live.status;
|
|
15252
15510
|
const isIdleUnacknowledged = status === "idle";
|
|
15253
15511
|
const ledgerOnlyStaleReason = !terminalRow && (isIdleUnacknowledged || isNoTransition || dispatchedToIdleSession && isIdleUnacknowledged) ? "direct task dispatch has no provider acknowledgement, transcript append, or active runtime transition" : void 0;
|
|
15254
|
-
const message =
|
|
15512
|
+
const message = readString3(dispatch.payload?.message) || readString3(dispatch.payload?.summary) || "";
|
|
15255
15513
|
const { title, summary: summary2 } = summarizeMessage(message);
|
|
15256
15514
|
const isFreshUnacknowledged = Boolean(ledgerOnlyStaleReason && !live.staleReason);
|
|
15257
15515
|
const record = {
|
|
@@ -15260,11 +15518,11 @@ function buildMeshActiveWork(opts) {
|
|
|
15260
15518
|
status,
|
|
15261
15519
|
nodeId: dispatch.nodeId,
|
|
15262
15520
|
sessionId: dispatch.sessionId,
|
|
15263
|
-
providerType: dispatch.providerType ||
|
|
15264
|
-
taskTitle:
|
|
15265
|
-
taskSummary:
|
|
15521
|
+
providerType: dispatch.providerType || readString3(dispatch.payload?.providerType),
|
|
15522
|
+
taskTitle: readString3(dispatch.payload?.taskTitle) || title,
|
|
15523
|
+
taskSummary: readString3(dispatch.payload?.taskSummary) || summary2,
|
|
15266
15524
|
message,
|
|
15267
|
-
taskMode:
|
|
15525
|
+
taskMode: readString3(dispatch.payload?.taskMode),
|
|
15268
15526
|
createdAt: dispatch.timestamp,
|
|
15269
15527
|
updatedAt: terminal?.timestamp || dispatch.timestamp,
|
|
15270
15528
|
dispatchedAt: dispatch.timestamp,
|
|
@@ -15299,7 +15557,7 @@ function buildMeshActiveWork(opts) {
|
|
|
15299
15557
|
const isNoTransition = !terminalStatus && !live.status;
|
|
15300
15558
|
const isIdleUnacknowledged = status === "idle";
|
|
15301
15559
|
const ledgerOnlyStaleReason = !terminalRow && (isIdleUnacknowledged || isNoTransition || dispatchedToIdleSession && isIdleUnacknowledged) ? "direct task dispatch has no provider acknowledgement, transcript append, or active runtime transition" : void 0;
|
|
15302
|
-
const message =
|
|
15560
|
+
const message = readString3(dispatch.payload?.message) || readString3(dispatch.payload?.summary) || "";
|
|
15303
15561
|
const { title, summary: summary2 } = summarizeMessage(message);
|
|
15304
15562
|
const isFreshUnacknowledged = Boolean(ledgerOnlyStaleReason && !live.staleReason);
|
|
15305
15563
|
const record = {
|
|
@@ -15308,11 +15566,11 @@ function buildMeshActiveWork(opts) {
|
|
|
15308
15566
|
status,
|
|
15309
15567
|
nodeId: dispatch.nodeId,
|
|
15310
15568
|
sessionId: dispatch.sessionId,
|
|
15311
|
-
providerType: dispatch.providerType ||
|
|
15312
|
-
taskTitle:
|
|
15313
|
-
taskSummary:
|
|
15569
|
+
providerType: dispatch.providerType || readString3(dispatch.payload?.providerType),
|
|
15570
|
+
taskTitle: readString3(dispatch.payload?.taskTitle) || title,
|
|
15571
|
+
taskSummary: readString3(dispatch.payload?.taskSummary) || summary2,
|
|
15314
15572
|
message,
|
|
15315
|
-
taskMode:
|
|
15573
|
+
taskMode: readString3(dispatch.payload?.taskMode),
|
|
15316
15574
|
createdAt: dispatch.timestamp,
|
|
15317
15575
|
updatedAt: terminal?.timestamp || dispatch.timestamp,
|
|
15318
15576
|
dispatchedAt: dispatch.timestamp,
|
|
@@ -15375,7 +15633,7 @@ function buildCompactStaleDirectWorkSummary(staleDirectWork, opts = {}) {
|
|
|
15375
15633
|
}
|
|
15376
15634
|
|
|
15377
15635
|
// src/mesh/mesh-refine-status.ts
|
|
15378
|
-
function
|
|
15636
|
+
function readString4(value) {
|
|
15379
15637
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
15380
15638
|
}
|
|
15381
15639
|
function readRecord(value) {
|
|
@@ -15401,7 +15659,7 @@ function instructionForStatus(status) {
|
|
|
15401
15659
|
return "Refine job failed; inspect result/finalBranchConvergenceState in mesh_task_history, fix the blocker, then rerun mesh_refine_node when ready.";
|
|
15402
15660
|
}
|
|
15403
15661
|
function mergeJob(jobs, patch) {
|
|
15404
|
-
const jobId =
|
|
15662
|
+
const jobId = readString4(patch.jobId);
|
|
15405
15663
|
if (!jobId) return;
|
|
15406
15664
|
const previous = jobs.get(jobId);
|
|
15407
15665
|
const status = patch.status || previous?.status || "running";
|
|
@@ -15424,23 +15682,23 @@ function buildMeshAsyncRefineJobs(args) {
|
|
|
15424
15682
|
const refineJob = readRecord(payload.refineJob);
|
|
15425
15683
|
const result = readRecord(payload.result);
|
|
15426
15684
|
const finalState = readRecord(payload.finalBranchConvergenceState) || readRecord(result?.finalBranchConvergenceState);
|
|
15427
|
-
const jobId =
|
|
15685
|
+
const jobId = readString4(refineJob?.jobId);
|
|
15428
15686
|
if (!jobId) continue;
|
|
15429
|
-
const status = ledgerStatus(entry.kind,
|
|
15687
|
+
const status = ledgerStatus(entry.kind, readString4(refineJob?.status));
|
|
15430
15688
|
mergeJob(jobs, {
|
|
15431
15689
|
jobId,
|
|
15432
|
-
interactionId:
|
|
15690
|
+
interactionId: readString4(refineJob?.interactionId),
|
|
15433
15691
|
status,
|
|
15434
|
-
meshId:
|
|
15435
|
-
nodeId:
|
|
15436
|
-
targetNodeId:
|
|
15437
|
-
targetDaemonId:
|
|
15438
|
-
workspace:
|
|
15439
|
-
branch:
|
|
15440
|
-
into:
|
|
15441
|
-
startedAt:
|
|
15442
|
-
completedAt:
|
|
15443
|
-
retryOfJobId:
|
|
15692
|
+
meshId: readString4(refineJob?.meshId) || args.meshId,
|
|
15693
|
+
nodeId: readString4(refineJob?.nodeId) || entry.nodeId,
|
|
15694
|
+
targetNodeId: readString4(refineJob?.nodeId) || entry.nodeId,
|
|
15695
|
+
targetDaemonId: readString4(refineJob?.targetDaemonId),
|
|
15696
|
+
workspace: readString4(refineJob?.workspace),
|
|
15697
|
+
branch: readString4(result?.branch) || readString4(finalState?.branch),
|
|
15698
|
+
into: readString4(result?.into) || readString4(finalState?.baseBranch),
|
|
15699
|
+
startedAt: readString4(refineJob?.startedAt),
|
|
15700
|
+
completedAt: readString4(refineJob?.completedAt),
|
|
15701
|
+
retryOfJobId: readString4(refineJob?.retryOfJobId) || readString4(payload.retryOfJobId),
|
|
15444
15702
|
lastLedgerKind: entry.kind,
|
|
15445
15703
|
lastUpdatedAt: entry.timestamp
|
|
15446
15704
|
});
|
|
@@ -15450,23 +15708,23 @@ function buildMeshAsyncRefineJobs(args) {
|
|
|
15450
15708
|
if (metadata?.source !== "refine_mesh_node_async_job") continue;
|
|
15451
15709
|
const result = readRecord(metadata.result);
|
|
15452
15710
|
const finalState = readRecord(result?.finalBranchConvergenceState);
|
|
15453
|
-
const jobId =
|
|
15711
|
+
const jobId = readString4(metadata.jobId);
|
|
15454
15712
|
if (!jobId) continue;
|
|
15455
|
-
const status = eventStatus(event.event,
|
|
15713
|
+
const status = eventStatus(event.event, readString4(metadata.status));
|
|
15456
15714
|
mergeJob(jobs, {
|
|
15457
15715
|
jobId,
|
|
15458
|
-
interactionId:
|
|
15716
|
+
interactionId: readString4(metadata.interactionId),
|
|
15459
15717
|
...status ? { status } : {},
|
|
15460
|
-
meshId:
|
|
15461
|
-
nodeId:
|
|
15462
|
-
targetNodeId:
|
|
15463
|
-
targetDaemonId:
|
|
15464
|
-
workspace:
|
|
15465
|
-
branch:
|
|
15466
|
-
into:
|
|
15467
|
-
startedAt:
|
|
15468
|
-
completedAt:
|
|
15469
|
-
retryOfJobId:
|
|
15718
|
+
meshId: readString4(metadata.meshId) || event.meshId || args.meshId,
|
|
15719
|
+
nodeId: readString4(metadata.nodeId) || event.nodeId,
|
|
15720
|
+
targetNodeId: readString4(metadata.nodeId) || event.nodeId,
|
|
15721
|
+
targetDaemonId: readString4(metadata.targetDaemonId),
|
|
15722
|
+
workspace: readString4(metadata.workspace) || event.workspace,
|
|
15723
|
+
branch: readString4(result?.branch) || readString4(finalState?.branch),
|
|
15724
|
+
into: readString4(result?.into) || readString4(finalState?.baseBranch),
|
|
15725
|
+
startedAt: readString4(metadata.startedAt),
|
|
15726
|
+
completedAt: readString4(metadata.completedAt),
|
|
15727
|
+
retryOfJobId: readString4(metadata.retryOfJobId),
|
|
15470
15728
|
lastEvent: event.event,
|
|
15471
15729
|
lastUpdatedAt: new Date(event.queuedAt).toISOString()
|
|
15472
15730
|
});
|
|
@@ -21643,6 +21901,7 @@ function buildCliSession(state, options) {
|
|
|
21643
21901
|
mode: state.mode,
|
|
21644
21902
|
resume: state.resume,
|
|
21645
21903
|
activeChat,
|
|
21904
|
+
...state.activeInteractivePrompt ? { activeInteractivePrompt: state.activeInteractivePrompt } : {},
|
|
21646
21905
|
...summaryMetadata && { summaryMetadata },
|
|
21647
21906
|
...includeSessionMetadata && {
|
|
21648
21907
|
capabilities: state.mode === "terminal" ? PTY_SESSION_CAPABILITIES : CLI_CHAT_SESSION_CAPABILITIES,
|
|
@@ -27395,6 +27654,9 @@ var SpecDriver = class {
|
|
|
27395
27654
|
return;
|
|
27396
27655
|
}
|
|
27397
27656
|
}
|
|
27657
|
+
snapshot() {
|
|
27658
|
+
return this.adapter.snapshot();
|
|
27659
|
+
}
|
|
27398
27660
|
shutdown() {
|
|
27399
27661
|
for (const t of this.delegateTimers.values()) clearTimeout(t);
|
|
27400
27662
|
this.delegateTimers.clear();
|
|
@@ -27674,6 +27936,10 @@ var SpecCliAdapter = class {
|
|
|
27674
27936
|
statusCallback = null;
|
|
27675
27937
|
ptyDataCallback = null;
|
|
27676
27938
|
partialResponse = "";
|
|
27939
|
+
activeInteractivePrompt = null;
|
|
27940
|
+
interactivePromptTransport = null;
|
|
27941
|
+
claudeTuiPromptCaptureInFlight = false;
|
|
27942
|
+
jsonLineTail = "";
|
|
27677
27943
|
exited = false;
|
|
27678
27944
|
spawned = false;
|
|
27679
27945
|
providerSessionId;
|
|
@@ -27723,11 +27989,11 @@ var SpecCliAdapter = class {
|
|
|
27723
27989
|
this.driver.dispatch({ kind: "send_message", text });
|
|
27724
27990
|
}
|
|
27725
27991
|
getStatus() {
|
|
27726
|
-
if (this.exited) return { status: "stopped", messages: [], activeModal: null };
|
|
27727
|
-
if (!this.spawned) return { status: "starting", messages: [], activeModal: null };
|
|
27992
|
+
if (this.exited) return { status: "stopped", messages: [], activeModal: null, activeInteractivePrompt: this.activeInteractivePrompt };
|
|
27993
|
+
if (!this.spawned) return { status: "starting", messages: [], activeModal: null, activeInteractivePrompt: this.activeInteractivePrompt };
|
|
27728
27994
|
this.maybeRefreshNativeHistory();
|
|
27729
27995
|
const state = this.latestState;
|
|
27730
|
-
if (!state) return { status: "starting", messages: [], activeModal: null };
|
|
27996
|
+
if (!state) return { status: "starting", messages: [], activeModal: null, activeInteractivePrompt: this.activeInteractivePrompt };
|
|
27731
27997
|
const modal = this.latestModal;
|
|
27732
27998
|
const lc = state.id.toLowerCase();
|
|
27733
27999
|
if (modal) {
|
|
@@ -27737,13 +28003,14 @@ var SpecCliAdapter = class {
|
|
|
27737
28003
|
activeModal: {
|
|
27738
28004
|
message: modal.title ?? state.label,
|
|
27739
28005
|
buttons: modal.buttons.map((b) => b.label)
|
|
27740
|
-
}
|
|
28006
|
+
},
|
|
28007
|
+
activeInteractivePrompt: this.activeInteractivePrompt
|
|
27741
28008
|
};
|
|
27742
28009
|
}
|
|
27743
28010
|
if (/busy|generating|working|running|thinking/i.test(lc + " " + state.label)) {
|
|
27744
|
-
return { status: "generating", messages: [], activeModal: null };
|
|
28011
|
+
return { status: "generating", messages: [], activeModal: null, activeInteractivePrompt: this.activeInteractivePrompt };
|
|
27745
28012
|
}
|
|
27746
|
-
return { status: "idle", messages: [], activeModal: null };
|
|
28013
|
+
return { status: "idle", messages: [], activeModal: null, activeInteractivePrompt: this.activeInteractivePrompt };
|
|
27747
28014
|
}
|
|
27748
28015
|
maybeRefreshNativeHistory() {
|
|
27749
28016
|
}
|
|
@@ -27806,6 +28073,24 @@ var SpecCliAdapter = class {
|
|
|
27806
28073
|
}
|
|
27807
28074
|
this.resolveModal(target);
|
|
27808
28075
|
}
|
|
28076
|
+
async setInteractivePromptResponse(response) {
|
|
28077
|
+
const prompt = this.activeInteractivePrompt;
|
|
28078
|
+
if (!prompt || prompt.promptId !== response.promptId) throw new Error("Interactive prompt response does not match active prompt");
|
|
28079
|
+
if (this.cliType !== "claude-cli") return;
|
|
28080
|
+
if (this.interactivePromptTransport === "tui") {
|
|
28081
|
+
const steps = buildClaudeInteractiveTuiAnswerSteps(prompt, response);
|
|
28082
|
+
for (const step of steps) {
|
|
28083
|
+
this.driver.dispatch({ kind: "pty_write", data: step });
|
|
28084
|
+
await new Promise((resolve23) => setTimeout(resolve23, 180));
|
|
28085
|
+
}
|
|
28086
|
+
} else {
|
|
28087
|
+
this.driver.dispatch({ kind: "pty_write", data: `${buildClaudeInteractiveToolResult(response)}
|
|
28088
|
+
` });
|
|
28089
|
+
}
|
|
28090
|
+
this.activeInteractivePrompt = null;
|
|
28091
|
+
this.interactivePromptTransport = null;
|
|
28092
|
+
this.statusCallback?.();
|
|
28093
|
+
}
|
|
27809
28094
|
isApprovalRecentlyResolved() {
|
|
27810
28095
|
return false;
|
|
27811
28096
|
}
|
|
@@ -27861,6 +28146,7 @@ var SpecCliAdapter = class {
|
|
|
27861
28146
|
spec_id: this.spec.id,
|
|
27862
28147
|
current_state: this.latestState,
|
|
27863
28148
|
current_modal: this.latestModal,
|
|
28149
|
+
activeInteractivePrompt: this.activeInteractivePrompt,
|
|
27864
28150
|
exited: this.exited
|
|
27865
28151
|
};
|
|
27866
28152
|
}
|
|
@@ -27890,9 +28176,12 @@ var SpecCliAdapter = class {
|
|
|
27890
28176
|
if (ev.state.title) {
|
|
27891
28177
|
LOG.debug("SpecAdapter", `[${this.cliType}] state.title=${JSON.stringify(ev.state.title)}`);
|
|
27892
28178
|
}
|
|
28179
|
+
this.maybeCaptureClaudeTuiPrompt();
|
|
27893
28180
|
this.statusCallback?.();
|
|
27894
28181
|
return;
|
|
27895
28182
|
case "pty_data":
|
|
28183
|
+
this.detectInteractivePromptFromPtyChunk(ev.chunk);
|
|
28184
|
+
this.maybeCaptureClaudeTuiPrompt();
|
|
27896
28185
|
try {
|
|
27897
28186
|
this.ptyDataCallback?.(ev.chunk);
|
|
27898
28187
|
} catch {
|
|
@@ -27909,6 +28198,66 @@ var SpecCliAdapter = class {
|
|
|
27909
28198
|
return;
|
|
27910
28199
|
}
|
|
27911
28200
|
}
|
|
28201
|
+
detectInteractivePromptFromPtyChunk(chunk) {
|
|
28202
|
+
if (this.cliType !== "claude-cli" || !chunk) return;
|
|
28203
|
+
this.jsonLineTail += chunk;
|
|
28204
|
+
if (this.jsonLineTail.length > 64 * 1024) this.jsonLineTail = this.jsonLineTail.slice(-64 * 1024);
|
|
28205
|
+
const lines = this.jsonLineTail.split(/\r?\n/);
|
|
28206
|
+
this.jsonLineTail = lines.pop() || "";
|
|
28207
|
+
for (const line of lines) {
|
|
28208
|
+
const trimmed = line.trim();
|
|
28209
|
+
if (!trimmed.startsWith("{") || !trimmed.includes("AskUserQuestion")) continue;
|
|
28210
|
+
try {
|
|
28211
|
+
const parsed = JSON.parse(trimmed);
|
|
28212
|
+
const prompt = detectClaudeAskUserQuestionPromptFromJson(parsed, this.cliType);
|
|
28213
|
+
if (!prompt) continue;
|
|
28214
|
+
this.activeInteractivePrompt = prompt;
|
|
28215
|
+
this.interactivePromptTransport = "stream-json";
|
|
28216
|
+
this.statusCallback?.();
|
|
28217
|
+
} catch {
|
|
28218
|
+
}
|
|
28219
|
+
}
|
|
28220
|
+
}
|
|
28221
|
+
maybeCaptureClaudeTuiPrompt() {
|
|
28222
|
+
if (this.cliType !== "claude-cli" || this.activeInteractivePrompt || this.claudeTuiPromptCaptureInFlight) return;
|
|
28223
|
+
const screenText = this.driver.snapshot();
|
|
28224
|
+
const headers = this.readClaudeTuiHeaders(screenText);
|
|
28225
|
+
if (headers.length === 0 || !screenText.includes("Enter to select")) return;
|
|
28226
|
+
this.claudeTuiPromptCaptureInFlight = true;
|
|
28227
|
+
void this.captureClaudeTuiPrompt(screenText, headers).finally(() => {
|
|
28228
|
+
this.claudeTuiPromptCaptureInFlight = false;
|
|
28229
|
+
});
|
|
28230
|
+
}
|
|
28231
|
+
readClaudeTuiHeaders(screenText) {
|
|
28232
|
+
const navLine = screenText.split(/\r?\n/).find((line) => line.includes("\u2714 Submit") && /[☐☒]/.test(line));
|
|
28233
|
+
if (!navLine) return [];
|
|
28234
|
+
const headers = [];
|
|
28235
|
+
for (const match of navLine.matchAll(/[☐☒]\s+(.+?)(?=\s+[☐☒]|\s+✔\s+Submit)/g)) {
|
|
28236
|
+
const header = match[1]?.trim();
|
|
28237
|
+
if (header) headers.push(header);
|
|
28238
|
+
}
|
|
28239
|
+
return headers;
|
|
28240
|
+
}
|
|
28241
|
+
async captureClaudeTuiPrompt(firstScreen, headers) {
|
|
28242
|
+
const pages = [{ screenText: firstScreen, header: headers[0] }];
|
|
28243
|
+
for (let index = 1; index < headers.length; index += 1) {
|
|
28244
|
+
this.driver.dispatch({ kind: "pty_write", data: " " });
|
|
28245
|
+
await new Promise((resolve23) => setTimeout(resolve23, 120));
|
|
28246
|
+
pages.push({ screenText: this.driver.snapshot(), header: headers[index] });
|
|
28247
|
+
}
|
|
28248
|
+
for (let index = headers.length - 1; index > 0; index -= 1) {
|
|
28249
|
+
this.driver.dispatch({ kind: "pty_write", data: "\x1B[Z" });
|
|
28250
|
+
await new Promise((resolve23) => setTimeout(resolve23, 80));
|
|
28251
|
+
}
|
|
28252
|
+
const prompt = detectClaudeAskUserQuestionPromptFromTuiPages(pages, {
|
|
28253
|
+
promptId: `ask-user-${this.providerSessionId || "claude"}-${Date.now()}`,
|
|
28254
|
+
providerType: this.cliType
|
|
28255
|
+
});
|
|
28256
|
+
if (!prompt) return;
|
|
28257
|
+
this.activeInteractivePrompt = prompt;
|
|
28258
|
+
this.interactivePromptTransport = "tui";
|
|
28259
|
+
this.statusCallback?.();
|
|
28260
|
+
}
|
|
27912
28261
|
};
|
|
27913
28262
|
|
|
27914
28263
|
// src/providers/spec/route.ts
|
|
@@ -28177,7 +28526,7 @@ var CliProviderInstance = class {
|
|
|
28177
28526
|
monitor;
|
|
28178
28527
|
generatingDebounceTimer = null;
|
|
28179
28528
|
generatingDebouncePending = null;
|
|
28180
|
-
|
|
28529
|
+
lastApprovalEventFingerprint = "";
|
|
28181
28530
|
autoApproveBusy = false;
|
|
28182
28531
|
autoApproveBusyTimer = null;
|
|
28183
28532
|
lastAutoApprovalSignature = "";
|
|
@@ -28196,6 +28545,7 @@ var CliProviderInstance = class {
|
|
|
28196
28545
|
suppressIdleHistoryReplay = false;
|
|
28197
28546
|
errorMessage = void 0;
|
|
28198
28547
|
errorReason = void 0;
|
|
28548
|
+
activeInteractivePrompt = null;
|
|
28199
28549
|
presentationMode;
|
|
28200
28550
|
providerSessionId;
|
|
28201
28551
|
launchMode;
|
|
@@ -28288,6 +28638,9 @@ var CliProviderInstance = class {
|
|
|
28288
28638
|
}
|
|
28289
28639
|
getState() {
|
|
28290
28640
|
const adapterStatus = this.adapter.getStatus();
|
|
28641
|
+
if (Object.prototype.hasOwnProperty.call(adapterStatus, "activeInteractivePrompt")) {
|
|
28642
|
+
this.activeInteractivePrompt = adapterStatus.activeInteractivePrompt ?? null;
|
|
28643
|
+
}
|
|
28291
28644
|
let parsedStatus = null;
|
|
28292
28645
|
let parseErrorMessage;
|
|
28293
28646
|
if (typeof this.adapter.getScriptParsedStatus === "function") {
|
|
@@ -28404,8 +28757,10 @@ var CliProviderInstance = class {
|
|
|
28404
28757
|
status: activeChatStatus,
|
|
28405
28758
|
messages: statusMessages,
|
|
28406
28759
|
activeModal: autoApproveActive ? null : parsedStatus?.activeModal ?? adapterStatus.activeModal,
|
|
28760
|
+
activeInteractivePrompt: this.activeInteractivePrompt,
|
|
28407
28761
|
inputContent: ""
|
|
28408
28762
|
},
|
|
28763
|
+
activeInteractivePrompt: this.activeInteractivePrompt,
|
|
28409
28764
|
workspace: this.workingDir,
|
|
28410
28765
|
instanceId: this.instanceId,
|
|
28411
28766
|
providerSessionId: this.providerSessionId,
|
|
@@ -28495,6 +28850,32 @@ var CliProviderInstance = class {
|
|
|
28495
28850
|
void this.adapter.resolveAction(data).catch((e) => {
|
|
28496
28851
|
LOG.warn("CLI", `[${this.type}] resolve_action failed: ${e?.message || e}`);
|
|
28497
28852
|
});
|
|
28853
|
+
} else if (event === "interactive_prompt" && data) {
|
|
28854
|
+
const prompt = normalizeInteractivePrompt(data);
|
|
28855
|
+
if (prompt) {
|
|
28856
|
+
this.activeInteractivePrompt = prompt;
|
|
28857
|
+
this.events.push({
|
|
28858
|
+
event: "interactive_prompt",
|
|
28859
|
+
timestamp: Date.now(),
|
|
28860
|
+
promptId: prompt.promptId
|
|
28861
|
+
});
|
|
28862
|
+
}
|
|
28863
|
+
} else if (event === "interactive_prompt_response" && data) {
|
|
28864
|
+
try {
|
|
28865
|
+
const response = normalizeInteractivePromptResponse(data);
|
|
28866
|
+
if (this.activeInteractivePrompt?.promptId === response.promptId) {
|
|
28867
|
+
this.activeInteractivePrompt = null;
|
|
28868
|
+
}
|
|
28869
|
+
if (typeof this.adapter.setInteractivePromptResponse !== "function") {
|
|
28870
|
+
LOG.warn("CLI", `[${this.type}] interactive_prompt_response ignored: adapter does not support interactive prompts`);
|
|
28871
|
+
return;
|
|
28872
|
+
}
|
|
28873
|
+
void this.adapter.setInteractivePromptResponse(response).catch((e) => {
|
|
28874
|
+
LOG.warn("CLI", `[${this.type}] interactive_prompt_response failed: ${e?.message || e}`);
|
|
28875
|
+
});
|
|
28876
|
+
} catch (e) {
|
|
28877
|
+
LOG.warn("CLI", `[${this.type}] invalid interactive_prompt_response: ${e?.message || e}`);
|
|
28878
|
+
}
|
|
28498
28879
|
} else if (event === "provider_state_patch" && data && typeof data === "object") {
|
|
28499
28880
|
this.applyProviderResponse(data, { phase: "immediate" });
|
|
28500
28881
|
}
|
|
@@ -28628,12 +29009,15 @@ var CliProviderInstance = class {
|
|
|
28628
29009
|
if (typeof adapterAny?.responseBuffer === "string" && adapterAny.responseBuffer.trim()) return false;
|
|
28629
29010
|
return true;
|
|
28630
29011
|
}
|
|
28631
|
-
getCompletedFinalizationBlock(latestVisibleStatus) {
|
|
29012
|
+
getCompletedFinalizationBlock(latestVisibleStatus, pending) {
|
|
28632
29013
|
if (latestVisibleStatus !== "idle") return { reason: `status:${latestVisibleStatus}`, terminal: true };
|
|
28633
29014
|
const adapterAny = this.adapter;
|
|
28634
|
-
|
|
28635
|
-
if (
|
|
28636
|
-
|
|
29015
|
+
const approvalResolvedIdle = pending.previousStatus === "waiting_approval";
|
|
29016
|
+
if (!approvalResolvedIdle) {
|
|
29017
|
+
if (adapterAny?.isWaitingForResponse === true) return { reason: "adapter_waiting_for_response", terminal: true };
|
|
29018
|
+
if (adapterAny?.currentTurnScope) return { reason: "adapter_turn_scope_active", terminal: true };
|
|
29019
|
+
if (this.hasAdapterPendingResponse()) return { reason: "adapter_pending_response", terminal: true };
|
|
29020
|
+
}
|
|
28637
29021
|
const partial = typeof this.adapter.getPartialResponse === "function" ? this.adapter.getPartialResponse() : "";
|
|
28638
29022
|
if (typeof partial === "string" && partial.trim()) return { reason: "partial_response_pending", terminal: true };
|
|
28639
29023
|
let parsed;
|
|
@@ -28658,7 +29042,7 @@ var CliProviderInstance = class {
|
|
|
28658
29042
|
if (screenText) {
|
|
28659
29043
|
const tailLines = screenText.split(/\r?\n/).slice(-16).join("\n");
|
|
28660
29044
|
if (looksLikeActiveApprovalPromptText(tailLines)) {
|
|
28661
|
-
return { reason: "screen_shows_approval_prompt", terminal:
|
|
29045
|
+
return { reason: "screen_shows_approval_prompt", terminal: approvalResolvedIdle };
|
|
28662
29046
|
}
|
|
28663
29047
|
}
|
|
28664
29048
|
} catch {
|
|
@@ -28684,7 +29068,7 @@ var CliProviderInstance = class {
|
|
|
28684
29068
|
this.completedDebounceTimer = null;
|
|
28685
29069
|
return;
|
|
28686
29070
|
}
|
|
28687
|
-
const block2 = this.getCompletedFinalizationBlock(latestVisibleStatus);
|
|
29071
|
+
const block2 = this.getCompletedFinalizationBlock(latestVisibleStatus, pending);
|
|
28688
29072
|
if (block2) {
|
|
28689
29073
|
const blockReason = block2.reason;
|
|
28690
29074
|
const waitedMs = Date.now() - pending.firstObservedAt;
|
|
@@ -28716,6 +29100,7 @@ var CliProviderInstance = class {
|
|
|
28716
29100
|
this.completedDebouncePending = null;
|
|
28717
29101
|
this.completedDebounceTimer = null;
|
|
28718
29102
|
this.generatingStartedAt = 0;
|
|
29103
|
+
this.lastApprovalEventFingerprint = "";
|
|
28719
29104
|
return;
|
|
28720
29105
|
}
|
|
28721
29106
|
LOG.info("CLI", `[${this.type}] completed in ${pending.duration}s`);
|
|
@@ -28729,6 +29114,7 @@ var CliProviderInstance = class {
|
|
|
28729
29114
|
this.completedDebouncePending = null;
|
|
28730
29115
|
this.completedDebounceTimer = null;
|
|
28731
29116
|
this.generatingStartedAt = 0;
|
|
29117
|
+
this.lastApprovalEventFingerprint = "";
|
|
28732
29118
|
}
|
|
28733
29119
|
maybeAutoApproveStatus(adapterStatus, now = Date.now()) {
|
|
28734
29120
|
const autoApproveActive = adapterStatus?.status === "waiting_approval" && this.shouldAutoApprove();
|
|
@@ -28825,9 +29211,12 @@ var CliProviderInstance = class {
|
|
|
28825
29211
|
if (!this.generatingStartedAt) this.generatingStartedAt = now;
|
|
28826
29212
|
const modal = adapterStatus.activeModal;
|
|
28827
29213
|
LOG.info("CLI", `[${this.type}] approval modal: "${modal?.message?.slice(0, 80) ?? "none"}"`);
|
|
28828
|
-
const
|
|
28829
|
-
|
|
28830
|
-
|
|
29214
|
+
const approvalFingerprint = JSON.stringify({
|
|
29215
|
+
message: typeof modal?.message === "string" ? modal.message.trim() : "",
|
|
29216
|
+
buttons: Array.isArray(modal?.buttons) ? modal.buttons.map((button) => String(button).trim()) : []
|
|
29217
|
+
});
|
|
29218
|
+
if (this.lastStatus !== "waiting_approval" && approvalFingerprint !== this.lastApprovalEventFingerprint) {
|
|
29219
|
+
this.lastApprovalEventFingerprint = approvalFingerprint;
|
|
28831
29220
|
this.appendRuntimeSystemMessage(
|
|
28832
29221
|
this.formatApprovalRequestMessage(modal?.message, modal?.buttons),
|
|
28833
29222
|
`approval_request:${now}`,
|
|
@@ -28869,7 +29258,13 @@ var CliProviderInstance = class {
|
|
|
28869
29258
|
}
|
|
28870
29259
|
});
|
|
28871
29260
|
} else {
|
|
28872
|
-
this.completedDebouncePending = {
|
|
29261
|
+
this.completedDebouncePending = {
|
|
29262
|
+
chatTitle,
|
|
29263
|
+
duration,
|
|
29264
|
+
timestamp: now,
|
|
29265
|
+
firstObservedAt: now,
|
|
29266
|
+
previousStatus: this.lastStatus
|
|
29267
|
+
};
|
|
28873
29268
|
this.scheduleCompletedDebounceFlush(3e3);
|
|
28874
29269
|
}
|
|
28875
29270
|
} else if (newStatus === "idle" && this.lastStatus === "starting") {
|
|
@@ -48952,6 +49347,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
48952
49347
|
buildChatMessage,
|
|
48953
49348
|
buildChatMessageSignature,
|
|
48954
49349
|
buildChatTailDeliverySignature,
|
|
49350
|
+
buildClaudeInteractiveToolResult,
|
|
48955
49351
|
buildCompactStaleDirectWorkSummary,
|
|
48956
49352
|
buildCoordinatorSystemPrompt,
|
|
48957
49353
|
buildIpcStatusHttpResponse,
|
|
@@ -48998,6 +49394,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
48998
49394
|
deleteMesh,
|
|
48999
49395
|
detectAllVersions,
|
|
49000
49396
|
detectCLIs,
|
|
49397
|
+
detectClaudeAskUserQuestionPromptFromJson,
|
|
49001
49398
|
detectIDEs,
|
|
49002
49399
|
drainPendingMeshCoordinatorEvents,
|
|
49003
49400
|
enqueueTask,
|
|
@@ -49052,6 +49449,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
49052
49449
|
insertDirectDispatch,
|
|
49053
49450
|
installExtensions,
|
|
49054
49451
|
installGlobalInterceptor,
|
|
49452
|
+
interactivePromptFromClaudeAskUserQuestion,
|
|
49055
49453
|
isActivityChatMessage,
|
|
49056
49454
|
isBuiltinChatMessageKind,
|
|
49057
49455
|
isCdpConnected,
|
|
@@ -49095,6 +49493,8 @@ var V1_CONTRACT_VERSION = "1.0.0";
|
|
|
49095
49493
|
normalizeGitOutput,
|
|
49096
49494
|
normalizeGitWorkspaceSubscriptionParams,
|
|
49097
49495
|
normalizeInputEnvelope,
|
|
49496
|
+
normalizeInteractivePrompt,
|
|
49497
|
+
normalizeInteractivePromptResponse,
|
|
49098
49498
|
normalizeManagedStatus,
|
|
49099
49499
|
normalizeMeshDaemonRole,
|
|
49100
49500
|
normalizeMeshTaskMode,
|