@rallycry/conveyor-agent 11.0.27 → 11.0.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-7HK6OIV4.js → chunk-FF5JML7W.js} +250 -137
- package/dist/{chunk-PBSFLQA7.js → chunk-KLM6ZOUX.js} +844 -675
- package/dist/{chunk-SI7WNWZZ.js → chunk-V5X3JCAZ.js} +7 -2
- package/dist/cli.js +4 -4
- package/dist/index.d.ts +28 -6
- package/dist/index.js +2 -2
- package/dist/{serve-boot-WGUFEWYJ.js → serve-boot-N5XKECWC.js} +2 -2
- package/package.json +1 -1
- package/skills/conveyor-build/SKILL.md +10 -11
- package/skills/conveyor-consensus/SKILL.md +4 -3
- package/skills/conveyor-plan/references/plan-format.md +7 -3
- package/skills/conveyor-prune/SKILL.md +181 -0
- package/skills/conveyor-workflows/SKILL.md +19 -5
|
@@ -47,13 +47,14 @@ import {
|
|
|
47
47
|
Lifecycle,
|
|
48
48
|
MAX_CI_WAIT_TIMEOUT_MINUTES,
|
|
49
49
|
MAX_FILE_SIZE_BYTES,
|
|
50
|
+
MAX_MANUAL_TESTS_PER_TASK,
|
|
51
|
+
MAX_MANUAL_TEST_TITLE_LENGTH,
|
|
50
52
|
PM_CHAT_HISTORY_LIMIT,
|
|
51
53
|
PRE_BUILD_TASK_STATUSES,
|
|
52
54
|
PTY_STREAM_PORT_ATTEMPTS,
|
|
53
55
|
PTY_STREAM_PORT_BASE,
|
|
54
56
|
PortDiscovery,
|
|
55
57
|
PtyStreamFrameReader,
|
|
56
|
-
ReviewGuideContentSchema,
|
|
57
58
|
SEVERITY_ENUM,
|
|
58
59
|
TAG_DESCRIPTION_MAX,
|
|
59
60
|
TAG_OVERVIEW_MAX,
|
|
@@ -63,12 +64,14 @@ import {
|
|
|
63
64
|
awaitGitReady,
|
|
64
65
|
clearForceFreshCooldown,
|
|
65
66
|
createServiceLogger,
|
|
67
|
+
describeManualTestRejection,
|
|
66
68
|
encodePtyStreamFrame,
|
|
67
69
|
ensureOnTaskBranch,
|
|
68
70
|
flushAllPendingWork,
|
|
69
71
|
flushPendingChanges,
|
|
70
72
|
forceFreshCooldownNotice,
|
|
71
73
|
forceFreshMintBlocked,
|
|
74
|
+
formatEvaluateQuestionsResult,
|
|
72
75
|
getCurrentBranch,
|
|
73
76
|
git,
|
|
74
77
|
hasTaskPlan,
|
|
@@ -92,7 +95,7 @@ import {
|
|
|
92
95
|
statWorkspacePath,
|
|
93
96
|
updateRemoteToken,
|
|
94
97
|
verifyGitCredential
|
|
95
|
-
} from "./chunk-
|
|
98
|
+
} from "./chunk-KLM6ZOUX.js";
|
|
96
99
|
import {
|
|
97
100
|
registerBootMilestoneSocketFallback,
|
|
98
101
|
reportBootMilestone
|
|
@@ -547,6 +550,8 @@ var MAX_TRACKED_MESSAGES = 200;
|
|
|
547
550
|
var CHAT_TEXT_MAX = 16e3;
|
|
548
551
|
var CHAT_TOOL_INPUT_MAX = 1900;
|
|
549
552
|
var CHAT_TOOL_OUTPUT_MAX = 1900;
|
|
553
|
+
var OPENCODE_LIVENESS_THROTTLE_MS = 5e3;
|
|
554
|
+
var MAX_TRACKED_CHILD_SESSIONS = 100;
|
|
550
555
|
function truncate(text, max) {
|
|
551
556
|
return text.length > max ? `${text.slice(0, max)}\u2026` : text;
|
|
552
557
|
}
|
|
@@ -582,6 +587,9 @@ var OpenCodeEventSource = class {
|
|
|
582
587
|
relayedTextParts = /* @__PURE__ */ new Set();
|
|
583
588
|
relayedToolUses = /* @__PURE__ */ new Set();
|
|
584
589
|
relayedToolResults = /* @__PURE__ */ new Set();
|
|
590
|
+
/** Session ids opencode reported with a `parentID` — subagent sessions. */
|
|
591
|
+
childSessions = /* @__PURE__ */ new Set();
|
|
592
|
+
lastLivenessAt = Number.NEGATIVE_INFINITY;
|
|
585
593
|
/** The opencode-assigned session id, once any event has carried it. */
|
|
586
594
|
get sessionId() {
|
|
587
595
|
return this.latchedSessionId;
|
|
@@ -595,11 +603,21 @@ var OpenCodeEventSource = class {
|
|
|
595
603
|
handleRecord(raw) {
|
|
596
604
|
if (typeof raw !== "object" || raw === null) return;
|
|
597
605
|
const event = raw;
|
|
606
|
+
this.trackChildSession(event);
|
|
598
607
|
this.latchSessionId(event);
|
|
608
|
+
if (this.isForeignSession(event)) {
|
|
609
|
+
if (this.active) this.emitLiveness();
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
599
612
|
const info = busInfoOf(event);
|
|
600
613
|
if (info?.id && info.role) this.trackRole(info.id, info.role);
|
|
601
614
|
if (isBusyEvent(event)) {
|
|
602
615
|
if (!this.active) this.beginBusTurn();
|
|
616
|
+
this.emitLiveness();
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
if (isRetryEvent(event)) {
|
|
620
|
+
if (this.active) this.emitLiveness();
|
|
603
621
|
return;
|
|
604
622
|
}
|
|
605
623
|
if (isIdleEvent(event)) {
|
|
@@ -626,15 +644,58 @@ var OpenCodeEventSource = class {
|
|
|
626
644
|
this.relayAssistantPart(part);
|
|
627
645
|
accumulateUsage({ part }, this.usage);
|
|
628
646
|
const mapped = mapOpenCodeEvent({ part });
|
|
629
|
-
if (!mapped)
|
|
647
|
+
if (!mapped) {
|
|
648
|
+
this.emitLiveness();
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
630
651
|
this.emit(mapped);
|
|
631
652
|
if (mapped.type === "assistant") {
|
|
632
653
|
const block = mapped.message.content[0];
|
|
633
654
|
if (block?.type === "text" && block.text) this.assistantText += block.text;
|
|
634
655
|
}
|
|
635
656
|
}
|
|
657
|
+
/**
|
|
658
|
+
* Local-only proof the turn is live. Throttled per turn; `beginBusTurn`
|
|
659
|
+
* resets the floor so every turn's `busy` gets through.
|
|
660
|
+
*/
|
|
661
|
+
emitLiveness() {
|
|
662
|
+
const now = Date.now();
|
|
663
|
+
if (now - this.lastLivenessAt < OPENCODE_LIVENESS_THROTTLE_MS) return;
|
|
664
|
+
this.lastLivenessAt = now;
|
|
665
|
+
this.emit({ type: "tool_progress", tool_name: "OpenCode", elapsed_time_seconds: 0 });
|
|
666
|
+
}
|
|
667
|
+
/**
|
|
668
|
+
* A record from another session. Known children (a `parentID` was seen)
|
|
669
|
+
* always are; an unknown session counts as foreign only mid-turn, where
|
|
670
|
+
* the only other session on the bus is a subagent. Outside a turn it is
|
|
671
|
+
* processed as before, and one that goes `busy` becomes the new root — a
|
|
672
|
+
* human's `/new` in the parked TUI opens a passive turn and later spawns
|
|
673
|
+
* resume into it.
|
|
674
|
+
*/
|
|
675
|
+
isForeignSession(event) {
|
|
676
|
+
const id = busSessionIdOf(event);
|
|
677
|
+
if (!id || !this.latchedSessionId || id === this.latchedSessionId) return false;
|
|
678
|
+
if (this.childSessions.has(id) || this.active) return true;
|
|
679
|
+
if (isBusyEvent(event)) {
|
|
680
|
+
this.latchedSessionId = id;
|
|
681
|
+
this.onSessionId?.(id);
|
|
682
|
+
}
|
|
683
|
+
return false;
|
|
684
|
+
}
|
|
685
|
+
trackChildSession(event) {
|
|
686
|
+
if (event.type !== "session.created" && event.type !== "session.updated") return;
|
|
687
|
+
const info = event.properties?.info;
|
|
688
|
+
if (typeof info?.id !== "string" || typeof info.parentID !== "string") return;
|
|
689
|
+
if (!info.parentID) return;
|
|
690
|
+
this.childSessions.add(info.id);
|
|
691
|
+
if (this.childSessions.size > MAX_TRACKED_CHILD_SESSIONS) {
|
|
692
|
+
const oldest = this.childSessions.values().next().value;
|
|
693
|
+
if (oldest !== void 0) this.childSessions.delete(oldest);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
636
696
|
beginBusTurn() {
|
|
637
697
|
this.active = true;
|
|
698
|
+
this.lastLivenessAt = Number.NEGATIVE_INFINITY;
|
|
638
699
|
this.usage = { inputTokens: 0, outputTokens: 0, totalCostUsd: 0 };
|
|
639
700
|
this.assistantText = "";
|
|
640
701
|
this.relayedTextParts.clear();
|
|
@@ -702,7 +763,7 @@ var OpenCodeEventSource = class {
|
|
|
702
763
|
latchSessionId(event) {
|
|
703
764
|
if (this.latchedSessionId) return;
|
|
704
765
|
const id = busSessionIdOf(event);
|
|
705
|
-
if (!id) return;
|
|
766
|
+
if (!id || this.childSessions.has(id)) return;
|
|
706
767
|
this.latchedSessionId = id;
|
|
707
768
|
this.onSessionId?.(id);
|
|
708
769
|
}
|
|
@@ -714,6 +775,9 @@ var OpenCodeEventSource = class {
|
|
|
714
775
|
}
|
|
715
776
|
}
|
|
716
777
|
};
|
|
778
|
+
function isRetryEvent(event) {
|
|
779
|
+
return event.type === "session.status" && event.properties?.status?.type === "retry";
|
|
780
|
+
}
|
|
717
781
|
function describeSessionError(event) {
|
|
718
782
|
const error = event.properties?.error;
|
|
719
783
|
if (error && typeof error.message === "string") return error.message;
|
|
@@ -1005,6 +1069,7 @@ var JsonlTailer = class {
|
|
|
1005
1069
|
|
|
1006
1070
|
// src/harness/codex/event-source.ts
|
|
1007
1071
|
var USAGE_CAP_PATTERN = /usage_limit_(?:reached|exceeded)|rate_limit_reached|UsageLimitReached|hit your usage limit/i;
|
|
1072
|
+
var CODEX_LIVENESS_THROTTLE_MS = 5e3;
|
|
1008
1073
|
var WEEKLY_WINDOW_MINUTES = 24 * 60;
|
|
1009
1074
|
function isUsageCap(error) {
|
|
1010
1075
|
return [error.codex_error_info, error.code, error.type, error.message].some(
|
|
@@ -1021,6 +1086,9 @@ var CodexEventSource = class {
|
|
|
1021
1086
|
onSession;
|
|
1022
1087
|
chat;
|
|
1023
1088
|
sessionId = null;
|
|
1089
|
+
/** UserPromptSubmit seen and no completion/interrupt since. */
|
|
1090
|
+
turnOpen = false;
|
|
1091
|
+
lastLivenessAt = Number.NEGATIVE_INFINITY;
|
|
1024
1092
|
completed = /* @__PURE__ */ new Set();
|
|
1025
1093
|
transcript = null;
|
|
1026
1094
|
/** Last reported reading per rate-limit window, keyed by `five_hour` / `seven_day`. */
|
|
@@ -1034,13 +1102,18 @@ var CodexEventSource = class {
|
|
|
1034
1102
|
this.sessionId = id;
|
|
1035
1103
|
this.onSession(id);
|
|
1036
1104
|
}
|
|
1037
|
-
if (id !== this.sessionId)
|
|
1105
|
+
if (id !== this.sessionId) {
|
|
1106
|
+
this.emitLiveness();
|
|
1107
|
+
return;
|
|
1108
|
+
}
|
|
1038
1109
|
if (e.hook_event_name === "SessionStart") this.watchTranscript(e);
|
|
1039
1110
|
if (e.type === "agent-turn-complete") {
|
|
1040
1111
|
this.finish(e);
|
|
1041
1112
|
return;
|
|
1042
1113
|
}
|
|
1043
1114
|
if (e.hook_event_name === "UserPromptSubmit") {
|
|
1115
|
+
this.turnOpen = true;
|
|
1116
|
+
this.lastLivenessAt = Date.now();
|
|
1044
1117
|
this.emit({ type: "tool_progress", tool_name: "Codex", elapsed_time_seconds: 0 });
|
|
1045
1118
|
if (typeof e.prompt === "string")
|
|
1046
1119
|
this.chat({ kind: "user_text", text: e.prompt.slice(0, 16e3) });
|
|
@@ -1053,6 +1126,7 @@ var CodexEventSource = class {
|
|
|
1053
1126
|
elapsed_time_seconds: 0
|
|
1054
1127
|
});
|
|
1055
1128
|
} else if (e.hook_event_name === "Interrupt") {
|
|
1129
|
+
this.turnOpen = false;
|
|
1056
1130
|
this.emit({ type: "result", subtype: "error", errors: ["Codex turn interrupted"] });
|
|
1057
1131
|
this.chat({ kind: "turn_end" });
|
|
1058
1132
|
}
|
|
@@ -1062,6 +1136,14 @@ var CodexEventSource = class {
|
|
|
1062
1136
|
await this.transcript?.flush();
|
|
1063
1137
|
this.transcript = null;
|
|
1064
1138
|
}
|
|
1139
|
+
/** Throttled local-only liveness; silent unless a turn is open. */
|
|
1140
|
+
emitLiveness() {
|
|
1141
|
+
if (!this.turnOpen) return;
|
|
1142
|
+
const now = Date.now();
|
|
1143
|
+
if (now - this.lastLivenessAt < CODEX_LIVENESS_THROTTLE_MS) return;
|
|
1144
|
+
this.lastLivenessAt = now;
|
|
1145
|
+
this.emit({ type: "tool_progress", tool_name: "Codex", elapsed_time_seconds: 0 });
|
|
1146
|
+
}
|
|
1065
1147
|
watchTranscript(e) {
|
|
1066
1148
|
if (this.transcript || typeof e.transcript_path !== "string" || typeof e.transcript_offset !== "number" || e.transcript_offset < 0)
|
|
1067
1149
|
return;
|
|
@@ -1076,9 +1158,10 @@ var CodexEventSource = class {
|
|
|
1076
1158
|
handleTranscriptRecord(raw) {
|
|
1077
1159
|
if (!raw || typeof raw !== "object") return;
|
|
1078
1160
|
const record = raw;
|
|
1079
|
-
if (
|
|
1080
|
-
return;
|
|
1161
|
+
if (!record.payload || typeof record.payload !== "object") return;
|
|
1081
1162
|
const event = record.payload;
|
|
1163
|
+
if (event.type !== "task_complete") this.emitLiveness();
|
|
1164
|
+
if (record.type !== "event_msg") return;
|
|
1082
1165
|
if (event.type === "token_count") {
|
|
1083
1166
|
this.handleTokenCount(event);
|
|
1084
1167
|
return;
|
|
@@ -1087,6 +1170,7 @@ var CodexEventSource = class {
|
|
|
1087
1170
|
const turn = event.turn_id;
|
|
1088
1171
|
if (typeof turn !== "string" || this.completed.has(turn)) return;
|
|
1089
1172
|
this.rememberTurn(turn);
|
|
1173
|
+
this.turnOpen = false;
|
|
1090
1174
|
const error = event.error;
|
|
1091
1175
|
if (isUsageCap(error)) this.emitUsageCap();
|
|
1092
1176
|
this.emit({
|
|
@@ -1175,6 +1259,7 @@ var CodexEventSource = class {
|
|
|
1175
1259
|
const turn = e["turn-id"];
|
|
1176
1260
|
if (typeof turn !== "string" || this.completed.has(turn)) return;
|
|
1177
1261
|
this.rememberTurn(turn);
|
|
1262
|
+
this.turnOpen = false;
|
|
1178
1263
|
const text = typeof e["last-assistant-message"] === "string" ? e["last-assistant-message"] : "";
|
|
1179
1264
|
if (text) {
|
|
1180
1265
|
this.emit({
|
|
@@ -2640,6 +2725,7 @@ var ClaudeTuiAdapter = class {
|
|
|
2640
2725
|
};
|
|
2641
2726
|
|
|
2642
2727
|
// src/harness/pty/session.ts
|
|
2728
|
+
var SUBMIT_PROVING_PROGRESS_ADAPTERS = /* @__PURE__ */ new Set(["codex", "opencode"]);
|
|
2643
2729
|
var PtySession = class {
|
|
2644
2730
|
constructor(prompt, options, resume, bridge, adapter = new ClaudeTuiAdapter()) {
|
|
2645
2731
|
this.options = options;
|
|
@@ -3699,7 +3785,7 @@ var PtySession = class {
|
|
|
3699
3785
|
if (this.pendingPlanApproval && event.type === "result") {
|
|
3700
3786
|
this.disarmPlanDialogAutoAccept();
|
|
3701
3787
|
}
|
|
3702
|
-
if (this.pendingSubmitNudge && (event.type === "assistant" || event.type === "result" || this.adapter.id
|
|
3788
|
+
if (this.pendingSubmitNudge && (event.type === "assistant" || event.type === "result" || SUBMIT_PROVING_PROGRESS_ADAPTERS.has(this.adapter.id) && event.type === "tool_progress")) {
|
|
3703
3789
|
this.disarmSubmitNudge();
|
|
3704
3790
|
}
|
|
3705
3791
|
this.synthesizeRateLimitFromBanner(event);
|
|
@@ -4916,6 +5002,13 @@ var CodexTuiAdapter = class {
|
|
|
4916
5002
|
// The pod image owns CLI upgrades. An interactive update would try to
|
|
4917
5003
|
// replace the root-owned global package from the conveyor user account.
|
|
4918
5004
|
check_for_update_on_startup: false,
|
|
5005
|
+
// Acknowledge 0.157.0's model promotions so unattended sessions start.
|
|
5006
|
+
// This dismisses the notices; --model below still selects the saved model.
|
|
5007
|
+
"notice.model_migrations": {
|
|
5008
|
+
"gpt-5.6-terra": "gpt-6-sol",
|
|
5009
|
+
"gpt-5.6-sol": "gpt-6-sol",
|
|
5010
|
+
"gpt-5.6-luna": "gpt-6-luna"
|
|
5011
|
+
},
|
|
4919
5012
|
sqlite_home: codexSqliteHome(this.env),
|
|
4920
5013
|
approval_policy: "never",
|
|
4921
5014
|
// Always full access, plan mode included. Codex's own read-only mode is
|
|
@@ -5214,7 +5307,10 @@ var DirectStreamController = class {
|
|
|
5214
5307
|
this.starting = true;
|
|
5215
5308
|
const created = new PtyStreamServer({
|
|
5216
5309
|
sessionId: this.reporter.sessionId,
|
|
5217
|
-
onInput: (data) =>
|
|
5310
|
+
onInput: (data) => {
|
|
5311
|
+
this.reporter.notePtyInput();
|
|
5312
|
+
this.inputHandler?.(data);
|
|
5313
|
+
},
|
|
5218
5314
|
onResize: (cols, rows) => {
|
|
5219
5315
|
this.directDims = { cols, rows };
|
|
5220
5316
|
this.applyDims();
|
|
@@ -6748,6 +6844,7 @@ function compileNumber(z11, spec) {
|
|
|
6748
6844
|
function compileArray(z11, spec) {
|
|
6749
6845
|
let schema = z11.array(compileField(z11, spec.item));
|
|
6750
6846
|
if (spec.min !== void 0) schema = schema.min(spec.min);
|
|
6847
|
+
if (spec.max !== void 0) schema = schema.max(spec.max);
|
|
6751
6848
|
return schema;
|
|
6752
6849
|
}
|
|
6753
6850
|
function compileBase(z11, spec) {
|
|
@@ -6877,16 +6974,24 @@ var readTaskChatContract = defineToolContract({
|
|
|
6877
6974
|
}
|
|
6878
6975
|
}
|
|
6879
6976
|
});
|
|
6977
|
+
var listTagsDetail = f.optional(
|
|
6978
|
+
f.enum(["summary", "full"], {
|
|
6979
|
+
desc: `"summary" (default) returns one compact row per tag with a contextPathCount. "full" also ships each tag's contextPaths inline (each link with its verification status). Full mode can exceed a client's tool-output budget on a large glossary; use get_tag for one term instead.`
|
|
6980
|
+
})
|
|
6981
|
+
);
|
|
6880
6982
|
var listTagsContract = defineToolContract({
|
|
6881
6983
|
name: "list_tags",
|
|
6882
6984
|
agent: {
|
|
6883
|
-
description: "List the project glossary
|
|
6884
|
-
fields: {
|
|
6985
|
+
description: "List the whole project glossary in one call. The default summary gives every tag's id, name, color, description, parent/child tag ids, whether it carries a full overview (hasOverview), its attachmentCount (files labelled as examples of the term), and its contextPathCount (the rule/doc/file/folder links it wires into agent context \u2014 `0` means none). Pass detail: \"full\" to ship the contextPaths themselves inline. Use get_tag for one term's full overview and full link verification. Use the ids with get_tag / update_tag.",
|
|
6986
|
+
fields: {
|
|
6987
|
+
detail: listTagsDetail
|
|
6988
|
+
}
|
|
6885
6989
|
},
|
|
6886
6990
|
mcp: {
|
|
6887
|
-
description:
|
|
6991
|
+
description: 'List all project tags in one call. The default summary gives names, IDs, colors, descriptions, hierarchy (parent/child ids), a hasOverview flag, an attachmentCount (files labelled as examples of the term \u2014 read the tiles with list_tag_attachments), and a contextPathCount (the rule/doc/file/folder links each tag wires into agent context \u2014 `0` means none). Pass detail: "full" to ship the contextPaths themselves inline. Call get_tag for one term\'s full overview and full link verification. Pass projectId to target a specific project; otherwise the configured default project is used.',
|
|
6888
6992
|
fields: {
|
|
6889
|
-
projectId: mcpProjectId
|
|
6993
|
+
projectId: mcpProjectId,
|
|
6994
|
+
detail: listTagsDetail
|
|
6890
6995
|
}
|
|
6891
6996
|
}
|
|
6892
6997
|
});
|
|
@@ -7022,7 +7127,7 @@ var updateTaskContract = defineToolContract({
|
|
|
7022
7127
|
}
|
|
7023
7128
|
},
|
|
7024
7129
|
mcp: {
|
|
7025
|
-
description: "Update task fields: title, description, plan, status, risk, story points, assignment, githubBranch, or tags. Set status to claim a card (InProgress), triage it (Open), or cancel it (Cancelled); for review approvals prefer approve_task / request_changes, which guard against stale-state races. Tags are additive/subtractive \u2014 pass addTags/removeTags with tag names (not a replace-set). Pass projectId to target a specific project; otherwise the configured default project is used. Moving a task beyond Planning auto-fills any missing icon, story points, and agent assignment \u2014 don't spend turns on them; pass storyPointValue only to correct the sizing yourself. For subtasks use update_subtask.",
|
|
7130
|
+
description: "Update task fields: title, description, plan, status, risk, story points, assignment, githubBranch, onHold, or tags. Set status to claim a card (InProgress), triage it (Open), or cancel it (Cancelled); for review approvals prefer approve_task / request_changes, which guard against stale-state races. Set onHold to park a card (true) or bring it back to the active board (false) without cancelling it. Tags are additive/subtractive \u2014 pass addTags/removeTags with tag names (not a replace-set). Pass projectId to target a specific project; otherwise the configured default project is used. Moving a task beyond Planning auto-fills any missing icon, story points, and agent assignment \u2014 don't spend turns on them; pass storyPointValue only to correct the sizing yourself. For subtasks use update_subtask.",
|
|
7026
7131
|
fields: {
|
|
7027
7132
|
projectId: mcpProjectId,
|
|
7028
7133
|
taskId: f.string({ desc: "The task ID" }),
|
|
@@ -7053,6 +7158,11 @@ var updateTaskContract = defineToolContract({
|
|
|
7053
7158
|
)
|
|
7054
7159
|
),
|
|
7055
7160
|
githubBranch: f.optional(f.nullable(f.string({ desc: GITHUB_BRANCH_DESC }))),
|
|
7161
|
+
onHold: f.optional(
|
|
7162
|
+
f.boolean({
|
|
7163
|
+
desc: "Park the card on hold (true) or return it to the active board (false). On hold hides the card from the active columns without cancelling it; a card already at an active work status is demoted to Open when parked."
|
|
7164
|
+
})
|
|
7165
|
+
),
|
|
7056
7166
|
addTags: f.optional(
|
|
7057
7167
|
f.array(f.string(), {
|
|
7058
7168
|
desc: 'Tag names to add to the card (e.g. ["refactor"]). Additive \u2014 existing tags are kept. Unknown names are rejected; use list_tags to see available tags or manage_tags to create one.'
|
|
@@ -7096,9 +7206,20 @@ var testStatuses = f.optional(
|
|
|
7096
7206
|
})
|
|
7097
7207
|
);
|
|
7098
7208
|
var setManualTestItems = f.array(
|
|
7099
|
-
f.object({
|
|
7100
|
-
|
|
7209
|
+
f.object({
|
|
7210
|
+
title: f.string({
|
|
7211
|
+
min: 1,
|
|
7212
|
+
max: MAX_MANUAL_TEST_TITLE_LENGTH,
|
|
7213
|
+
desc: "One sentence a non-engineer can follow: where to go, what to do, what they should see. No commands, no code."
|
|
7214
|
+
})
|
|
7215
|
+
}),
|
|
7216
|
+
{
|
|
7217
|
+
min: 1,
|
|
7218
|
+
max: MAX_MANUAL_TESTS_PER_TASK,
|
|
7219
|
+
desc: `Manual tests to add. A card holds at most ${MAX_MANUAL_TESTS_PER_TASK}; most changes need 1, and a change with no user-visible behavior needs none.`
|
|
7220
|
+
}
|
|
7101
7221
|
);
|
|
7222
|
+
var setManualTestsBar = 'A manual test is a real user path in plain language ("Open a card with a PR: the Pull Request slat sits directly under Description"), not an engineering check. Never record lint, typecheck, unit tests, CI, curl, database, log, or deploy steps; those run automatically. Record at most 5 per card, usually 1, and none when the change has no user-visible behavior. Existing items with the same title are skipped; items that name an automated step or exceed the cap are rejected and reported back.';
|
|
7102
7223
|
var titleToEdit = f.string({ min: 1, desc: "The current title of the manual test to edit" });
|
|
7103
7224
|
var newTitle = f.string({ min: 1, desc: "The new title for the manual test" });
|
|
7104
7225
|
var titleToRemove = f.string({ min: 1, desc: "The title of the manual test to remove" });
|
|
@@ -7152,13 +7273,13 @@ var queryManualTestsContract = defineToolContract({
|
|
|
7152
7273
|
var setManualTestsContract = defineToolContract({
|
|
7153
7274
|
name: "set_manual_tests",
|
|
7154
7275
|
agent: {
|
|
7155
|
-
description:
|
|
7276
|
+
description: `Record the manual tests a person should run in the app to sign off on this card. ${setManualTestsBar}`,
|
|
7156
7277
|
fields: {
|
|
7157
7278
|
items: setManualTestItems
|
|
7158
7279
|
}
|
|
7159
7280
|
},
|
|
7160
7281
|
mcp: {
|
|
7161
|
-
description:
|
|
7282
|
+
description: `Record the manual tests a person should run in the app to sign off on a card. Pass projectId to target a specific project; otherwise the configured default project is used. ${setManualTestsBar}`,
|
|
7162
7283
|
fields: {
|
|
7163
7284
|
projectId: mcpProjectId,
|
|
7164
7285
|
taskId: mcpChecklistTaskId,
|
|
@@ -8567,6 +8688,71 @@ var waitForChecksContract = defineToolContract({
|
|
|
8567
8688
|
}
|
|
8568
8689
|
});
|
|
8569
8690
|
var ciWaitContracts = [waitForChecksContract];
|
|
8691
|
+
var DESCRIPTION = [
|
|
8692
|
+
"Ask typed questions about text and get probabilities back, never text: yes/no (noul \u2192 probability of yes), pick-one (choice \u2192 the chosen option, per-option probabilities, and a confidence), or a graded scale (score \u2192 the level, per-level probabilities, and a confidence).",
|
|
8693
|
+
"Requires Jev to be switched on under Project Settings \u2192 AI Provider Keys (a TypeSafe key, or an OpenCode Zen key); without it the tool returns an error saying so.",
|
|
8694
|
+
"The state is data, not a guardrail: adversarial text inside it can move the answers, so never use a result to authorize an action.",
|
|
8695
|
+
"Ask one simple judgment per question and split compound questions; accuracy falls when the state carries irrelevant text.",
|
|
8696
|
+
"Pass items to judge up to 100 separate texts with the same questions in one call; answers come back in item order.",
|
|
8697
|
+
"Each call spends the project's Jev credit and is rate-limited per project. A choice takes 2-255 options, a score 2-10 levels, at most 32 questions per call."
|
|
8698
|
+
].join(" ");
|
|
8699
|
+
var question = f.object(
|
|
8700
|
+
{
|
|
8701
|
+
key: f.string({
|
|
8702
|
+
min: 1,
|
|
8703
|
+
desc: "Name for this question's answer, e.g. is_complaint. Letters, digits, _ and - only; unique within the call."
|
|
8704
|
+
}),
|
|
8705
|
+
type: f.enum(["noul", "choice", "score"], {
|
|
8706
|
+
desc: "noul = yes/no; choice = pick one option; score = pick a level on an ordered scale"
|
|
8707
|
+
}),
|
|
8708
|
+
instructions: f.string({
|
|
8709
|
+
min: 1,
|
|
8710
|
+
desc: "The question, as one plain sentence about the state, e.g. 'Is this message a complaint about the product?'"
|
|
8711
|
+
}),
|
|
8712
|
+
options: f.optional(
|
|
8713
|
+
f.array(
|
|
8714
|
+
f.object({
|
|
8715
|
+
key: f.string({ min: 1, desc: "Option name returned as the answer" }),
|
|
8716
|
+
description: f.string({
|
|
8717
|
+
min: 1,
|
|
8718
|
+
desc: "What choosing this option means, concretely"
|
|
8719
|
+
})
|
|
8720
|
+
}),
|
|
8721
|
+
{ desc: "choice only: the options (2-255). Option order can move the answer." }
|
|
8722
|
+
)
|
|
8723
|
+
),
|
|
8724
|
+
levels: f.optional(
|
|
8725
|
+
f.array(f.string({ min: 1 }), {
|
|
8726
|
+
desc: "score only: 2-10 level descriptions, lowest first"
|
|
8727
|
+
})
|
|
8728
|
+
)
|
|
8729
|
+
},
|
|
8730
|
+
{ desc: "One typed question" }
|
|
8731
|
+
);
|
|
8732
|
+
var stateDesc = "The thing being judged, as plain text or JSON. Required unless items is given; with items it is ignored.";
|
|
8733
|
+
var itemsDesc = "Up to 100 separate texts (each up to 8,000 characters), each judged on its own with the same questions. Use this for bulk classification instead of one call per item.";
|
|
8734
|
+
var questionsDesc = "1-32 questions, all answered independently against the same state.";
|
|
8735
|
+
var evaluateQuestionsContract = defineToolContract({
|
|
8736
|
+
name: "evaluate_questions",
|
|
8737
|
+
agent: {
|
|
8738
|
+
description: DESCRIPTION,
|
|
8739
|
+
fields: {
|
|
8740
|
+
state: f.optional(f.string({ desc: stateDesc })),
|
|
8741
|
+
questions: f.array(question, { min: 1, desc: questionsDesc }),
|
|
8742
|
+
items: f.optional(f.array(f.string(), { desc: itemsDesc }))
|
|
8743
|
+
}
|
|
8744
|
+
},
|
|
8745
|
+
mcp: {
|
|
8746
|
+
description: `${DESCRIPTION} Pass projectId to target a specific project; otherwise the configured default project is used.`,
|
|
8747
|
+
fields: {
|
|
8748
|
+
projectId: mcpProjectId,
|
|
8749
|
+
state: f.optional(f.string({ desc: stateDesc })),
|
|
8750
|
+
questions: f.array(question, { min: 1, desc: questionsDesc }),
|
|
8751
|
+
items: f.optional(f.array(f.string(), { desc: itemsDesc }))
|
|
8752
|
+
}
|
|
8753
|
+
}
|
|
8754
|
+
});
|
|
8755
|
+
var evaluateContracts = [evaluateQuestionsContract];
|
|
8570
8756
|
var TOOL_CONTRACTS = Object.fromEntries(
|
|
8571
8757
|
[
|
|
8572
8758
|
...tasksContracts,
|
|
@@ -8583,7 +8769,8 @@ var TOOL_CONTRACTS = Object.fromEntries(
|
|
|
8583
8769
|
...driveContracts,
|
|
8584
8770
|
...meetingsContracts,
|
|
8585
8771
|
...logsContracts,
|
|
8586
|
-
...ciWaitContracts
|
|
8772
|
+
...ciWaitContracts,
|
|
8773
|
+
...evaluateContracts
|
|
8587
8774
|
].map((contract) => [contract.name, contract])
|
|
8588
8775
|
);
|
|
8589
8776
|
|
|
@@ -9588,6 +9775,7 @@ function buildSetManualTestsTool(connection) {
|
|
|
9588
9775
|
});
|
|
9589
9776
|
const parts = [`Created ${result.created} manual test item(s).`];
|
|
9590
9777
|
if (result.skipped > 0) parts.push(`Skipped ${result.skipped} duplicate(s).`);
|
|
9778
|
+
for (const item of result.rejected ?? []) parts.push(describeManualTestRejection(item));
|
|
9591
9779
|
return textResult(parts.join(" "));
|
|
9592
9780
|
} catch (error) {
|
|
9593
9781
|
const msg = error instanceof Error ? error.message : "Unknown error";
|
|
@@ -10149,9 +10337,9 @@ async function rejectBadContextPaths(contextPaths, workspaceDir) {
|
|
|
10149
10337
|
function buildListTagsTool(connection, projectId) {
|
|
10150
10338
|
return defineContractTool(
|
|
10151
10339
|
listTagsContract,
|
|
10152
|
-
async () => {
|
|
10340
|
+
async ({ detail }) => {
|
|
10153
10341
|
try {
|
|
10154
|
-
const tags = await connection.call("listProjectTags", { projectId });
|
|
10342
|
+
const tags = await connection.call("listProjectTags", { projectId, detail });
|
|
10155
10343
|
return textResult(JSON.stringify(tags, null, 2));
|
|
10156
10344
|
} catch (error) {
|
|
10157
10345
|
return errText("Failed to list tags", error);
|
|
@@ -11016,6 +11204,31 @@ function settleTools(connection, projectId) {
|
|
|
11016
11204
|
];
|
|
11017
11205
|
}
|
|
11018
11206
|
|
|
11207
|
+
// src/tools/evaluate-tools.ts
|
|
11208
|
+
function buildEvaluateTools(connection, projectId) {
|
|
11209
|
+
return [
|
|
11210
|
+
defineContractTool(
|
|
11211
|
+
evaluateQuestionsContract,
|
|
11212
|
+
async (input) => {
|
|
11213
|
+
try {
|
|
11214
|
+
const res = await connection.call("evaluateQuestions", {
|
|
11215
|
+
projectId,
|
|
11216
|
+
state: input.state,
|
|
11217
|
+
items: input.items,
|
|
11218
|
+
questions: input.questions
|
|
11219
|
+
});
|
|
11220
|
+
return textResult(formatEvaluateQuestionsResult(res));
|
|
11221
|
+
} catch (error) {
|
|
11222
|
+
return textResult(
|
|
11223
|
+
`evaluate_questions failed: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
11224
|
+
);
|
|
11225
|
+
}
|
|
11226
|
+
},
|
|
11227
|
+
{ annotations: { readOnlyHint: true } }
|
|
11228
|
+
)
|
|
11229
|
+
];
|
|
11230
|
+
}
|
|
11231
|
+
|
|
11019
11232
|
// src/tools/connected-tools.ts
|
|
11020
11233
|
function connectedToolsFor(connection, context) {
|
|
11021
11234
|
const projectId = context?.projectId;
|
|
@@ -11028,6 +11241,9 @@ function connectedToolsFor(connection, context) {
|
|
|
11028
11241
|
// Always available: the decision tables exist on every project, and a fork
|
|
11029
11242
|
// an agent cannot file is a fork it assumes its way past instead.
|
|
11030
11243
|
...buildDecisionTools(connection, projectId),
|
|
11244
|
+
// Ungated: whether the project has Jev on is answered by calling it, and
|
|
11245
|
+
// the error names what an admin has to switch on.
|
|
11246
|
+
...buildEvaluateTools(connection, projectId),
|
|
11031
11247
|
...context.googleAnalyticsConfigured ? [buildAnalyticsSummaryTool(connection, projectId)] : [],
|
|
11032
11248
|
...context.gcpLogsConfigured ? [buildQueryGcpLogsTool(connection, projectId)] : [],
|
|
11033
11249
|
...context.grafanaLogsConfigured ? [buildQueryGrafanaLogsTool(connection, projectId)] : []
|
|
@@ -11035,8 +11251,6 @@ function connectedToolsFor(connection, context) {
|
|
|
11035
11251
|
}
|
|
11036
11252
|
|
|
11037
11253
|
// src/tools/code-review-tools.ts
|
|
11038
|
-
import { execFile } from "child_process";
|
|
11039
|
-
import { promisify } from "util";
|
|
11040
11254
|
import { z as z10 } from "zod";
|
|
11041
11255
|
async function endReviewSession(connection, reason) {
|
|
11042
11256
|
await connection.call("endReviewSession", {
|
|
@@ -11047,101 +11261,6 @@ async function endReviewSession(connection, reason) {
|
|
|
11047
11261
|
var RISK_LEVELS = ["critical", "high", "medium", "low"];
|
|
11048
11262
|
var reviewedShaSchema = z10.string().regex(/^[0-9a-f]{40}$/i).describe("REQUIRED. The full 40-character commit SHA this verdict reviews.");
|
|
11049
11263
|
var riskDescription = "REQUIRED. The risk level this change carries, judged by the surface area it touches: critical = touches critical/foundational surface, high = important surface, medium = moderate, low = small/isolated. Set this on every verdict. You have authority to override a risk level already set on the task if you disagree with it.";
|
|
11050
|
-
var ReviewGuideToolSchema = z10.strictObject({
|
|
11051
|
-
reviewedSha: z10.string().regex(/^[0-9a-f]{40}$/i).describe(
|
|
11052
|
-
"REQUIRED. The PR's current head as a full 40-char SHA. Run `git rev-parse HEAD` immediately before this call \u2014 never extend an abbreviated hash into 40 characters."
|
|
11053
|
-
),
|
|
11054
|
-
overview: z10.string().min(1).max(6e4).describe("REQUIRED. Plain-text walkthrough intro, max 3000 characters. Keep it short."),
|
|
11055
|
-
sections: z10.array(
|
|
11056
|
-
z10.strictObject({
|
|
11057
|
-
title: z10.string().min(1).max(160),
|
|
11058
|
-
explanation: z10.string().min(1).max(2e3),
|
|
11059
|
-
classification: z10.enum(["core", "supporting"]).optional(),
|
|
11060
|
-
files: z10.array(
|
|
11061
|
-
z10.strictObject({
|
|
11062
|
-
path: z10.string().min(1).max(500).describe(
|
|
11063
|
-
"A file the PR's diff actually changed. Context files you merely read are rejected."
|
|
11064
|
-
),
|
|
11065
|
-
startLine: z10.number().int().positive().max(1e6).optional(),
|
|
11066
|
-
endLine: z10.number().int().positive().max(1e6).optional(),
|
|
11067
|
-
hunkHeader: z10.string().min(1).max(300).optional().describe(
|
|
11068
|
-
"Optional anchor, matched byte-exactly against the full hunk header line from `git diff` INCLUDING the context text after the second @@. Copy it verbatim from `git diff <base>..HEAD -- <file> | grep '^@@'`, or omit anchors entirely (path-only entries always validate)."
|
|
11069
|
-
)
|
|
11070
|
-
})
|
|
11071
|
-
).min(1).max(20)
|
|
11072
|
-
})
|
|
11073
|
-
).min(1).max(12).optional().describe(
|
|
11074
|
-
"REQUIRED top-level array (never text appended to overview) of ordered conceptual sections."
|
|
11075
|
-
)
|
|
11076
|
-
});
|
|
11077
|
-
var FLATTENED_SECTIONS_PATTERN = /<\/overview>\s*(?:<parameter name="sections">|<sections>)/;
|
|
11078
|
-
var TRAILING_TAGS_PATTERN = /(?:\s*<\/(?:parameter|sections|invoke)>)+\s*$/;
|
|
11079
|
-
function sliceOutermostArray(tail) {
|
|
11080
|
-
const start = tail.indexOf("[");
|
|
11081
|
-
const end = tail.lastIndexOf("]");
|
|
11082
|
-
return start >= 0 && end > start ? tail.slice(start, end + 1) : null;
|
|
11083
|
-
}
|
|
11084
|
-
function recoverFlattenedGuide(overview) {
|
|
11085
|
-
const match = FLATTENED_SECTIONS_PATTERN.exec(overview);
|
|
11086
|
-
if (!match) return null;
|
|
11087
|
-
const head = overview.slice(0, match.index).trim();
|
|
11088
|
-
const tail = overview.slice(match.index + match[0].length).replace(TRAILING_TAGS_PATTERN, "").trim();
|
|
11089
|
-
for (const candidate of [tail, sliceOutermostArray(tail)]) {
|
|
11090
|
-
if (!candidate) continue;
|
|
11091
|
-
try {
|
|
11092
|
-
return { overview: head, sections: JSON.parse(candidate) };
|
|
11093
|
-
} catch {
|
|
11094
|
-
}
|
|
11095
|
-
}
|
|
11096
|
-
return null;
|
|
11097
|
-
}
|
|
11098
|
-
async function resolveGitHeadSha(cwd) {
|
|
11099
|
-
try {
|
|
11100
|
-
const stdout = workbenchEnabled() ? (await getWorkbenchClient().execFile("git", ["rev-parse", "HEAD"], {
|
|
11101
|
-
cwd,
|
|
11102
|
-
timeout: 1e4
|
|
11103
|
-
})).stdout : (await promisify(execFile)("git", ["rev-parse", "HEAD"], { cwd, timeout: 1e4 })).stdout;
|
|
11104
|
-
const sha = stdout.trim();
|
|
11105
|
-
return /^[0-9a-f]{40}$/i.test(sha) ? sha : null;
|
|
11106
|
-
} catch {
|
|
11107
|
-
return null;
|
|
11108
|
-
}
|
|
11109
|
-
}
|
|
11110
|
-
function buildPublishReviewGuideTool(connection, options = {}) {
|
|
11111
|
-
const { resolveHeadSha } = options;
|
|
11112
|
-
return defineTool(
|
|
11113
|
-
"publish_review_guide",
|
|
11114
|
-
"Publish or update the PR guide for the CURRENT PR head commit. Call right after create_pull_request succeeds, and again after every push to the branch. The head SHA is resolved from the local repo, so never hand-expand a short hash. Best-effort \u2014 it does not gate opening or updating the PR.",
|
|
11115
|
-
ReviewGuideToolSchema.shape,
|
|
11116
|
-
async ({ reviewedSha, overview, sections }) => {
|
|
11117
|
-
let resolvedOverview = overview;
|
|
11118
|
-
let resolvedSections = sections;
|
|
11119
|
-
if (resolvedSections === void 0) {
|
|
11120
|
-
const recovered = recoverFlattenedGuide(overview);
|
|
11121
|
-
if (!recovered) {
|
|
11122
|
-
throw new Error(
|
|
11123
|
-
"publish_review_guide requires a top-level `sections` array \u2014 an ordered list of conceptual sections, each with title, explanation, and files[]. Your call arrived with only `reviewedSha` and `overview`; the `sections` parameter never reached the server, which usually means the call encoding flattened it into `overview`. Do not append the sections to `overview` as text. Retry with sections as a real array argument, and shorten `overview` if the failure repeats."
|
|
11124
|
-
);
|
|
11125
|
-
}
|
|
11126
|
-
resolvedOverview = recovered.overview;
|
|
11127
|
-
resolvedSections = recovered.sections;
|
|
11128
|
-
}
|
|
11129
|
-
const content = ReviewGuideContentSchema.parse({
|
|
11130
|
-
overview: resolvedOverview,
|
|
11131
|
-
sections: resolvedSections
|
|
11132
|
-
});
|
|
11133
|
-
const result = await connection.call("publishReviewGuide", {
|
|
11134
|
-
sessionId: connection.sessionId,
|
|
11135
|
-
reviewedSha: (resolveHeadSha ? await resolveHeadSha() : null) ?? reviewedSha,
|
|
11136
|
-
...content
|
|
11137
|
-
});
|
|
11138
|
-
return textResult(
|
|
11139
|
-
`Review guide published for ${result.reviewedSha}${result.replaced ? " (replaced)" : ""}.`
|
|
11140
|
-
);
|
|
11141
|
-
},
|
|
11142
|
-
{ strict: true }
|
|
11143
|
-
);
|
|
11144
|
-
}
|
|
11145
11264
|
function buildApproveCodeReviewTool(connection) {
|
|
11146
11265
|
return defineTool(
|
|
11147
11266
|
"approve_code_review",
|
|
@@ -11251,15 +11370,6 @@ function getModeTools(agentMode, connection, config, context) {
|
|
|
11251
11370
|
return config.mode === "pm" ? buildPmTools(connection) : [];
|
|
11252
11371
|
}
|
|
11253
11372
|
}
|
|
11254
|
-
function buildPrGuideToolsFor(effectiveMode, connection, config, context) {
|
|
11255
|
-
const isLeafBuild = effectiveMode === "building" || effectiveMode === "auto" || effectiveMode === "chat";
|
|
11256
|
-
const isPackRunner = config.mode === "pack";
|
|
11257
|
-
return (isLeafBuild || isPackRunner) && (isPackRunner || !context?.isParentTask) ? [
|
|
11258
|
-
buildPublishReviewGuideTool(connection, {
|
|
11259
|
-
resolveHeadSha: () => resolveGitHeadSha(config.workspaceDir)
|
|
11260
|
-
})
|
|
11261
|
-
] : [];
|
|
11262
|
-
}
|
|
11263
11373
|
function ciWaitToolsFor(effectiveMode, connection, config) {
|
|
11264
11374
|
const isPackRunner = config.mode === "pack";
|
|
11265
11375
|
return effectiveMode === "review" && !isPackRunner ? [] : [buildWaitForChecksTool(connection)];
|
|
@@ -11294,8 +11404,6 @@ var ALWAYS_LOADED_TOOLS = /* @__PURE__ */ new Set([
|
|
|
11294
11404
|
// The shared-skill card write: one name whose fields match the mcp surface,
|
|
11295
11405
|
// so a single skill text drives a local session and a pod verbatim.
|
|
11296
11406
|
"update_task",
|
|
11297
|
-
// Building/auto — the PR guide is published as part of opening the PR
|
|
11298
|
-
"publish_review_guide",
|
|
11299
11407
|
// Review mode
|
|
11300
11408
|
"approve_code_review",
|
|
11301
11409
|
"request_code_changes"
|
|
@@ -11349,7 +11457,6 @@ function buildConveyorTools(connection, config, context, agentMode) {
|
|
|
11349
11457
|
const modeTools = getModeTools(effectiveMode, connection, config, context);
|
|
11350
11458
|
const discoveryTools = effectiveMode === "discovery" || effectiveMode === "auto" || effectiveMode === "building" || effectiveMode === "chat" ? buildDiscoveryTools(connection) : [];
|
|
11351
11459
|
const codeReviewTools = effectiveMode === "review" ? buildCodeReviewTools(connection) : [];
|
|
11352
|
-
const prGuideTools = buildPrGuideToolsFor(effectiveMode, connection, config, context);
|
|
11353
11460
|
const ciWaitTools = ciWaitToolsFor(effectiveMode, connection, config);
|
|
11354
11461
|
const handoffTools = config.mode === "pm" && (effectiveMode === "discovery" || effectiveMode === "auto") ? [buildHandoffTool(connection)] : [];
|
|
11355
11462
|
const emergencyTools = [buildForceUpdateTaskStatusTool(connection)];
|
|
@@ -11362,7 +11469,6 @@ function buildConveyorTools(connection, config, context, agentMode) {
|
|
|
11362
11469
|
...modeTools,
|
|
11363
11470
|
...discoveryTools,
|
|
11364
11471
|
...codeReviewTools,
|
|
11365
|
-
...prGuideTools,
|
|
11366
11472
|
...ciWaitTools,
|
|
11367
11473
|
...handoffTools,
|
|
11368
11474
|
...glossaryTools,
|
|
@@ -12913,13 +13019,17 @@ async function runPassiveTurn(host, context) {
|
|
|
12913
13019
|
host.activeQuery = null;
|
|
12914
13020
|
}
|
|
12915
13021
|
}
|
|
13022
|
+
function parkedTuiWatchOptions(harness, cwd) {
|
|
13023
|
+
if (harness.emitsStructuredEvents === false) return { disableWedgeAbort: true };
|
|
13024
|
+
if (harness.ownsClaudeConfigHome === false) return {};
|
|
13025
|
+
return { probeMountDead: () => isConfigHomeMountDead(cwd) };
|
|
13026
|
+
}
|
|
12916
13027
|
async function trackAndRun(host, context, options, agentQuery) {
|
|
12917
13028
|
if (host.harnessKind === "pty" && options.promptDelivery !== "prefill") {
|
|
12918
|
-
const rawRelay = host.harness.emitsStructuredEvents === false;
|
|
12919
13029
|
agentQuery = watchForParkedTui(
|
|
12920
13030
|
agentQuery,
|
|
12921
13031
|
host,
|
|
12922
|
-
|
|
13032
|
+
parkedTuiWatchOptions(host.harness, options.cwd)
|
|
12923
13033
|
);
|
|
12924
13034
|
}
|
|
12925
13035
|
host.activeQuery = agentQuery;
|
|
@@ -13927,9 +14037,9 @@ function buildUnmeasurableEvent(reason, codingAgentKeyId) {
|
|
|
13927
14037
|
}
|
|
13928
14038
|
|
|
13929
14039
|
// src/runner/parent-pull-handler.ts
|
|
13930
|
-
import { execFile
|
|
13931
|
-
import { promisify
|
|
13932
|
-
var execFileAsync =
|
|
14040
|
+
import { execFile } from "child_process";
|
|
14041
|
+
import { promisify } from "util";
|
|
14042
|
+
var execFileAsync = promisify(execFile);
|
|
13933
14043
|
async function handlePullBranch(workDir, branch) {
|
|
13934
14044
|
if (!branch) return;
|
|
13935
14045
|
const current = await getCurrentBranch(workDir);
|
|
@@ -14307,6 +14417,7 @@ var SessionRunner = class _SessionRunner {
|
|
|
14307
14417
|
onGitFlush: () => void this.periodicGitFlush(),
|
|
14308
14418
|
onUsageSample: () => void this.sampleAndReportKeyUsage()
|
|
14309
14419
|
});
|
|
14420
|
+
this.connection.onPtyInputActivity(() => this.lifecycle.touchIdleTimer());
|
|
14310
14421
|
}
|
|
14311
14422
|
get state() {
|
|
14312
14423
|
return this._state;
|
|
@@ -15643,7 +15754,9 @@ ${outcome.failures.join("\n")}
|
|
|
15643
15754
|
* turn: a background launch, or an armed `ScheduleWakeup`. */
|
|
15644
15755
|
noteToolUseForBackgroundWork(event) {
|
|
15645
15756
|
if (event.type !== "tool_use" || typeof event.tool !== "string") return;
|
|
15646
|
-
this.
|
|
15757
|
+
if (resolveCardTui(this.config.runnerMode) === "claude-code") {
|
|
15758
|
+
this.backgroundWork.noteToolUse(event.tool, event.input);
|
|
15759
|
+
}
|
|
15647
15760
|
this.scheduledWakeup.noteToolUse(event.tool, event.input);
|
|
15648
15761
|
}
|
|
15649
15762
|
async setState(status) {
|