thincoder 0.12.64 → 0.12.65

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.
@@ -0,0 +1,64 @@
1
+ import { createInteraction } from "./interaction.mjs"
2
+ import { runAgentTurn } from "./agent-turn.mjs"
3
+ import { pasteClipboardImage as pasteClipboardImageImpl } from "./clipboard.mjs"
4
+
5
+ /** 回合面(2026-09-22 structure-debt §2.2 · #159):submit 门禁 / interaction 装配(权限 + 提问)/
6
+ * 剪贴板图片粘贴 / turnCtx / turn——块体自 index.mjs startTUI 逐字搬移;唯一改指 = turnCtx 的
7
+ * `assistantLabeled` 存取器两行改经 ctx.conversation(写入面单源)承接。
8
+ * `handleSlash` 由调用侧以惰性转发承接(命令层后定义——循环依赖语义逐字保持),turnCtx 由
9
+ * index.mjs 在命令层之后原址回填 `turnCtx.handleSlash`。
10
+ * @param {object} ctx
11
+ * @returns {{ submit: Function, turn: Function, turnCtx: object, askPermission: Function,
12
+ * askQuestion: Function, askBatchPermission: Function, pasteClipboardImage: Function }} */
13
+ export function createTurnFace(ctx) {
14
+ const { agent, state, pushLine, pushLabel, render, ensureAssistantLabel, summarize, handleSlash, conversation } = ctx
15
+ async function submit() {
16
+ const text = state.input.join("").trim()
17
+ if (!text) return
18
+ // INPUT-LOCK 防御(C'——2026-09-09 + F16 busy 单槽——2026-09-21):门禁在 key-handler
19
+ // (busy Enter 非模态 = 单槽注入 / 模态·斜杠·空·槽满 = 吞 + 提示,文本保留——TUI-INPUT-BOX.md
20
+ // §4.1);submit 只在非 busy 期达此;防御直呼/上游改动:busy 期拒绝(不清输入框不吞内容)。
21
+ if (state.processing) {
22
+ pushLine(`[主会话处理中 —— 消息未发送(回合结束后请重按 Enter)]`, C.warn)
23
+ render()
24
+ return
25
+ }
26
+ state.input = []
27
+ state.cursor = 0
28
+ const wasInHistory = state.historyIndex !== -1
29
+ state.history.push(text) // review #3 fix: single push (was duplicated — every submit appeared twice in ↑/↓ history)
30
+ state.historyIndex = -1
31
+ if (!wasInHistory) state._draft = null // submitted — the draft is now history. Keep draft when submitting from history mode (↓ can recover)
32
+ state.scroll = 0
33
+ state._followTail = true // 2026-08-31 会诊 deepseek:新消息恢复跟随(注释曾承诺、实现缺漏)
34
+
35
+ // Slash commands: handled locally, don't enter agent loop. 斜杠 busy 期提交在 key-handler
36
+ // 门禁被吞(白名单已删——斜杠同吞——INPUT-LOCK-BEHAVIOR-REVISED)——submit 仅非 busy 期可达。
37
+ if (text.startsWith("/")) {
38
+ await handleSlash(text)
39
+ render()
40
+ return
41
+ }
42
+
43
+ await turn(text)
44
+ }
45
+
46
+ // Interaction primitives: permission approval + Q&A input, implemented in interaction.mjs
47
+ const { askPermission, askQuestion, askBatchPermission } = createInteraction({
48
+ agent, state, pushLine, pushLabel, render, summarize,
49
+ })
50
+
51
+ // Clipboard image paste: implemented in clipboard.mjs
52
+ const pasteClipboardImage = () => pasteClipboardImageImpl({ agent, state, pushLine, render })
53
+
54
+ // Agent loop: implemented in agent-turn.mjs
55
+ const turnCtx = {
56
+ agent, state, pushLine, pushLabel, render, scheduleRender: render, ensureAssistantLabel,
57
+ askPermission, askQuestion, askBatchPermission, handleSlash: null,
58
+ get assistantLabeled() { return conversation.assistantLabeled },
59
+ set assistantLabeled(v) { conversation.assistantLabeled = v },
60
+ }
61
+ const turn = (text) => runAgentTurn(turnCtx, text)
62
+
63
+ return { submit, turn, turnCtx, askPermission, askQuestion, askBatchPermission, pasteClipboardImage }
64
+ }