dsh-composer-plus 1.0.0 → 1.0.2

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 (3) hide show
  1. package/README.md +4 -4
  2. package/client.js +34 -11
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -21,7 +21,7 @@ dsh plugin --profile web add dsh-composer-plus
21
21
 
22
22
  Then restart dsh. (The CLI can't install into the desktop profile; the app manages it.)
23
23
 
24
- > dsh's pnpm skips versions younger than 24 hours. Right after a release, add the version: `dsh-composer-plus@1.0.0`.
24
+ > dsh's pnpm skips versions younger than 24 hours. Right after a release, add the version: `dsh-composer-plus@1.0.2`.
25
25
 
26
26
  ## Features
27
27
 
@@ -30,12 +30,12 @@ Then restart dsh. (The CLI can't install into the desktop profile; the app manag
30
30
  | **Changes panel** | Right sidebar → `+` → **Changes**. Pick **Uncommitted**, **Unstaged**, **Staged** or **Branch** to see changed files with `+/-` counts; click a file for its diff. **Last Turn** opens dsh's own review of the latest turn. |
31
31
  | **Input history** | In an empty composer, press `↑` / `↓` to walk through messages you sent, like a terminal. |
32
32
  | **Plan mode shortcut** | `Shift+Tab` adds `/plan ` to the start of the draft (press again to remove it). If the chat is already in plan mode, `Shift+Tab` leaves it. |
33
- | **One-click Continue** | When a turn has stopped and the composer is empty, Send turns into **▶**. One click sends “continue” in dsh's language (`continue` / `继续`). |
33
+ | **One-click Continue** | When the last turn was stopped, failed or cut off and the composer is empty, Send turns into **▶**. One click sends “continue” in dsh's language (`continue` / `继续`). A turn that finished normally keeps the regular Send button. |
34
34
  | **Queue drag-and-drop** | Queued messages get a grip (⠿). Drag to reorder, or focus the grip and press `↑` / `↓`. `Esc` cancels. |
35
35
  | **Copy deeplink** | Right-click a chat in the sidebar → **Copy deeplink**. Paste the `dsh-session:…` link into another chat to attach that chat as read-only context. |
36
36
  | **Allow for this chat** | When Auto Review asks you, the approval card gets **Allow for this chat**: the same tool in the same chat is allowed from then on, with any arguments. A header chip lists the grants and revokes them. Grants survive a restart. |
37
37
  | **Project status** | A project row in the sidebar shows the same spinner / waiting / done marker as its chats, so a collapsed project still tells you a chat inside is working or needs you. Hover it for details. |
38
- | **Active projects first** | When a chat starts running or needs you, its project moves to the top of the sidebar with dsh's own row animation (the same move as dragging it there). Finished projects stay where they are; drag them anywhere as usual. |
38
+ | **Active projects first** | When a chat starts running or needs you, its project moves to the top of the sidebar with dsh's own row animation (the same move as dragging it there). Finished projects stay where they are; drag them anywhere as usual. Moves are saved to dsh's project order, so turning this off keeps the current order. |
39
39
  | **Background notifications** | While dsh is in the background you get a notification when a turn finishes (first line of the reply), or when a chat needs an approval (tool name), an answer (the question) or a plan review. The Dock/taskbar badge counts waiting chats. Clicking opens that chat. |
40
40
 
41
41
  All text — buttons, tooltips, notices, notifications and the Continue message — follows the language selected in dsh (English or Chinese, the two languages dsh ships). Switching the language in dsh settings updates it live.
@@ -69,7 +69,7 @@ Tested on dsh `0.2.0-rc.2` (desktop and web) and `0.2.1-alpha.2` (web). CI runs
69
69
 
70
70
  - **No notifications on macOS:** System Settings → Notifications → DeepSeek Harness → allow. Choose **Alerts** to keep them on screen.
71
71
  - **▶, queue grips, project status, Allow for this chat or right-click missing after a dsh update:** these attach to dsh's current HTML because dsh has no slot for them yet. If dsh changes that markup they hide themselves; nothing else breaks. Please open an [issue](https://github.com/furkancak1r/dsh-composer-plus/issues).
72
- - **Install fails right after a release:** add the version (`dsh-composer-plus@1.0.0`), see the install note above.
72
+ - **Install fails right after a release:** add the version (`dsh-composer-plus@1.0.2`), see the install note above.
73
73
 
74
74
  ## Limits
75
75
 
package/client.js CHANGED
@@ -207,12 +207,25 @@ window.__ModuleLoader__.load({
207
207
  const buttons = [...seat.querySelectorAll('button')].filter((b) => /(^|\s)\w+_primary(\s|$)/.test(b.className));
208
208
  return buttons.length === 0 ? null : buttons[buttons.length - 1];
209
209
  }
210
- /** Codex-style resume: when the turn has stopped, the composer is empty and the chat has history,
211
- * Send turns into a play button that submits "continue". Send is not a slot, so the play button is
212
- * portaled into Send's row with Send's own class and Send is hidden meanwhile.
213
- * Hidden on a blank chat, while running, in subagent views, or as soon as the user types or attaches. */
214
- function ContinueButton({ useSession, useInput, inputActions, t }) {
215
- const show = useSession((s) => s !== undefined && !s.blank && !s.running && s.subagent === null && !s.removed);
210
+ /** True when the newest turn in the loaded window did not finish normally: stopped, failed, cut by a token
211
+ * limit, or still open without a running agent (lost connection). A completed turn needs no resume. */
212
+ function needsResume(entries) {
213
+ for (let i = entries.length - 1; i >= 0; i--) {
214
+ const event = entries[i].event;
215
+ if (event.type === 'turn/end') return event.data?.reason?.kind !== 'completed';
216
+ if (event.type === 'turn/start') return true;
217
+ }
218
+ return false;
219
+ }
220
+ /** Codex-style resume: when the last turn was stopped or failed, the composer is empty and the chat has
221
+ * history, Send turns into a play button that submits "continue". A normally completed turn keeps dsh's
222
+ * own Send. Send is not a slot, so the play button is portaled into Send's row with Send's own class and
223
+ * Send is hidden meanwhile. Hidden on a blank chat, while running, in subagent views, or as soon as the
224
+ * user types or attaches. */
225
+ function ContinueButton({ useSession, useInput, useTurnEnd, inputActions, t }) {
226
+ const ended = typeof useTurnEnd === 'function' ? useTurnEnd((window) => window !== undefined && needsResume(window.entries)) : false;
227
+ const failed = useSession((s) => s !== undefined && (s.lastAgentError != null || s.promptError != null));
228
+ const show = useSession((s) => s !== undefined && !s.blank && !s.running && s.subagent === null && !s.removed) && (ended || failed);
216
229
  const idle = useInput((s) => s !== undefined && s.phase === 'plain' && s.draft.trim() === '' && s.attachmentIds.length === 0);
217
230
  const visible = show && idle && inputActions !== undefined;
218
231
  const anchorRef = React.useRef(null);
@@ -877,6 +890,11 @@ window.__ModuleLoader__.load({
877
890
  id: 'composer-continue',
878
891
  order: 1000,
879
892
  locale: LOCALE_NS,
893
+ inject: (sessionId) => {
894
+ // The session's loaded event window; its newest turn/end says how the last turn finished.
895
+ const source = ctx.sessions?.binding?.(sessionId)?.eventSource;
896
+ return source === undefined ? {} : { hooks: { turnEnd: source } };
897
+ },
880
898
  }, ContinueButton))]);
881
899
  if (ctx.locale !== undefined) ctx.effect(() => ctx.locale.register(LOCALE_NS, {
882
900
  en: {
@@ -887,13 +905,13 @@ window.__ModuleLoader__.load({
887
905
  'feature.projectStatus': 'Project status',
888
906
  'feature.projectStatus.description': 'Show the running / waiting / done marker of a project\'s chats on the project row.',
889
907
  'feature.activeProjectsFirst': 'Active projects first',
890
- 'feature.activeProjectsFirst.description': 'Move a project to the top of the sidebar when one of its chats runs or needs you.',
908
+ 'feature.activeProjectsFirst.description': 'Move a project to the top of the sidebar when one of its chats runs or needs you. Moves are saved; turning this off keeps the current order.',
891
909
  'feature.notifications': 'Background notifications',
892
910
  'feature.notifications.description': 'Notify when a chat finishes or needs you while dsh is in the background, with a Dock badge.',
893
911
  'feature.allowForChat': 'Allow for this chat',
894
912
  'feature.allowForChat.description': 'Add “Allow for this chat” to Auto Review approvals and auto-allow granted tools.',
895
913
  'feature.continueButton': 'One-click Continue',
896
- 'feature.continueButton.description': 'Turn Send into ▶ after a stopped turn; one click sends “continue”.',
914
+ 'feature.continueButton.description': 'Turn Send into ▶ after a stopped or failed turn; one click sends “continue”.',
897
915
  'feature.inputHistory': 'Input history',
898
916
  'feature.inputHistory.description': 'Use ↑ / ↓ in an empty composer to reuse messages you sent.',
899
917
  'feature.planToggle': 'Shift+Tab plan mode',
@@ -954,13 +972,13 @@ window.__ModuleLoader__.load({
954
972
  'feature.projectStatus': '项目状态',
955
973
  'feature.projectStatus.description': '在项目行上显示其对话的进行中 / 等待 / 完成标记。',
956
974
  'feature.activeProjectsFirst': '活跃项目置顶',
957
- 'feature.activeProjectsFirst.description': '当项目中的对话正在运行或需要你处理时,将该项目移到侧边栏顶部。',
975
+ 'feature.activeProjectsFirst.description': '当项目中的对话正在运行或需要你处理时,将该项目移到侧边栏顶部。移动会被保存;关闭此项后保留当前顺序。',
958
976
  'feature.notifications': '后台通知',
959
977
  'feature.notifications.description': 'dsh 在后台时,对话完成或需要你处理时发出通知,并显示程序坞角标。',
960
978
  'feature.allowForChat': '本对话内允许',
961
979
  'feature.allowForChat.description': '在 Auto Review 审批中添加“本对话内允许”,并自动允许已授权的工具。',
962
980
  'feature.continueButton': '一键继续',
963
- 'feature.continueButton.description': '回合停止后,发送按钮变为 ▶,点击即发送“继续”。',
981
+ 'feature.continueButton.description': '回合被停止或出错后,发送按钮变为 ▶,点击即发送“继续”。',
964
982
  'feature.inputHistory': '输入历史',
965
983
  'feature.inputHistory.description': '在空输入框中按 ↑ / ↓ 复用已发送的消息。',
966
984
  'feature.planToggle': 'Shift+Tab 计划模式',
@@ -1019,7 +1037,12 @@ window.__ModuleLoader__.load({
1019
1037
  id: 'project-status',
1020
1038
  locale: LOCALE_NS,
1021
1039
  }, ProjectStatusMarkers))]);
1022
- const injectScope = (deps, setup) => (ctx.inject === undefined ? [] : [ctx.inject(deps, setup)]);
1040
+ // ctx.inject returns a Cordis fiber, not a disposer.
1041
+ const injectScope = (deps, setup) => {
1042
+ if (ctx.inject === undefined) return [];
1043
+ const fiber = ctx.inject(deps, setup);
1044
+ return [() => fiber.dispose()];
1045
+ };
1023
1046
  feature('notifications', () => injectScope(['uiSession', 'uiWorkspace', 'sessions'], (scope) => {
1024
1047
  const t = ctx.locale.bind(LOCALE_NS);
1025
1048
  scope.effect(() => watchAttention(scope.uiSession.sessionStatus, scope.sessions.list, t,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-composer-plus",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "DeepSeek Harness helpers: Codex-style Changes panel, input history, Shift+Tab /plan, one-click Continue, queue drag-and-drop, Copy deeplink, Auto Review allow-for-chat, background notifications",
5
5
  "license": "MIT",
6
6
  "type": "module",