dsh-composer-plus 1.1.1 → 1.3.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.
package/index.js CHANGED
@@ -3,7 +3,10 @@
3
3
  * - Message-free Continue: authenticated resume through public agent lifecycle hooks.
4
4
  * - Changes panel: read-only git status/diff for a session's working directory, served on the authenticated `/api` channel.
5
5
  * - Persistent Auto Review grants: per-session tool names saved under the dsh home, so "Allow for this chat" survives a restart.
6
+ * - Update check: the latest GitHub release, offered only once npm serves that exact version (the client installs it
7
+ * through dsh's own plugin manager).
6
8
  */
9
+ import { readFileSync } from 'node:fs';
7
10
  import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
8
11
  import { randomUUID } from 'node:crypto';
9
12
  import { homedir } from 'node:os';
@@ -16,6 +19,14 @@ export const CHANGES_PATH = '/api/composer-plus.changes';
16
19
  export const DIFF_PATH = '/api/composer-plus.diff';
17
20
  export const GRANTS_PATH = '/api/composer-plus.grants';
18
21
  export const CONTINUE_PATH = '/api/composer-plus.continue';
22
+ export const UPDATE_PATH = '/api/composer-plus.update';
23
+ export const SHOT_PATH = '/api/composer-plus.shot';
24
+ /** Feature screenshots shipped in assets/features/<id>.webp; only these ids are served (no path input). */
25
+ export const SHOTS = ['changesPanel', 'projectStatus', 'recentProjects', 'collapseProjects', 'notifications', 'allowForChat', 'continueButton', 'inputHistory', 'planToggle',
26
+ 'queueReorder', 'copyDeeplink', 'copyProjectPath', 'language', 'autoUpdate'];
27
+ const PACKAGE = JSON.parse(readFileSync(new URL('./package.json', import.meta.url), 'utf8'));
28
+ const NPM_NAME = 'dsh-composer-plus';
29
+ const RELEASES_URL = 'https://api.github.com/repos/furkancak1r/dsh-composer-plus/releases/latest';
19
30
  const CONTINUE_SOURCE = 'composer-plus-continue';
20
31
  const CONTINUE_TEXT = 'The previous turn stopped before it finished (it was interrupted or failed). Continue the task from where it stopped. Do not repeat completed work.';
21
32
  const continueMessage = () => Object.freeze({ id: randomUUID(), role: 'user', content: Object.freeze([Object.freeze({ type: 'text', text: CONTINUE_TEXT })]),
@@ -158,6 +169,31 @@ export function grantsStore(file) {
158
169
  };
159
170
  }
160
171
 
172
+ /** `1.2.3` / `v1.2.3` -> [1, 2, 3]; anything else (pre-releases, ranges) is not an update target. */
173
+ export const parseVersion = (text) => {
174
+ const m = /^v?(\d{1,6})\.(\d{1,6})\.(\d{1,6})$/.exec(String(text ?? '').trim());
175
+ return m === null ? undefined : m.slice(1).map(Number);
176
+ };
177
+ export const newer = (a, b) => { for (let i = 0; i < 3; i++) if (a[i] !== b[i]) return a[i] > b[i]; return false; };
178
+ /** Latest GitHub release vs this copy. `managed` is false for a renamed or linked local copy, which pnpm can't upgrade. */
179
+ export async function checkUpdate(fetchImpl = fetch, pkg = PACKAGE, signal) {
180
+ const current = parseVersion(pkg.version);
181
+ const managed = pkg.name === NPM_NAME && current !== undefined;
182
+ const timeout = AbortSignal.timeout(10000);
183
+ const opts = { signal: signal === undefined ? timeout : AbortSignal.any([signal, timeout]) };
184
+ const response = await fetchImpl(RELEASES_URL, { ...opts, headers: { accept: 'application/vnd.github+json', 'user-agent': NPM_NAME } });
185
+ if (!response.ok) throw new Error(`GitHub answered ${response.status}`);
186
+ const release = await response.json();
187
+ const latest = parseVersion(release?.tag_name);
188
+ if (latest === undefined) throw new Error('latest release has no x.y.z tag');
189
+ const info = { name: NPM_NAME, current: pkg.version, latest: latest.join('.'), managed, newer: false,
190
+ url: typeof release.html_url === 'string' && release.html_url.startsWith('https://github.com/') ? release.html_url : undefined };
191
+ if (current === undefined || !newer(latest, current)) return info;
192
+ // A release can go out before `npm publish`; offer only what pnpm can install.
193
+ const npm = await fetchImpl(`https://registry.npmjs.org/${NPM_NAME}/${info.latest}`, opts);
194
+ return { ...info, newer: npm.ok };
195
+ }
196
+
161
197
  const json = (value, status = 200) => Response.json(value, { status, headers: { 'cache-control': 'no-store' } });
162
198
  const isText = (v, max = 512) => typeof v === 'string' && v.length > 0 && v.length <= max;
163
199
 
@@ -239,6 +275,23 @@ export function apply(ctx) {
239
275
  } catch (error) { return json({ error: String(error?.message ?? error) }, 500); }
240
276
  },
241
277
  });
