@gajae-code/coding-agent 0.9.4 → 0.9.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/dist/types/modes/acp/acp-event-mapper.d.ts +2 -0
- package/package.json +7 -7
- package/src/modes/acp/acp-agent.ts +72 -16
- package/src/modes/acp/acp-client-bridge.ts +27 -5
- package/src/modes/acp/acp-event-mapper.ts +39 -1
- package/src/modes/components/model-selector.ts +17 -5
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.9.5] - 2026-07-09
|
|
6
|
+
### Fixed
|
|
7
|
+
|
|
8
|
+
- ACP permission prompts now honor `clientCapabilities._meta.gjc.permissionHandling` and the `GJC_ACP_PERMISSION_MODE` fallback, so `auto` and `always-allow` no longer emit `session/request_permission` calls while invalid values fail safely to `prompt`.
|
|
9
|
+
- Model selector batch assignments ("Set for all role agents" / "Set for all targets") now open the reasoning-effort menu whenever any batch target requires an explicit choice (e.g. Anthropic reasoning models like `claude-fable-5`), and the chosen effort plus the full batch survive the menu. Previously the menu never appeared for Anthropic models (silently persisting `:off` selectors for every role agent), and for OpenAI/Codex models picking an effort collapsed the batch to a DEFAULT-only assignment.
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- ACP clients now receive GJC automatic-compaction start/end state through additive `session_info_update` metadata, including the compaction action, trigger, retry/abort/error outcome, and busy-to-idle phase transitions.
|
|
13
|
+
|
|
5
14
|
## [0.9.4] - 2026-07-09
|
|
6
15
|
### Fixed
|
|
7
16
|
|
|
@@ -16,6 +16,8 @@ interface AcpEventMapperOptions {
|
|
|
16
16
|
* before emitting `ToolCallLocation` entries.
|
|
17
17
|
*/
|
|
18
18
|
cwd?: string;
|
|
19
|
+
/** Phase to expose after compaction ends. Prompt-bound compaction resumes responding; idle maintenance returns idle. */
|
|
20
|
+
compactionEndPhase?: "responding" | "idle";
|
|
19
21
|
}
|
|
20
22
|
export declare function mapToolKind(toolName: string): ToolKind;
|
|
21
23
|
export declare function mapAgentWireEventPayloadToAcpSessionUpdates(payload: AgentWireEventPayload, sessionId: string, options?: AcpEventMapperOptions): SessionNotification[];
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@gajae-code/coding-agent",
|
|
4
|
-
"version": "0.9.
|
|
4
|
+
"version": "0.9.5",
|
|
5
5
|
"description": "Gajae Code CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://gajae-code.com",
|
|
7
7
|
"author": "Yeachan-Heo and Gajae Code Contributors",
|
|
@@ -49,12 +49,12 @@
|
|
|
49
49
|
"@agentclientprotocol/sdk": "0.21.0",
|
|
50
50
|
"@babel/parser": "^7.29.3",
|
|
51
51
|
"@mozilla/readability": "^0.6.0",
|
|
52
|
-
"@gajae-code/stats": "0.9.
|
|
53
|
-
"@gajae-code/agent-core": "0.9.
|
|
54
|
-
"@gajae-code/ai": "0.9.
|
|
55
|
-
"@gajae-code/natives": "0.9.
|
|
56
|
-
"@gajae-code/tui": "0.9.
|
|
57
|
-
"@gajae-code/utils": "0.9.
|
|
52
|
+
"@gajae-code/stats": "0.9.5",
|
|
53
|
+
"@gajae-code/agent-core": "0.9.5",
|
|
54
|
+
"@gajae-code/ai": "0.9.5",
|
|
55
|
+
"@gajae-code/natives": "0.9.5",
|
|
56
|
+
"@gajae-code/tui": "0.9.5",
|
|
57
|
+
"@gajae-code/utils": "0.9.5",
|
|
58
58
|
"@puppeteer/browsers": "^2.13.0",
|
|
59
59
|
"@types/turndown": "5.0.6",
|
|
60
60
|
"@xterm/headless": "^6.0.0",
|
|
@@ -152,8 +152,8 @@ type ManagedSessionRecord = {
|
|
|
152
152
|
liveMessageProgress: { textEmitted: boolean; thoughtEmitted: boolean } | undefined;
|
|
153
153
|
toolArgsById: Map<string, unknown>;
|
|
154
154
|
extensionsConfigured: boolean;
|
|
155
|
-
// Installed
|
|
156
|
-
// in `#disposeSessionRecord`. Lives independent of any prompt turn.
|
|
155
|
+
// Installed after the bootstrap race guard or eagerly when the client starts a prompt;
|
|
156
|
+
// released in `#disposeSessionRecord`. Lives independent of any prompt turn.
|
|
157
157
|
lifetimeUnsubscribe: (() => void) | undefined;
|
|
158
158
|
};
|
|
159
159
|
|
|
@@ -619,6 +619,7 @@ export class AcpAgent implements Agent {
|
|
|
619
619
|
promise: pendingPrompt.promise,
|
|
620
620
|
};
|
|
621
621
|
|
|
622
|
+
this.#ensureLifetimeSubscription(record);
|
|
622
623
|
record.promptTurn.unsubscribe = record.session.subscribe(event => {
|
|
623
624
|
void this.#handlePromptEvent(record, event);
|
|
624
625
|
});
|
|
@@ -831,6 +832,7 @@ export class AcpAgent implements Agent {
|
|
|
831
832
|
}
|
|
832
833
|
promptTurn.cancelRequested = true;
|
|
833
834
|
promptTurn.unsubscribe?.();
|
|
835
|
+
void this.#emitCancelledPromptIdleUpdate(record);
|
|
834
836
|
const cleanup = this.#runCancelCleanup(record, promptTurn);
|
|
835
837
|
promptTurn.cleanup = cleanup;
|
|
836
838
|
this.#finishPrompt(record, {
|
|
@@ -1043,8 +1045,8 @@ export class AcpAgent implements Agent {
|
|
|
1043
1045
|
async #registerPreparedSession(session: AgentSession, mcpServers: McpServer[]): Promise<ManagedSessionRecord> {
|
|
1044
1046
|
const record = this.#createManagedSessionRecord(session);
|
|
1045
1047
|
session.setClientBridge(createAcpClientBridge(this.#connection, session.sessionId, this.#clientCapabilities));
|
|
1046
|
-
//
|
|
1047
|
-
//
|
|
1048
|
+
// The lifetime subscription normally follows the bootstrap race guard, but
|
|
1049
|
+
// prompt() installs it eagerly once the client has demonstrated session ownership.
|
|
1048
1050
|
try {
|
|
1049
1051
|
await this.#configureExtensions(record);
|
|
1050
1052
|
await this.#configureMcpServers(record, mcpServers);
|
|
@@ -1070,7 +1072,38 @@ export class AcpAgent implements Agent {
|
|
|
1070
1072
|
};
|
|
1071
1073
|
}
|
|
1072
1074
|
|
|
1075
|
+
#ensureLifetimeSubscription(record: ManagedSessionRecord): void {
|
|
1076
|
+
if (record.lifetimeUnsubscribe) {
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
1079
|
+
record.lifetimeUnsubscribe = record.session.subscribe(event => {
|
|
1080
|
+
void this.#handleLifetimeEvent(record, event);
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1073
1084
|
async #handleLifetimeEvent(record: ManagedSessionRecord, event: AgentSessionEvent): Promise<void> {
|
|
1085
|
+
if (event.type === "auto_compaction_start" || event.type === "auto_compaction_end") {
|
|
1086
|
+
// Prompt-bound compaction is normally forwarded by #handlePromptEvent. The lifetime
|
|
1087
|
+
// subscription covers idle maintenance and the end event after prompt cancellation.
|
|
1088
|
+
const promptTurn = record.promptTurn;
|
|
1089
|
+
if (
|
|
1090
|
+
isPromptTurnInFlight(promptTurn) &&
|
|
1091
|
+
(!promptTurn.cancelRequested || event.type === "auto_compaction_start")
|
|
1092
|
+
) {
|
|
1093
|
+
return;
|
|
1094
|
+
}
|
|
1095
|
+
for (const notification of mapAgentWireEventPayloadToAcpSessionUpdates(
|
|
1096
|
+
toAgentWireEventPayload(event),
|
|
1097
|
+
record.session.sessionId,
|
|
1098
|
+
{
|
|
1099
|
+
cwd: record.session.sessionManager.getCwd(),
|
|
1100
|
+
compactionEndPhase: "idle",
|
|
1101
|
+
},
|
|
1102
|
+
)) {
|
|
1103
|
+
await this.#connection.sessionUpdate(notification);
|
|
1104
|
+
}
|
|
1105
|
+
return;
|
|
1106
|
+
}
|
|
1074
1107
|
if (event.type !== "thinking_level_changed") {
|
|
1075
1108
|
return;
|
|
1076
1109
|
}
|
|
@@ -1140,6 +1173,7 @@ export class AcpAgent implements Agent {
|
|
|
1140
1173
|
getMessageProgress: message => this.#getLiveMessageProgress(record, message),
|
|
1141
1174
|
getToolArgs: toolCallId => record.toolArgsById.get(toolCallId),
|
|
1142
1175
|
cwd: record.session.sessionManager.getCwd(),
|
|
1176
|
+
compactionEndPhase: "responding",
|
|
1143
1177
|
},
|
|
1144
1178
|
)) {
|
|
1145
1179
|
await this.#connection.sessionUpdate(notification);
|
|
@@ -1551,13 +1585,10 @@ export class AcpAgent implements Agent {
|
|
|
1551
1585
|
// enough that the response future has scheduled before our timer fires
|
|
1552
1586
|
// on stdio-only transports.
|
|
1553
1587
|
//
|
|
1554
|
-
// The session-lifetime subscription
|
|
1555
|
-
//
|
|
1556
|
-
//
|
|
1557
|
-
//
|
|
1558
|
-
// hasn't been told about yet. The pre-bootstrap thinking level is
|
|
1559
|
-
// reported in the response's `configOptions`, so deferring the
|
|
1560
|
-
// notification loses no state.
|
|
1588
|
+
// The session-lifetime subscription normally shares this guard so extension
|
|
1589
|
+
// work cannot notify an unknown session id. prompt() may install it earlier:
|
|
1590
|
+
// receipt of a prompt proves the client already owns the returned session id,
|
|
1591
|
+
// and closes the cancellation window before this timer fires.
|
|
1561
1592
|
setTimeout(() => {
|
|
1562
1593
|
if (this.#connection.signal.aborted) {
|
|
1563
1594
|
return;
|
|
@@ -1566,11 +1597,7 @@ export class AcpAgent implements Agent {
|
|
|
1566
1597
|
if (!record) {
|
|
1567
1598
|
return;
|
|
1568
1599
|
}
|
|
1569
|
-
|
|
1570
|
-
record.lifetimeUnsubscribe = record.session.subscribe(event => {
|
|
1571
|
-
void this.#handleLifetimeEvent(record, event);
|
|
1572
|
-
});
|
|
1573
|
-
}
|
|
1600
|
+
this.#ensureLifetimeSubscription(record);
|
|
1574
1601
|
void this.#emitBootstrapUpdates(sessionId, record);
|
|
1575
1602
|
}, ACP_BOOTSTRAP_RACE_GUARD_MS);
|
|
1576
1603
|
}
|
|
@@ -1606,6 +1633,30 @@ export class AcpAgent implements Agent {
|
|
|
1606
1633
|
});
|
|
1607
1634
|
}
|
|
1608
1635
|
|
|
1636
|
+
/** Ensure cancellation clears a previously emitted busy/compacting phase even if abort never produces an end event. */
|
|
1637
|
+
async #emitCancelledPromptIdleUpdate(record: ManagedSessionRecord): Promise<void> {
|
|
1638
|
+
if (this.#connection.signal.aborted) {
|
|
1639
|
+
return;
|
|
1640
|
+
}
|
|
1641
|
+
try {
|
|
1642
|
+
await this.#connection.sessionUpdate({
|
|
1643
|
+
sessionId: record.session.sessionId,
|
|
1644
|
+
update: {
|
|
1645
|
+
sessionUpdate: "session_info_update",
|
|
1646
|
+
title: record.session.sessionName,
|
|
1647
|
+
updatedAt: new Date().toISOString(),
|
|
1648
|
+
_meta: {
|
|
1649
|
+
gjcPhase: "idle",
|
|
1650
|
+
running: false,
|
|
1651
|
+
gjcRunning: false,
|
|
1652
|
+
},
|
|
1653
|
+
},
|
|
1654
|
+
});
|
|
1655
|
+
} catch (error) {
|
|
1656
|
+
logger.warn("Failed to emit cancelled ACP prompt idle update", { error });
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1609
1660
|
/**
|
|
1610
1661
|
* Reload plugin/registry state for an ACP session. Mirrors the interactive
|
|
1611
1662
|
* `/reload-plugins` and `/move` flows: invalidates the plugin-roots cache,
|
|
@@ -1647,6 +1698,11 @@ export class AcpAgent implements Agent {
|
|
|
1647
1698
|
sessionUpdate: "session_info_update",
|
|
1648
1699
|
title: record.session.sessionName,
|
|
1649
1700
|
updatedAt: new Date().toISOString(),
|
|
1701
|
+
_meta: {
|
|
1702
|
+
gjcPhase: "idle",
|
|
1703
|
+
running: false,
|
|
1704
|
+
gjcRunning: false,
|
|
1705
|
+
},
|
|
1650
1706
|
},
|
|
1651
1707
|
});
|
|
1652
1708
|
}
|
|
@@ -22,18 +22,38 @@ import type {
|
|
|
22
22
|
ClientBridgeTerminalHandle,
|
|
23
23
|
} from "../../session/client-bridge";
|
|
24
24
|
|
|
25
|
+
type AcpPermissionMode = "auto" | "prompt" | "always-allow";
|
|
26
|
+
|
|
27
|
+
const ACP_PERMISSION_MODE_ENV = "GJC_ACP_PERMISSION_MODE";
|
|
28
|
+
|
|
29
|
+
function parseAcpPermissionMode(value: unknown): AcpPermissionMode {
|
|
30
|
+
if (value === "auto" || value === "prompt" || value === "always-allow") return value;
|
|
31
|
+
return "prompt";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Client metadata is authoritative; the process environment is only a fallback when that field is absent. */
|
|
35
|
+
function resolveAcpPermissionMode(clientCapabilities: ClientCapabilities | undefined): AcpPermissionMode {
|
|
36
|
+
const meta = clientCapabilities?._meta;
|
|
37
|
+
if (typeof meta === "object" && meta !== null) {
|
|
38
|
+
const gjc = (meta as { gjc?: unknown }).gjc;
|
|
39
|
+
if (typeof gjc === "object" && gjc !== null && "permissionHandling" in gjc) {
|
|
40
|
+
return parseAcpPermissionMode((gjc as { permissionHandling?: unknown }).permissionHandling);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return parseAcpPermissionMode(process.env[ACP_PERMISSION_MODE_ENV]);
|
|
44
|
+
}
|
|
45
|
+
|
|
25
46
|
export function createAcpClientBridge(
|
|
26
47
|
connection: AgentSideConnection,
|
|
27
48
|
sessionId: string,
|
|
28
49
|
clientCapabilities: ClientCapabilities | undefined,
|
|
29
50
|
): ClientBridge {
|
|
51
|
+
const promptPermission = resolveAcpPermissionMode(clientCapabilities) === "prompt";
|
|
30
52
|
const capabilities: ClientBridgeCapabilities = {
|
|
31
53
|
readTextFile: clientCapabilities?.fs?.readTextFile === true,
|
|
32
54
|
writeTextFile: clientCapabilities?.fs?.writeTextFile === true,
|
|
33
55
|
terminal: clientCapabilities?.terminal === true,
|
|
34
|
-
|
|
35
|
-
// the agent's policy choice rather than a client capability.
|
|
36
|
-
requestPermission: true,
|
|
56
|
+
requestPermission: promptPermission,
|
|
37
57
|
};
|
|
38
58
|
|
|
39
59
|
const bridge: ClientBridge = { capabilities, deferAgentInitiatedTurns: true };
|
|
@@ -65,8 +85,10 @@ export function createAcpClientBridge(
|
|
|
65
85
|
createTerminalHandle(connection, sessionId, params);
|
|
66
86
|
}
|
|
67
87
|
|
|
68
|
-
|
|
69
|
-
requestPermission
|
|
88
|
+
if (promptPermission) {
|
|
89
|
+
bridge.requestPermission = (toolCall, options, signal) =>
|
|
90
|
+
requestPermission(connection, sessionId, toolCall, options, signal);
|
|
91
|
+
}
|
|
70
92
|
|
|
71
93
|
return bridge;
|
|
72
94
|
}
|
|
@@ -27,6 +27,8 @@ interface AcpEventMapperOptions {
|
|
|
27
27
|
* before emitting `ToolCallLocation` entries.
|
|
28
28
|
*/
|
|
29
29
|
cwd?: string;
|
|
30
|
+
/** Phase to expose after compaction ends. Prompt-bound compaction resumes responding; idle maintenance returns idle. */
|
|
31
|
+
compactionEndPhase?: "responding" | "idle";
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
interface ContentArrayContainer {
|
|
@@ -236,8 +238,44 @@ export function mapAgentSessionEventToAcpSessionUpdates(
|
|
|
236
238
|
case "turn_start":
|
|
237
239
|
case "turn_end":
|
|
238
240
|
case "message_start":
|
|
241
|
+
return [];
|
|
239
242
|
case "auto_compaction_start":
|
|
240
|
-
|
|
243
|
+
return [
|
|
244
|
+
toSessionNotification(sessionId, {
|
|
245
|
+
sessionUpdate: "session_info_update",
|
|
246
|
+
_meta: {
|
|
247
|
+
gjcPhase: "compacting",
|
|
248
|
+
gjcCompactionState: "start",
|
|
249
|
+
gjcCompactionTrigger: event.reason,
|
|
250
|
+
gjcCompactionAction: event.action,
|
|
251
|
+
running: true,
|
|
252
|
+
gjcRunning: true,
|
|
253
|
+
},
|
|
254
|
+
}),
|
|
255
|
+
];
|
|
256
|
+
case "auto_compaction_end": {
|
|
257
|
+
const phase = options.compactionEndPhase ?? "responding";
|
|
258
|
+
const running = phase !== "idle";
|
|
259
|
+
const meta: Record<string, unknown> = {
|
|
260
|
+
gjcPhase: phase,
|
|
261
|
+
gjcCompactionState: "end",
|
|
262
|
+
gjcCompactionAction: event.action,
|
|
263
|
+
gjcCompactionAborted: event.aborted,
|
|
264
|
+
gjcCompactionWillRetry: event.willRetry,
|
|
265
|
+
running,
|
|
266
|
+
gjcRunning: running,
|
|
267
|
+
};
|
|
268
|
+
if (event.skipped !== undefined) {
|
|
269
|
+
meta.gjcCompactionSkipped = event.skipped;
|
|
270
|
+
}
|
|
271
|
+
if (event.errorMessage !== undefined) {
|
|
272
|
+
meta.gjcCompactionErrorMessage = event.errorMessage;
|
|
273
|
+
}
|
|
274
|
+
if (event.continuationSkipReason !== undefined) {
|
|
275
|
+
meta.gjcCompactionContinuationSkipReason = event.continuationSkipReason;
|
|
276
|
+
}
|
|
277
|
+
return [toSessionNotification(sessionId, { sessionUpdate: "session_info_update", _meta: meta })];
|
|
278
|
+
}
|
|
241
279
|
case "auto_retry_start":
|
|
242
280
|
case "auto_retry_end":
|
|
243
281
|
case "retry_fallback_applied":
|
|
@@ -121,6 +121,7 @@ export type ModelSelectorSelection =
|
|
|
121
121
|
interface PendingThinkingChoice {
|
|
122
122
|
item: ModelItem | CanonicalModelItem;
|
|
123
123
|
role: GjcModelAssignmentTargetId | null;
|
|
124
|
+
roles?: readonly GjcModelAssignmentTargetId[];
|
|
124
125
|
levels: ThinkingLevel[];
|
|
125
126
|
}
|
|
126
127
|
|
|
@@ -1373,7 +1374,13 @@ export class ModelSelectorComponent extends Container {
|
|
|
1373
1374
|
}
|
|
1374
1375
|
|
|
1375
1376
|
#renderThinkingMenu(choice: PendingThinkingChoice): void {
|
|
1376
|
-
const targetLabel = choice.
|
|
1377
|
+
const targetLabel = choice.roles
|
|
1378
|
+
? choice.roles.includes("default")
|
|
1379
|
+
? "all targets"
|
|
1380
|
+
: "all role agents"
|
|
1381
|
+
: choice.role === null
|
|
1382
|
+
? "temporary model"
|
|
1383
|
+
: GJC_MODEL_ASSIGNMENT_TARGETS[choice.role].name;
|
|
1377
1384
|
this.#listContainer.addChild(new Spacer(1));
|
|
1378
1385
|
this.#listContainer.addChild(
|
|
1379
1386
|
new Text(theme.fg("muted", ` Reasoning for ${targetLabel}: ${choice.item.model.id}`), 0, 0),
|
|
@@ -1700,14 +1707,16 @@ export class ModelSelectorComponent extends Container {
|
|
|
1700
1707
|
const level = choice.levels[this.#selectedThinkingIndex];
|
|
1701
1708
|
if (!level) return;
|
|
1702
1709
|
this.#pendingThinkingChoice = undefined;
|
|
1703
|
-
this.#handleSelect(choice.item, choice.role, level);
|
|
1710
|
+
this.#handleSelect(choice.item, choice.role, level, choice.roles);
|
|
1704
1711
|
return;
|
|
1705
1712
|
}
|
|
1706
1713
|
if (getKeybindings().matches(keyData, "tui.select.cancel")) {
|
|
1707
1714
|
this.#pendingThinkingChoice = undefined;
|
|
1708
1715
|
if (choice.role !== null) {
|
|
1709
1716
|
this.#pendingActionItem = choice.item;
|
|
1710
|
-
this.#selectedActionIndex =
|
|
1717
|
+
this.#selectedActionIndex = choice.roles
|
|
1718
|
+
? GJC_MODEL_ASSIGNMENT_TARGET_IDS.length + (choice.roles.includes("default") ? 1 : 0)
|
|
1719
|
+
: Math.max(0, GJC_MODEL_ASSIGNMENT_TARGET_IDS.indexOf(choice.role));
|
|
1711
1720
|
}
|
|
1712
1721
|
this.#updateList();
|
|
1713
1722
|
}
|
|
@@ -1736,9 +1745,12 @@ export class ModelSelectorComponent extends Container {
|
|
|
1736
1745
|
): void {
|
|
1737
1746
|
const itemThinkingLevel = thinkingLevel ?? item.thinkingLevel;
|
|
1738
1747
|
const hasExplicitThinkingChoice = thinkingLevel !== undefined || item.explicitThinkingLevel === true;
|
|
1739
|
-
|
|
1748
|
+
const needsExplicitThinkingChoice = roles
|
|
1749
|
+
? roles.some(targetRole => requiresExplicitThinkingChoice(item.model, targetRole))
|
|
1750
|
+
: requiresExplicitThinkingChoice(item.model, role);
|
|
1751
|
+
if (!hasExplicitThinkingChoice && needsExplicitThinkingChoice) {
|
|
1740
1752
|
const levels = getSelectableThinkingLevels(item.model);
|
|
1741
|
-
this.#pendingThinkingChoice = { item, role, levels };
|
|
1753
|
+
this.#pendingThinkingChoice = { item, role, roles, levels };
|
|
1742
1754
|
this.#selectedThinkingIndex = this.#getInitialThinkingChoiceIndex(item, levels);
|
|
1743
1755
|
this.#updateList();
|
|
1744
1756
|
return;
|