@zq-silk/yui 2.16.0 → 2.17.0

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.
Files changed (69) hide show
  1. package/dist/cli/commandCatalog.js +17 -11
  2. package/dist/cli/interactionCandidates.js +20 -5
  3. package/dist/cli/interactionPolicy.js +5 -4
  4. package/dist/cli/roleWizard.js +7 -0
  5. package/dist/commands/globalRoleCommands.js +13 -2
  6. package/dist/commands/operatorCommands.js +2 -0
  7. package/dist/commands/profileCommands.js +19 -2
  8. package/dist/commands/roleConfiguration.js +3 -0
  9. package/dist/commands/taskCommands.js +16 -0
  10. package/dist/commands/taskRoleRuntimeStatus.js +3 -0
  11. package/dist/controller/agentJobControl.js +9 -1
  12. package/dist/controller/fileSchedulerStoreAdapter.js +35 -4
  13. package/dist/controller/globalInputDelivery.js +14 -8
  14. package/dist/controller/providerRetryAdmission.js +9 -0
  15. package/dist/controller/providerRetryDelivery.js +16 -0
  16. package/dist/controller/runtime.js +14 -0
  17. package/dist/controller/runtimeLaunchCoordinator.js +3 -1
  18. package/dist/executor/fileRoleLaunchPlanner.js +3 -0
  19. package/dist/message/messageContinuation.js +4 -0
  20. package/dist/output/rolePresentation.js +3 -0
  21. package/dist/profile/agentProfile.js +8 -0
  22. package/dist/profile/agentProfileRuntime.js +16 -1
  23. package/dist/review/reviewDecision.js +6 -0
  24. package/dist/role/availability.js +28 -0
  25. package/dist/role/role.js +6 -0
  26. package/dist/runtime/codexNativeAccess.js +21 -4
  27. package/dist/runtime/tmuxAdapters.js +5 -0
  28. package/dist/scheduler/activeRoleRunDelivery.js +9 -0
  29. package/dist/scheduler/leaderWakeupProcessor.js +8 -1
  30. package/dist/scheduler/roleRunLiveness.js +3 -0
  31. package/dist/storage/sqliteSchema.js +10 -0
  32. package/dist/storage/storageVersions.js +1 -1
  33. package/dist/web/assets/client/app/main.js +15 -22
  34. package/dist/web/assets/client/app/taskView.js +7 -11
  35. package/dist/web/assets/client/i18n/en.js +62 -18
  36. package/dist/web/assets/client/i18n/zh-CN.js +62 -18
  37. package/dist/web/assets/client/index.js +2 -0
  38. package/dist/web/assets/client/layout/shortcuts.js +2 -2
  39. package/dist/web/assets/client/layout/workspace.js +99 -112
  40. package/dist/web/assets/client/ui/primitives.js +15 -2
  41. package/dist/web/assets/client/views/dock/conversation.js +421 -123
  42. package/dist/web/assets/client/views/dock/session.js +229 -0
  43. package/dist/web/assets/client/views/dock/terminal.js +48 -39
  44. package/dist/web/assets/client/views/overview.js +2 -2
  45. package/dist/web/assets/client/views/task/page.js +2 -12
  46. package/dist/web/assets/shell/dock.js +9 -27
  47. package/dist/web/assets/styles/views/conversation.js +96 -17
  48. package/dist/web/assets/styles/views/dock.js +17 -5
  49. package/dist/web/assets/styles/views/task.js +1 -2
  50. package/dist/web/assets/styles/views/terminal.js +12 -8
  51. package/dist/web/webConversation.js +1 -0
  52. package/dist/web/webSettings.js +10 -2
  53. package/docs/managed-turn-and-session-runtime.md +10 -0
  54. package/docs/managed-turn-and-session-runtime.zh-CN.md +6 -0
  55. package/docs/release-workflow.md +24 -0
  56. package/docs/release-workflow.zh-CN.md +19 -0
  57. package/docs/roles-and-configuration.md +45 -1
  58. package/docs/roles-and-configuration.zh-CN.md +35 -0
  59. package/docs/storage-baseline.md +6 -1
  60. package/docs/storage-baseline.zh-CN.md +5 -1
  61. package/docs/testing/review-evaluation.md +35 -1
  62. package/docs/testing/review-evaluation.zh-CN.md +25 -1
  63. package/docs/testing/verification-levels.md +2 -2
  64. package/docs/testing/verification-levels.zh-CN.md +2 -2
  65. package/package.json +1 -1
  66. package/skills/yui-leader/VERSION +1 -1
  67. package/skills/yui-leader/references/execution.md +19 -8
  68. package/skills/yui-reviewer/SKILL.md +13 -2
  69. package/skills/yui-reviewer/VERSION +1 -1
