thincoder 0.12.65 → 0.12.67
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 +37 -0
- package/README.md +9 -0
- package/bin/thincoder.mjs +15 -0
- package/package.json +2 -2
- package/src/acp/bridge.mjs +8 -10
- package/src/cli/permission.mjs +1 -1
- package/src/prompt-injections.mjs +1 -1
- package/src/tui/agent-turn.mjs +29 -22
- package/src/tui/cmd-advisor.mjs +19 -4
- package/src/tui/cmd-config.mjs +9 -1
- package/src/tui/index.mjs +3 -4
- package/src/tui/interaction.mjs +1 -1
- package/src/tui/key-handler-busy.mjs +17 -12
- package/src/tui/key-handler-ctrlc.mjs +4 -4
- package/src/tui/key-handler-edit.mjs +12 -8
- package/src/tui/key-handler.mjs +1 -1
- package/src/tui/ledger-surface.mjs +26 -5
- package/src/tui/mouse.mjs +2 -2
- package/src/tui/queued-merge.mjs +68 -0
- package/src/tui/queued-pickup.mjs +34 -0
- package/src/tui/render-conversation.mjs +37 -1
- package/src/tui/render-frame.mjs +11 -5
- package/src/tui/render-segments.mjs +2 -2
- package/src/tui/subagent-blocks.mjs +13 -13
- package/src/tui/subagent-freeze.mjs +4 -4
- package/src/tui/subagent-panel.mjs +4 -4
- package/src/tui/suspension-drive.mjs +42 -35
- package/src/tui/tool-display.mjs +1 -1
- package/src/tui/tool-events.mjs +7 -7
- package/src/tui/tui-state.mjs +1 -1
- package/src/tui/turn-face.mjs +2 -2
package/src/tui/tool-events.mjs
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* 满足 500 行硬限)。只做「事件 → TUI 状态/对话行」的映射:
|
|
4
4
|
*
|
|
5
5
|
* - onToken/onReasoning : 子agent 前缀分流(routeSub*)→ 主流 streaming/reasoning
|
|
6
|
-
* - onToolCall : 状态栏 + `❯ name args` 标题行 + 计时 + §
|
|
6
|
+
* - onToolCall : 状态栏 + `❯ name args` 标题行 + 计时 + AGENT-LOOP-SUBAGENT.md §6.7 action 记录
|
|
7
7
|
* - onToolResult : 子agent 完成冻结(finishSubTaskKey 精确冻 + freezeDoneSubTasks——
|
|
8
8
|
* F-2 后 finishSubTask 为 no-op 兼容保留)、
|
|
9
9
|
* 工具块结果入块、advisor 评审冻结框
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
* - 其余 : usage 累计、等待提示、task 面板、回合末增量落盘
|
|
12
12
|
*
|
|
13
13
|
* flushStream 同时返回给调用方(回合循环 / onTurnEnd 共用)。纯回调装配,无终端副作用
|
|
14
|
-
* (除经 deps 注入的 pushLine/render
|
|
15
|
-
*
|
|
14
|
+
* (除经 deps 注入的 pushLine/render)。AGENT-LOOP-SUBAGENT.md §6.7: subagent_check/escalate 工具退役后
|
|
15
|
+
* (AGENT-LOOP-SUBAGENT.md §6.7.5——check 动作已删),subagent 家族全部调用以工具名 "subagent" +
|
|
16
16
|
* action 到达——完成路由按 onToolCall 时记录的 action 分流(spawn 区块 / escalate
|
|
17
17
|
* 区块 / status/observe/send 普通工具块——observe/send 不建子代理区块)。
|
|
18
18
|
*/
|
|
@@ -115,7 +115,7 @@ export function buildToolCallbacks(deps) {
|
|
|
115
115
|
// Subagent tool call: prefix role#id/toolName → open a fresh tool block and
|
|
116
116
|
// set currentTool for the header summary line.
|
|
117
117
|
if (routeSubToolCall(state, name, args, scheduleRender)) return
|
|
118
|
-
// §
|
|
118
|
+
// AGENT-LOOP-SUBAGENT.md §6.7: record the action of a merged subagent-family call (spawn is the
|
|
119
119
|
// default — only non-spawn actions need a record for result-time routing).
|
|
120
120
|
if (name === "subagent" && args?.action && args.action !== "spawn") {
|
|
121
121
|
if (toolId !== undefined && toolId !== null) _subActions.set(toolId, args.action)
|
|
@@ -179,7 +179,7 @@ export function buildToolCallbacks(deps) {
|
|
|
179
179
|
// 签名(普通工具/老回调/错误路径不带 key)。
|
|
180
180
|
onToolResult: (name, result, toolId, subKey) => {
|
|
181
181
|
state.currentTool = null
|
|
182
|
-
// §
|
|
182
|
+
// AGENT-LOOP-SUBAGENT.md §6.7 merged family: route per the action recorded at onToolCall (no record = default spawn).
|
|
183
183
|
let subAction = null
|
|
184
184
|
if (name === "subagent") {
|
|
185
185
|
subAction = (toolId !== undefined && toolId !== null)
|
|
@@ -192,7 +192,7 @@ export function buildToolCallbacks(deps) {
|
|
|
192
192
|
// Subagent complete: mark the earliest running child as done — the block
|
|
193
193
|
// persists (✓ frozen elapsed header, expandable) as the ONLY carrier of the
|
|
194
194
|
// child's activity; memory bounded by the N2 line cap.
|
|
195
|
-
// §
|
|
195
|
+
// AGENT-LOOP-SUBAGENT.md §6.7.2: cancel 动作排除在 isSubagent 外——ack/错误 JSON 走普通工具块;区块冻结由
|
|
196
196
|
// ⟦ev⟧stopped settle 事件承担(此处 finishSubTask 会误冻最早 running 区块)。
|
|
197
197
|
if (isSubagent) {
|
|
198
198
|
// The dispatch-level tool-block carrier for this call would otherwise
|
|
@@ -362,7 +362,7 @@ export function buildToolCallbacks(deps) {
|
|
|
362
362
|
scheduleRender()
|
|
363
363
|
},
|
|
364
364
|
// Manual-tier auto-turn digests (agent-turn.mjs suspension driver) pass null
|
|
365
|
-
// handlers — permission requests then deny WITHOUT a panel (§
|
|
365
|
+
// handlers — permission requests then deny WITHOUT a panel (AGENT-LOOP-ASYNC-POOL.md §6.8 D-S7: no modal
|
|
366
366
|
// during unattended digestion) and question errors out instead of hanging.
|
|
367
367
|
...(askPermission ? { onPermissionRequest: (name, args) => askPermission(name, args) } : {}),
|
|
368
368
|
// Merged batch ask (§16 D-B1): one confirmation for N non-readonly tools in
|
package/src/tui/tui-state.mjs
CHANGED
|
@@ -37,7 +37,7 @@ export function createTuiState({ cols, rows, agent }) {
|
|
|
37
37
|
reasoning: "", // thinking stream buffer (dimmed display)
|
|
38
38
|
completion: null, // Tab completion state { candidates, index }
|
|
39
39
|
|
|
40
|
-
subTasks: {}, // sub-agent activity blocks (§7.2 D4): { "coder#1": { key, role, model, started, done, doneAt, blocks: [{kind,text}], currentTool, toolArgs, turn, maxTurns, approval, lastError, dropped, blockEpoch, awaitingDigest
|
|
40
|
+
subTasks: {}, // sub-agent activity blocks (§7.2 D4): { "coder#1": { key, role, model, started, done, doneAt, blocks: [{kind,text}], currentTool, toolArgs, turn, maxTurns, approval, lastError, dropped, blockEpoch, awaitingDigest(AGENT-LOOP-ASYNC-POOL.md §6.8 挂起中间态), _freezeAt(冻结锚点), stopped, children: [](SUBAGENT-TAIL:嵌套子代理**守护载体**——内容行并入本块 blocks——subagent-children.mjs) } } — rendered as collapsible in-conversation blocks; persists across turns (blocks are the child activity's ONLY carrier — child tool calls never enter the parent history); bounded by the N2 500-line per-child ring buffer(SUBAGENT-TAIL 单环:内层行同环计数、单载体最旧先行——TUI.md §6)
|
|
41
41
|
currentTool: null, // currently executing tool name (shown in status bar)
|
|
42
42
|
processingStarted: 0, // current turn start time (status bar timer)
|
|
43
43
|
status: "Ready",
|
package/src/tui/turn-face.mjs
CHANGED
|
@@ -15,8 +15,8 @@ export function createTurnFace(ctx) {
|
|
|
15
15
|
async function submit() {
|
|
16
16
|
const text = state.input.join("").trim()
|
|
17
17
|
if (!text) return
|
|
18
|
-
// INPUT-LOCK 防御(C'——2026-09-09 + F16 busy
|
|
19
|
-
// (busy Enter 非模态 =
|
|
18
|
+
// INPUT-LOCK 防御(C'——2026-09-09 + F16 busy 队列——2026-09-21 · queue-visible 2026-09-24):门禁在 key-handler
|
|
19
|
+
// (busy Enter 非模态 = 队列受理(容量 8)/ 模态·斜杠·空·满队 = 吞 + 提示,文本保留——TUI-INPUT-BOX.md
|
|
20
20
|
// §4.1);submit 只在非 busy 期达此;防御直呼/上游改动:busy 期拒绝(不清输入框不吞内容)。
|
|
21
21
|
if (state.processing) {
|
|
22
22
|
pushLine(`[主会话处理中 —— 消息未发送(回合结束后请重按 Enter)]`, C.warn)
|