278
+ ctx.connection.fetch.register({
279
+ path: SHOT_PATH, methods: ['GET'], requestBody: 'buffered',
280
+ fetch: async (request) => {
281
+ const id = new URL(request.url).searchParams.get('id');
282
+ if (!SHOTS.includes(id)) return json({ error: 'not found' }, 404);
283
+ try {
284
+ const bytes = await readFile(new URL(`./assets/features/${id}.webp`, import.meta.url));
285
+ return new Response(bytes, { headers: { 'content-type': 'image/webp', 'cache-control': 'private, max-age=86400' } });
286
+ } catch { return json({ error: 'not found' }, 404); }
287
+ },
288
+ });
289
+ ctx.connection.fetch.register({
290
+ path: UPDATE_PATH, methods: ['GET'], requestBody: 'buffered',
291
+ fetch: async (request) => {
292
+ try { return json(await checkUpdate(fetch, PACKAGE, request.signal)); } catch (error) { return json({ error: String(error?.message ?? error) }, 502); }
293
+ },
294
+ });
242
295
  const store = grantsStore(join(process.env.DSH_HOME || join(homedir(), '.dsh'), 'storages', 'dsh-composer-plus', 'grants.json'));
243
296
  ctx.connection.fetch.register({
244
297
  path: GRANTS_PATH, methods: ['GET', 'POST'], requestBody: 'buffered',
package/locale/de.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Composer Plus",
4
+ "description": "Änderungsansicht, Eingabeverlauf, Shift+Tab /plan, Fortsetzen mit einem Klick, Warteschlange per Drag-and-drop, Links, Benachrichtigungen, 11 Sprachen und automatische Updates."
5
+ }
6
+ }
package/locale/en.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Composer Plus",
4
+ "description": "Changes panel, input history, Shift+Tab /plan, one-click Continue, queue drag-and-drop, deeplinks, notifications, 11 UI languages and automatic updates."
5
+ }
6
+ }
package/locale/es.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Composer Plus",
4
+ "description": "Panel de cambios, historial de entrada, Shift+Tab /plan, Continuar con un clic, reordenar la cola arrastrando, enlaces, notificaciones, 11 idiomas y actualizaciones automáticas."
5
+ }
6
+ }
package/locale/fr.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Composer Plus",
4
+ "description": "Panneau des modifications, historique de saisie, Shift+Tab /plan, Continuer en un clic, file réorganisable par glisser-déposer, liens, notifications, 11 langues et mises à jour automatiques."
5
+ }
6
+ }
package/locale/hi.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Composer Plus",
4
+ "description": "बदलाव पैनल, इनपुट इतिहास, Shift+Tab /plan, एक क्लिक में जारी रखें, कतार ड्रैग-एंड-ड्रॉप, लिंक, सूचनाएं, 11 भाषाएं और अपने-आप अपडेट।"
5
+ }
6
+ }
package/locale/id.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Composer Plus",
4
+ "description": "Panel perubahan, riwayat input, Shift+Tab /plan, Lanjutkan sekali klik, urutkan antrean dengan seret, tautan, notifikasi, 11 bahasa, dan pembaruan otomatis."
5
+ }
6
+ }
package/locale/ja.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Composer Plus",
4
+ "description": "変更パネル、入力履歴、Shift+Tab で /plan、ワンクリック続行、キューのドラッグ並べ替え、リンク、通知、11 言語、自動アップデート。"
5
+ }
6
+ }
package/locale/ko.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Composer Plus",
4
+ "description": "변경 사항 패널, 입력 기록, Shift+Tab /plan, 원클릭 계속, 대기열 끌어서 정렬, 링크, 알림, 11개 언어와 자동 업데이트."
5
+ }
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Composer Plus",
4
+ "description": "Painel de alterações, histórico de entrada, Shift+Tab /plan, Continuar com um clique, reordenar a fila arrastando, links, notificações, 11 idiomas e atualizações automáticas."
5
+ }
6
+ }
package/locale/ru.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Composer Plus",
4
+ "description": "Панель изменений, история ввода, Shift+Tab /plan, продолжение в один клик, перетаскивание очереди, ссылки, уведомления, 11 языков и автообновления."
5
+ }
6
+ }
package/locale/tr.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Composer Plus",
4
+ "description": "Değişiklikler paneli, giriş geçmişi, Shift+Tab /plan, tek tıkla devam, sıradaki mesajları sürükle-bırak, bağlantılar, bildirimler, 11 arayüz dili ve otomatik güncellemeler."
5
+ }
6
+ }
package/locale/vi.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Composer Plus",
4
+ "description": "Bảng thay đổi, lịch sử nhập, Shift+Tab /plan, Tiếp tục một chạm, kéo thả hàng đợi, liên kết, thông báo, 11 ngôn ngữ và tự động cập nhật."
5
+ }
6
+ }
package/locale/zh.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Composer Plus",
4
+ "description": "改动面板、输入历史、Shift+Tab /plan、一键继续、队列拖拽排序、会话链接、通知、11 种界面语言和自动更新。"
5
+ }
6
+ }
package/package.json CHANGED
@@ -1,35 +1,60 @@
1
1
  {
2
2
  "name": "dsh-composer-plus",
3
- "version": "1.1.1",
4
- "description": "DeepSeek Harness helpers: 11 extra UI languages (Türkçe, Español, Français, Deutsch, 日本語…), Changes panel, input history, Shift+Tab /plan, one-click Continue, queue drag-and-drop, deeplinks, Auto Review allow-for-chat, notifications",
3
+ "version": "1.3.0",
4
+ "description": "DeepSeek Harness helpers: 11 extra UI languages (Türkçe, Español, Français, Deutsch, 日本語…), Changes panel, input history, Shift+Tab /plan, one-click Continue, queue drag-and-drop, deeplinks, Auto Review allow-for-chat, notifications, automatic updates",
5
+ "icon": "./assets/icon.svg",
5
6
  "license": "MIT",
6
7
  "type": "module",
7
8
  "keywords": [
9
+ "auto-review",
10
+ "auto-update",
8
11
  "changes",
12
+ "claude-code",
13
+ "codex",
14
+ "collapse-all",
15
+ "composer-plus",
16
+ "continue",
17
+ "copy-path",
18
+ "deeplink",
19
+ "deepseek",
9
20
  "deepseek-harness",
21
+ "deepseek-harness-plugin",
22
+ "drag-and-drop",
10
23
  "dsh",
24
+ "dsh-composer-plus",
11
25
  "dsh-plugin",
26
+ "dsh-plugins",
12
27
  "git",
28
+ "git-diff",
13
29
  "i18n",
30
+ "input-history",
14
31
  "localization",
15
32
  "notifications",
33
+ "plan-mode",
16
34
  "plugin",
35
+ "queue",
36
+ "recent-projects",
17
37
  "translation"
18
38
  ],
19
39
  "exports": {
20
40
  ".": "./index.js",
21
- "./client": "./client.js"
41
+ "./client": "./client.js",
42
+ "./locale/*.json": "./locale/*.json",
43
+ "./package.json": "./package.json"
22
44
  },
23
45
  "files": [
24
46
  "index.js",
25
47
  "client.js",
48
+ "locale/*.json",
49
+ "assets/icon.svg",
26
50
  "cordis.patch.yml",
27
51
  "README.md",
28
52
  "LICENSE",
29
- "locales/LICENSE"
53
+ "locales/LICENSE",
54
+ "assets/features/*.webp"
30
55
  ],
31
56
  "scripts": {
32
- "test": "node scripts/build-locales.mjs --check && node test/locale.test.mjs && node test/continue.test.mjs && node test/continue-host.test.mjs && node test/queue-drag.test.mjs && node test/plan-toggle.test.mjs && node test/deeplink.test.mjs && node test/chat-grant.test.mjs && node test/notify.test.mjs && node test/changes.test.mjs && node test/project-status.test.mjs && node test/toggles.test.mjs",
57
+ "test": "node scripts/build-locales.mjs --check && node test/locale.test.mjs && node test/continue.test.mjs && node test/continue-host.test.mjs && node test/queue-drag.test.mjs && node test/plan-toggle.test.mjs && node test/deeplink.test.mjs && node test/chat-grant.test.mjs && node test/notify.test.mjs && node test/changes.test.mjs && node test/project-status.test.mjs && node test/recent-projects.test.mjs && node test/project-tools.test.mjs && node test/toggles.test.mjs && node test/update.test.mjs && node test/meta.test.mjs && node test/shots.test.mjs",
33
58
  "build:locales": "node scripts/build-locales.mjs",
34
59
  "prepublishOnly": "npm test"
35
60
  },