@@ -7,7 +7,8 @@ export const APP_SCRIPT = String.raw `
7
7
  // Everything kept in the browser is view state; Task facts always come from
8
8
  // the loopback API.
9
9
  //
10
- // layout/workspace sidebar | center | dock columns, dock modes, sizing
10
+ // layout/workspace sidebar | center | dock columns, dock views, sizing
11
+ // views/dock/session the dock's session page: one Role and Session, chat or terminal
11
12
  // app/taskView draws the selected Task, the dock discussion, the overview
12
13
  // app/selection selected Task, its detail reads, URL-driven navigation
13
14
  // app/catalog refresh loop, sidebar, catalog paging and filters
@@ -24,14 +25,13 @@ import { createI18n } from "/assets/js/lib/i18n.js";
24
25
  import { createThemeController } from "/assets/js/lib/theme.js";
25
26
  import { api } from "/assets/js/lib/api.js";
26
27
  import { createToast } from "/assets/js/ui/toast.js";
27
- import { createTerminalController } from "/assets/js/views/dock/terminal.js";
28
- import { createConversationController } from "/assets/js/views/dock/conversation.js";
28
+ import { createSessionPage } from "/assets/js/views/dock/session.js";
29
29
  import { createPreviewController } from "/assets/js/views/dock/preview.js";
30
30
  import { bindGlobalInput } from "/assets/js/views/globalInput.js";
31
31
  import { bindCreateTask } from "/assets/js/views/createTask.js";
32
32
  import { bindBodySearch } from "/assets/js/views/bodySearch.js";
33
33
  import { readQuery } from "/assets/js/layout/router.js";
34
- import { rememberPlace, linkPlaces } from "/assets/js/lib/prefs.js";
34
+ import { rememberPlace, linkPlaces, readSessionAccessMode } from "/assets/js/lib/prefs.js";
35
35
  import { createWorkspace } from "/assets/js/layout/workspace.js";
36
36
  import { createSidebarNav } from "/assets/js/layout/sidebarNav.js";
37
37
  import { bindShortcuts } from "/assets/js/layout/shortcuts.js";
@@ -51,12 +51,10 @@ const el = {
51
51
  dockTargetOptions: $("#dock-target-options"), globalInputOpen: $("#global-input-open"), settings: $("#settings-dialog"),
52
52
  locale: $("#locale-select"), themeOptions: $("#theme-options"),
53
53
  dock: $("#dock"), divider: $("#dock-divider"), dockSwap: $("#dock-swap"), dockClose: $("#dock-close"),
54
- dockTabDiscussion: $("#dock-tab-discussion"), dockTabSession: $("#dock-tab-session"),
54
+ dockTabDiscussion: $("#dock-tab-discussion"),
55
55
  dockTabConversation: $("#dock-tab-conversation"), conversation: $("#dock-conversation"),
56
56
  dockTabPreview: $("#dock-tab-preview"), preview: $("#dock-preview"),
57
- discussion: $("#dock-discussion"), session: $("#dock-session"),
58
- terminalHost: $("#terminal-host"), terminalEmpty: $("#terminal-empty"), terminalState: $("#terminal-state"),
59
- sessionTargets: $("#session-targets"), settingsOpen: $("#settings-open"), terminalCli: $("#terminal-cli")
57
+ discussion: $("#dock-discussion"), settingsOpen: $("#settings-open")
60
58
  };
61
59
 
62
60
  // View state. Each group has exactly one writer.
@@ -77,28 +75,23 @@ const t = i18n.t;
77
75
  const locale = i18n.getLocale;
78
76
  const theme = createThemeController(el.themeOptions, t);
79
77
  const toast = createToast(el.toast);
80
- const conversation = createConversationController(el.conversation, t, locale);
81
78
  const preview = createPreviewController(el.preview, t);
82
- const terminal = createTerminalController({
83
- host: el.terminalHost, empty: el.terminalEmpty, state: el.terminalState, targets: el.sessionTargets, cli: el.terminalCli
84
- }, t, locale, toast);
85
- theme.subscribe(function () { terminal.retheme(); });
79
+ // The mode changed inside the session page: the dock header follows it.
80
+ const session = createSessionPage(el.conversation, t, locale, toast, function () { workspace.syncDockButtons(); });
81
+ theme.subscribe(function () { session.retheme(); });
86
82
 
87
83
  // Controllers are created in dependency order; the arrow callbacks below are
88
84
  // the only edges pointing at controllers created later.
89
85
  let taskView = null;
90
86
  let selection = null;
91
87
  let catalog = null;
92
- const workspace = createWorkspace({
93
- el: el, state: state, t: t, terminal: terminal, conversation: conversation, preview: preview,
94
- sessionOpened: function () { taskView.updateSessionTargets(); }
95
- });
88
+ const workspace = createWorkspace({ el: el, state: state, t: t, session: session, preview: preview });
96
89
  const sidebarNav = createSidebarNav({
97
90
  el: { sidebar: el.sidebar, rail: el.rail, scrim: el.sidebarScrim, collapse: el.sidebarCollapse },
98
91
  relayout: function () { workspace.updateLayout(); }
99
92
  });
100
93
  taskView = createTaskView({
101
- el: el, state: state, t: t, locale: locale, api: api, toast: toast, terminal: terminal, workspace: workspace,
94
+ el: el, state: state, t: t, locale: locale, api: api, toast: toast, workspace: workspace,
102
95
  selectTask: function (taskId) { return selection.selectTask(taskId); },
103
96
  clearSelection: function () { selection.clearSelection(); },
104
97
  revealSidebar: function () { sidebarNav.reveal(); },
@@ -121,7 +114,7 @@ bindCreateTask({ t: t, api: api, selectTask: selection.selectTask,
121
114
  afterWrite: function () { catalog.refresh({ quiet: true }); } });
122
115
  bindBodySearch({ t: t, api: api, selectTask: selection.selectTask,
123
116
  currentTask: function () { return state.selected; },
124
- captureDraftTarget: conversation.captureDraftTarget, insertReference: conversation.insertReference });
117
+ captureDraftTarget: session.captureDraftTarget, insertReference: session.insertReference });
125
118
  bindShortcuts({
126
119
  el: el, state: state, globalInput: globalInput, workspace: workspace, sidebarNav: sidebarNav,
127
120
  selection: selection, catalog: catalog, taskView: taskView
@@ -155,7 +148,7 @@ window.addEventListener("popstate", function () {
155
148
 
156
149
  i18n.subscribe(function () {
157
150
  theme.render();
158
- terminal.relabel();
151
+ session.relabel();
159
152
  catalog.renderSidebar();
160
153
  taskView.relabel();
161
154
  workspace.updateLayout();
@@ -164,8 +157,8 @@ i18n.subscribe(function () {
164
157
  workspace.updateLayout();
165
158
  taskView.showOverview();
166
159
  // The panel starts closed: name its owner without polling until it opens.
167
- conversation.open({ scope: "global", roleName: "operator" });
168
- conversation.close();
160
+ session.open({ scope: "global", roleName: "operator" }, { mode: readSessionAccessMode() === "native" ? "terminal" : "chat" });
161
+ session.close();
169
162
  applyStateFromUrl();
170
163
  catalog.refresh();
171
164
  window.setInterval(function () { catalog.refresh({ quiet: true }); }, 5000);
@@ -12,7 +12,6 @@ import { renderOverview } from "/assets/js/views/overview.js";
12
12
  import { renderTaskDetail, selectTab, TABS, TAB_ALIASES } from "/assets/js/views/task/page.js";
13
13
  import { updateObservation } from "/assets/js/views/task/observation.js";
14
14
  import { renderDiscussion, discussionHasUnsent } from "/assets/js/views/dock/discussion.js";
15
- import { sameTarget } from "/assets/js/views/dock/terminal.js";
16
15
  import { setSectionParam } from "/assets/js/layout/router.js";
17
16
  import { enter } from "/assets/js/lib/motion.js";
18
17
 
@@ -29,14 +28,13 @@ function runtimeSignature(detail) {
29
28
  }).join(",");
30
29
  }
31
30
 
32
- // deps: { el, state, t, locale, api, toast, terminal, workspace,
31
+ // deps: { el, state, t, locale, api, toast, workspace,
33
32
  // selectTask, clearSelection, revealSidebar, pickAttention, readPageSessions, refreshCatalog }
34
33
  // el #detail, #center and the dock discussion
35
34
  // state reads selected, detail, detailKey and the catalog fields the
36
35
  // overview shows; writes activeTab
37
36
  // api Task reads for lazy blocks and the Task page's writes
38
- // terminal the dock's native Session (views/dock/terminal)
39
- // workspace layout/workspace: dock toggles and opening Sessions
37
+ // workspace layout/workspace: dock toggles, the session page and its Role list
40
38
  // selectTask(taskId) an overview row was chosen (app/selection)
41
39
  // clearSelection() the Task page's "Tasks" crumb (app/selection)
42
40
  // revealSidebar() the page header's task-list switch (layout/sidebarNav)
@@ -155,7 +153,7 @@ function detailContext(view) {
155
153
  },
156
154
  onBack: deps.clearSelection,
157
155
  revealSidebar: deps.revealSidebar,
158
- showDock: deps.workspace.toggleDock,
156
+ togglePanel: function () { deps.workspace.toggleDock(); },
159
157
  toggleOperator: deps.workspace.toggleOperator,
160
158
  openConversation: function (materials) {
161
159
  deps.workspace.openConversation({ scope: "task", taskId: deps.state.selected, roleName: "leader" }, materials);
@@ -239,8 +237,8 @@ function drawDetail(deps, ctx) {
239
237
  el.center.scrollTop = scroll;
240
238
  }
241
239
 
242
- // The dock's Session chips: every role of the selected Task plus the global
243
- // operator, keeping the Session currently open even when it left the list.
240
+ // The Roles the dock's target menu offers: every Role of the selected Task,
241
+ // with whether it has a live native Session (Operator is always offered).
244
242
  function updateSessionTargets(deps) {
245
243
  const detail = deps.state.detail;
246
244
  const targets = [];
@@ -252,10 +250,7 @@ function updateSessionTargets(deps) {
252
250
  live: !!(runtimeRole && runtimeRole.runtimeSession && runtimeRole.runtimeSession.nativeSessionId) });
253
251
  });
254
252
  }
255
- targets.push({ scope: "global", roleName: "operator" });
256
- const current = deps.terminal.current();
257
- if (current && !targets.some(function (target) { return sameTarget(target, current); })) targets.unshift(current);
258
- deps.terminal.setTargets(targets);
253
+ deps.workspace.setTargets(targets);
259
254
  }
260
255
 
261
256
  function showOverview(deps) {
@@ -264,6 +259,7 @@ function showOverview(deps) {
264
259
  select: deps.selectTask,
265
260
  filterAttention: deps.pickAttention,
266
261
  readSessions: deps.readPageSessions,
262
+ togglePanel: function () { deps.workspace.toggleDock(); },
267
263
  toggleOperator: deps.workspace.toggleOperator,
268
264
  revealSidebar: deps.revealSidebar
269
265
  });
@@ -861,10 +861,7 @@ export const EN = {
861
861
  "store.job": "Operation",
862
862
  "dock.label": "Session panel",
863
863
  "dock.discussion": "Discussion",
864
- "dock.session": "Terminal",
865
864
  "conversation.title": "Conversation",
866
- "conversation.defaultMode": "Default view",
867
- "conversation.defaultSaved": "Saved for future openings in this browser. The current view and Session are unchanged.",
868
865
  "conversation.nativeRequest": "Codex native request",
869
866
  "conversation.nativeOmitted": "Additional or large native requests are available in Terminal.",
870
867
  "conversation.leaderQuestions": "Leader questions · Task input channel",
@@ -880,15 +877,22 @@ export const EN = {
880
877
  "conversation.input": "Message to the selected Session",
881
878
  "conversation.send": "Send",
882
879
  "conversation.model": "Session model",
883
- "conversation.modelsLoad": "Load available models",
884
- "conversation.modelApply": "Apply while idle",
885
- "conversation.launchModel": "Fixed launch request",
886
- "conversation.confirmedModel": "Last native confirmation",
880
+ "conversation.modelsLoad": "Reload",
881
+ "conversation.modelApply": "Apply selection",
882
+ "conversation.selectedModel": "Selected model",
883
+ "conversation.modelNotSelected": "Choose a model",
884
+ "conversation.modelsLoading": "Loading models…",
885
+ "conversation.modelsFailed": "Could not read models. Please reload.",
886
+ "conversation.modelsEmpty": "No models available",
887
+ "conversation.modelBusy": "A turn is running. Apply your selection when it finishes.",
888
+ "conversation.modelTerminalBusy": "Exit Codex in the native terminal before applying. Closing the terminal panel does not exit it.",
889
+ "conversation.launchModel": "Launch config",
890
+ "conversation.confirmedModel": "Execution model",
887
891
  "conversation.modelBoundary": "Same Codex Thread; idle only. Does not change Role defaults or the current Turn. A Host reconnect restores the fixed launch configuration; check the native confirmation again. No automatic retry.",
888
- "conversation.modelApplying": "Applying model; waiting for native confirmation…",
889
- "conversation.modelConfirmed": "Native model adoption confirmed for this live connection.",
890
- "conversation.modelFailed": "Not applied. Review the reason before trying again.",
891
- "conversation.modelUnknown": "Adoption unconfirmed. Do not retry; inspect confirmation or explicitly select a new Session through existing lifecycle controls.",
892
+ "conversation.modelApplying": "Switching model…",
893
+ "conversation.modelConfirmed": "Model switched",
894
+ "conversation.modelFailed": "Could not switch models. Check that the session is idle before retrying.",
895
+ "conversation.modelUnknown": "Switch not yet confirmed. Repeat submission is blocked.",
892
896
  "conversation.commands": "Supported commands",
893
897
  "conversation.literal": "Send as ordinary text",
894
898
  "conversation.command.help": "Show supported operations",
@@ -899,7 +903,6 @@ export const EN = {
899
903
  "conversation.command.latest": "Return to latest messages",
900
904
  "conversation.commandHelp": "/help · /status · /model · /stop · /latest. Tab completes an unambiguous command; Ctrl/⌘+Enter sends. These are Yui controls, not arbitrary native CLI commands.",
901
905
  "conversation.commandUnknown": "Unsupported command. Use /help, or explicitly send it as ordinary text.",
902
- "conversation.draftSaved": "Draft saved in this browser tab · Ctrl/⌘+Enter to send",
903
906
  "conversation.storageFailed": "Browser storage is unavailable. Keep a copy of this draft before leaving.",
904
907
  "conversation.receiptDetails": "Exact receipt",
905
908
  "conversation.receipt.sending": "Sending once…",
@@ -927,13 +930,48 @@ export const EN = {
927
930
  "conversation.empty": "No public items on this page. Older pages may contain messages.",
928
931
  "conversation.liveUnavailable": "Live reply observation unavailable; native history only",
929
932
  "conversation.truncated": "Long item excerpt; open native access for the full item.",
930
- "conversation.placeholder": "Message this Session…",
931
- "conversation.more": "More",
933
+ "conversation.placeholder": "Message this Session… (/ for commands)",
932
934
  "conversation.copy": "Copy",
933
935
  "conversation.copied": "Copied",
934
936
  "conversation.jump": "Jump to latest",
935
937
  "conversation.selectModel": "Select model",
936
938
  "conversation.worked": "Worked",
939
+ "conversation.modelConfirmedNote": "Confirmed {time} at start, resume or switch; not a live reading, and Desktop changes may not show",
940
+ "conversation.modelStateConfirmed": "Last confirmed",
941
+ "conversation.modelStatePending": "Applying",
942
+ "conversation.modelConfirmedShort": "last native confirmation {time}; not live",
943
+ "conversation.details": "Session details",
944
+ "conversation.copyIdentity": "Copy identity",
945
+ "conversation.copyFailed": "Copy unavailable in this browser",
946
+ "conversation.modelUnconfirmed": "Model unconfirmed",
947
+ "conversation.modelUnconfirmedHint": "No native confirmation for this Session; the launch config is not shown as current.",
948
+ "conversation.modelPendingLabel": "Applying",
949
+ "conversation.modelHistorical": "Previous Sessions are not observed live.",
950
+ "conversation.modelNoRead": "Not reported yet.",
951
+ "conversation.effortUnobserved": "effort not reported",
952
+ "conversation.launchNote": "Requested at launch; not current",
953
+ "conversation.agentDefault": "Agent default",
954
+ "conversation.sendHint": "Send (Ctrl/⌘+Enter)",
955
+ "conversation.backCurrent": "Back to current Session",
956
+ "conversation.backCurrentShort": "Current",
957
+ "conversation.readOnlyHistory": "Previous Session · read only",
958
+ "conversation.placeholderHistory": "Previous Sessions are read only",
959
+ "conversation.pendingInput": "Waiting for the last input's receipt",
960
+ "conversation.turnUnsettled": "Last input delivery is unsettled",
961
+ "conversation.inputUnavailable": "Input unavailable for this Session",
962
+ "conversation.sessionActive": "Running",
963
+ "conversation.sessionEnded": "Ended",
964
+ "conversation.sessionFailed": "Failed",
965
+ "conversation.previousSessions": "Previous",
966
+ "conversation.noSessionShort": "No Session",
967
+ "conversation.sessionLabel": "Session",
968
+ "conversation.sessionId": "Session ID",
969
+ "conversation.authority": "Authority",
970
+ "conversation.agent": "Agent",
971
+ "conversation.turn": "Turn",
972
+ "conversation.writer": "Input",
973
+ "conversation.stateUnknown": "Unknown",
974
+ "conversation.disconnectedShort": "Disconnected",
937
975
  "conversation.activity.commandExecution": "Ran",
938
976
  "conversation.activity.fileChange": "Edited files",
939
977
  "conversation.activity.mcpToolCall": "Used tool",
@@ -942,6 +980,7 @@ export const EN = {
942
980
  "conversation.activity.collabAgentToolCall": "Asked another agent",
943
981
  "dock.swap": "Swap with task details",
944
982
  "dock.hide": "Hide session panel",
983
+ "dock.show": "Show session panel",
945
984
  "dock.resize": "Resize session panel",
946
985
  "dock.target": "Session target",
947
986
  "discussion.title": "Task discussion",
@@ -999,10 +1038,15 @@ export const EN = {
999
1038
  "terminal.closed": "Detached",
1000
1039
  "terminal.error": "Unavailable",
1001
1040
  "terminal.errorDetail": "Unable to open this native Session. Check that the Controller is running and the Role has a Session.",
1002
- "terminal.global": "Global",
1003
- "terminal.noTargets": "No Roles",
1004
- "terminal.emptyTitle": "Attach to a native Session",
1005
- "terminal.emptyText": "Pick a Role above. The panel shows the Session's current screen; attaching never starts or restarts an Agent.",
1041
+ "session.mode": "Session view",
1042
+ "session.modeChat": "Chat",
1043
+ "session.modeTerminal": "Terminal",
1044
+ "terminal.unavailable": "Unavailable",
1045
+ "terminal.noSessionTitle": "No Session to attach",
1046
+ "terminal.noSessionText": "This Role has no attachable Session yet. Attaching never starts an Agent.",
1047
+ "terminal.notCurrentTitle": "Not the current Session",
1048
+ "terminal.notCurrentText": "The terminal can only attach to the current Session; the selected Session is no longer current.",
1049
+ "conversation.roleReadOnly": "This Role is read only here; its input goes through its dispatch controls.",
1006
1050
  "terminal.cliHint": "Full terminal",
1007
1051
  "terminal.historyLimited": "This Role has a {current}-line tmux history. Exit and re-enter it to use {target} lines.",
1008
1052
  "global.open": "Global input",
@@ -857,10 +857,7 @@ export const ZH_CN = {
857
857
  "store.job": "操作",
858
858
  "dock.label": "会话面板",
859
859
  "dock.discussion": "讨论",
860
- "dock.session": "终端",
861
860
  "conversation.title": "会话",
862
- "conversation.defaultMode": "默认展示",
863
- "conversation.defaultSaved": "已保存为此浏览器今后打开时的默认展示;当前视图和 Session 未切换。",
864
861
  "conversation.nativeRequest": "Codex 原生请求",
865
862
  "conversation.nativeOmitted": "更多或较大的原生请求请在终端处理。",
866
863
  "conversation.leaderQuestions": "Leader 问题 · Task 输入通道",
@@ -876,15 +873,22 @@ export const ZH_CN = {
876
873
  "conversation.input": "发送到选中的会话",
877
874
  "conversation.send": "发送",
878
875
  "conversation.model": "当前会话模型",
879
- "conversation.modelsLoad": "读取可用模型",
880
- "conversation.modelApply": "空闲时采用",
881
- "conversation.launchModel": "固定启动请求",
882
- "conversation.confirmedModel": "最近原生确认",
876
+ "conversation.modelsLoad": "重新加载",
877
+ "conversation.modelApply": "应用选择",
878
+ "conversation.selectedModel": "选中模型",
879
+ "conversation.modelNotSelected": "请选择",
880
+ "conversation.modelsLoading": "正在加载模型…",
881
+ "conversation.modelsFailed": "模型列表读取失败,请重新加载。",
882
+ "conversation.modelsEmpty": "暂无可用模型",
883
+ "conversation.modelBusy": "当前正在执行,结束后可应用选择。",
884
+ "conversation.modelTerminalBusy": "请先在原生终端退出 Codex,再应用选择。仅关闭终端面板不会退出。",
885
+ "conversation.launchModel": "启动配置",
886
+ "conversation.confirmedModel": "当前执行模型",
883
887
  "conversation.modelBoundary": "只切换同一 Codex Thread,且必须空闲。不更改角色默认配置或当前轮次。Host 重连会恢复固定启动配置,请重新核对原生确认。不会自动重试。",
884
- "conversation.modelApplying": "正在采用模型,等待原生确认…",
885
- "conversation.modelConfirmed": "原生已确认当前连接采用该模型。",
886
- "conversation.modelFailed": "未采用。请查看原因后再决定是否重试。",
887
- "conversation.modelUnknown": "采用结果未确认。请勿重试;查看最近确认,或通过现有生命周期控制明确选择新会话。",
888
+ "conversation.modelApplying": "正在切换模型…",
889
+ "conversation.modelConfirmed": "模型已切换",
890
+ "conversation.modelFailed": "未能切换模型,请确认会话空闲后再试。",
891
+ "conversation.modelUnknown": "切换结果待确认,暂不可重复提交。",
888
892
  "conversation.commands": "支持的命令",
889
893
  "conversation.literal": "作为普通文本发送",
890
894
  "conversation.command.help": "查看支持的操作",
@@ -895,7 +899,6 @@ export const ZH_CN = {
895
899
  "conversation.command.latest": "返回最新消息",
896
900
  "conversation.commandHelp": "/help · /status · /model · /stop · /latest。Tab 补全唯一匹配;Ctrl/⌘+Enter 发送。这些是 Yui 操作,不是任意原生 CLI 命令。",
897
901
  "conversation.commandUnknown": "不支持此命令。请使用 /help,或明确选择作为普通文本发送。",
898
- "conversation.draftSaved": "草稿已保存在当前浏览器标签页 · Ctrl/⌘+Enter 发送",
899
902
  "conversation.storageFailed": "浏览器存储不可用。离开前请保留草稿副本。",
900
903
  "conversation.receiptDetails": "精确回执",
901
904
  "conversation.receipt.sending": "正在发送,不会重复提交…",
@@ -923,13 +926,48 @@ export const ZH_CN = {
923
926
  "conversation.empty": "此页没有公开消息,可继续读取更早的历史。",
924
927
  "conversation.liveUnavailable": "实时回复观测不可用,仅显示原生历史",
925
928
  "conversation.truncated": "长消息仅显示摘要;完整内容请打开原生入口。",
926
- "conversation.placeholder": "给当前会话发消息…",
927
- "conversation.more": "更多",
929
+ "conversation.placeholder": "给当前会话发消息…(/ 查看命令)",
928
930
  "conversation.copy": "复制",
929
931
  "conversation.copied": "已复制",
930
932
  "conversation.jump": "回到最新",
931
933
  "conversation.selectModel": "选择模型",
932
934
  "conversation.worked": "已处理",
935
+ "conversation.modelConfirmedNote": "{time} 于启动、恢复或切换时确认;非实时读取,外部 Desktop 改动可能未反映",
936
+ "conversation.modelStateConfirmed": "最近确认",
937
+ "conversation.modelStatePending": "待应用",
938
+ "conversation.modelConfirmedShort": "最近原生确认 {time};非实时",
939
+ "conversation.details": "会话详情",
940
+ "conversation.copyIdentity": "复制标识",
941
+ "conversation.copyFailed": "此浏览器无法复制",
942
+ "conversation.modelUnconfirmed": "模型未确认",
943
+ "conversation.modelUnconfirmedHint": "此会话尚无原生确认;不会把启动配置当作当前模型。",
944
+ "conversation.modelPendingLabel": "应用中",
945
+ "conversation.modelHistorical": "历史会话不做实时观测。",
946
+ "conversation.modelNoRead": "尚未报告。",
947
+ "conversation.effortUnobserved": "未报告推理强度",
948
+ "conversation.launchNote": "启动时请求;非当前",
949
+ "conversation.agentDefault": "Agent 默认",
950
+ "conversation.sendHint": "发送(Ctrl/⌘+Enter)",
951
+ "conversation.backCurrent": "回到当前会话",
952
+ "conversation.backCurrentShort": "当前",
953
+ "conversation.readOnlyHistory": "历史会话 · 只读",
954
+ "conversation.placeholderHistory": "历史会话只读",
955
+ "conversation.pendingInput": "等待上一条输入的回执",
956
+ "conversation.turnUnsettled": "上一条输入的投递尚未确定",
957
+ "conversation.inputUnavailable": "此会话暂不可输入",
958
+ "conversation.sessionActive": "运行中",
959
+ "conversation.sessionEnded": "已结束",
960
+ "conversation.sessionFailed": "失败",
961
+ "conversation.previousSessions": "历史",
962
+ "conversation.noSessionShort": "无会话",
963
+ "conversation.sessionLabel": "会话",
964
+ "conversation.sessionId": "会话 ID",
965
+ "conversation.authority": "执行权",
966
+ "conversation.agent": "Agent",
967
+ "conversation.turn": "Turn",
968
+ "conversation.writer": "输入方",
969
+ "conversation.stateUnknown": "未知",
970
+ "conversation.disconnectedShort": "已断开",
933
971
  "conversation.activity.commandExecution": "运行",
934
972
  "conversation.activity.fileChange": "修改文件",
935
973
  "conversation.activity.mcpToolCall": "调用工具",
@@ -938,6 +976,7 @@ export const ZH_CN = {
938
976
  "conversation.activity.collabAgentToolCall": "询问其他 Agent",
939
977
  "dock.swap": "与任务详情交换位置",
940
978
  "dock.hide": "隐藏会话面板",
979
+ "dock.show": "显示会话面板",
941
980
  "dock.resize": "调整会话面板宽度",
942
981
  "dock.target": "会话目标",
943
982
  "discussion.title": "任务讨论",
@@ -995,10 +1034,15 @@ export const ZH_CN = {
995
1034
  "terminal.closed": "已分离",
996
1035
  "terminal.error": "不可用",
997
1036
  "terminal.errorDetail": "无法打开该原生会话。请确认 Controller 正在运行且该 Role 已有会话。",
998
- "terminal.global": "全局",
999
- "terminal.noTargets": "暂无 Role",
1000
- "terminal.emptyTitle": "连接到原生会话",
1001
- "terminal.emptyText": "在上方选择一个 Role。面板显示该会话的当前画面;连接不会启动或重启 Agent。",
1037
+ "session.mode": "会话视图",
1038
+ "session.modeChat": "聊天",
1039
+ "session.modeTerminal": "终端",
1040
+ "terminal.unavailable": "不可连接",
1041
+ "terminal.noSessionTitle": "没有可连接的会话",
1042
+ "terminal.noSessionText": "该角色还没有可连接的会话;连接不会启动 Agent。",
1043
+ "terminal.notCurrentTitle": "不是当前会话",
1044
+ "terminal.notCurrentText": "终端只能连接当前会话;所选会话已不是当前会话。",
1045
+ "conversation.roleReadOnly": "此角色在这里只读,输入通过其分派控制。",
1002
1046
  "terminal.cliHint": "完整终端",
1003
1047
  "terminal.historyLimited": "这个 Role 的 tmux 历史只有 {current} 行;退出并重新进入后可使用 {target} 行。",
1004
1048
  "global.open": "全局消息",
@@ -36,6 +36,7 @@ import { WORK_SCRIPT } from "./domain/work.js";
36
36
  import { DISCUSSION_SCRIPT } from "./views/dock/discussion.js";
37
37
  import { CONVERSATION_SCRIPT } from "./views/dock/conversation.js";
38
38
  import { TERMINAL_SCRIPT } from "./views/dock/terminal.js";
39
+ import { SESSION_PAGE_SCRIPT } from "./views/dock/session.js";
39
40
  import { PREVIEW_SCRIPT } from "./views/dock/preview.js";
40
41
  import { GLOBAL_INPUT_SCRIPT } from "./views/globalInput.js";
41
42
  import { CREATE_TASK_SCRIPT } from "./views/createTask.js";
@@ -106,6 +107,7 @@ export const CLIENT_MODULES = Object.freeze({
106
107
  "views/dock/discussion": DISCUSSION_SCRIPT,
107
108
  "views/dock/conversation": CONVERSATION_SCRIPT,
108
109
  "views/dock/terminal": TERMINAL_SCRIPT,
110
+ "views/dock/session": SESSION_PAGE_SCRIPT,
109
111
  "views/dock/preview": PREVIEW_SCRIPT,
110
112
  "views/task/page": TASK_PAGE_SCRIPT,
111
113
  "views/task/actions": TASK_ACTIONS_SCRIPT,
@@ -7,7 +7,7 @@ import { isEditing } from "/assets/js/lib/dom.js";
7
7
  const TABS = ${JSON.stringify(TASK_TABS)};
8
8
 
9
9
  // deps: { el, state, globalInput, workspace, sidebarNav, selection, catalog, taskView }
10
- // el #search, #settings-dialog and #terminal-host
10
+ // el #search, #settings-dialog and the dock (its terminal host)
11
11
  // state read-only here: state.selected, state.detail
12
12
  // globalInput views/globalInput (its dialog blocks shortcuts while open)
13
13
  // workspace layout/workspace: the dock and the operator Session
@@ -20,7 +20,7 @@ export function bindShortcuts(deps) {
20
20
  if (document.querySelector("dialog[open]")) return;
21
21
  const active = document.activeElement;
22
22
  const typing = isEditing(active);
23
- const inTerminal = deps.el.terminalHost.contains(active);
23
+ const inTerminal = !!active && !!active.closest && !!active.closest(".terminal-host");
24
24
  if (event.key === "Escape") { escape(deps, active, typing, inTerminal); return; }
25
25
  if (typing || inTerminal || event.metaKey || event.ctrlKey || event.altKey) return;
26
26
  shortcut(deps, event);