@linxin666/dsh-client-ui-task-board 0.3.1 → 0.3.3
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/README.i18n.yaml +2 -2
- package/README.md +6 -2
- package/README.zh.md +6 -2
- package/lib/client.js +72 -1
- package/lib/client.js.map +1 -1
- package/lib/index.js +3 -3
- package/lib/types/client/index.d.ts +1 -1
- package/lib/types/client/settings-form.d.ts +1 -1
- package/lib/types/client/telemetry.d.ts +26 -0
- package/lib/types/http.d.ts +1 -1
- package/lib/types/index.d.ts +1 -1
- package/lib/types/loopback.d.ts +1 -1
- package/lib/types/mount-once.d.ts +1 -1
- package/package.json +2 -4
- package/src/client/board/TaskBoard.tsx +1 -1
- package/src/client/index.ts +6 -1
- package/src/client/settings-form.ts +1 -1
- package/src/client/telemetry.ts +105 -0
- package/src/http.ts +1 -1
- package/src/index.ts +1 -1
- package/src/loopback.ts +1 -1
- package/src/mount-once.ts +2 -2
package/lib/index.js
CHANGED
|
@@ -2465,7 +2465,7 @@ function makeTaskBoardRoutes(service, access = {}) {
|
|
|
2465
2465
|
//#region src/mount-once.ts
|
|
2466
2466
|
/**
|
|
2467
2467
|
* Host single-instance guard shared by the plugin family. The family bundle
|
|
2468
|
-
* (dsh-web-
|
|
2468
|
+
* (dsh-web-all / dsh-skins) namespaces every child row id (web-ui-*), so
|
|
2469
2469
|
* the loader accepts a standalone install of the same package side by side;
|
|
2470
2470
|
* without this guard the second instance would still re-register the same
|
|
2471
2471
|
* webserver routes, tools, settings namespaces, and system-prompt sections
|
|
@@ -2478,7 +2478,7 @@ function makeTaskBoardRoutes(service, access = {}) {
|
|
|
2478
2478
|
* `ctx.effect` runs its callback immediately and treats the callback's
|
|
2479
2479
|
* return value as the fiber disposer, so the unmarker is returned, not run.
|
|
2480
2480
|
*/
|
|
2481
|
-
const MOUNTED = Symbol.for("dsh-web
|
|
2481
|
+
const MOUNTED = Symbol.for("dsh-web.mounted-plugins");
|
|
2482
2482
|
function mountedSet() {
|
|
2483
2483
|
const registry = globalThis;
|
|
2484
2484
|
return registry[MOUNTED] ??= /* @__PURE__ */ new Set();
|
|
@@ -2516,7 +2516,7 @@ const inject = [
|
|
|
2516
2516
|
"commands"
|
|
2517
2517
|
];
|
|
2518
2518
|
/** Model-facing announcement: plugin presence, capabilities, and limits. */
|
|
2519
|
-
const TASK_BOARD_GUIDANCE = "本机已安装 dsh-task-board 插件(DSH Web GUI 的任务看板):侧边栏「任务看板」入口;在 dsh-web
|
|
2519
|
+
const TASK_BOARD_GUIDANCE = "本机已安装 dsh-task-board 插件(DSH Web GUI 的任务看板):侧边栏「任务看板」入口;在 dsh-web 插件全家桶仓库(packages/dsh-task-board)统一维护,经聚合包 web-ui-all 一键安装。能力:多列看板管理任务;Host 权威账本;关闭浏览器后仍由 Host 执行和结算;任务可钉住工作区、agent 预设和权限;支持 Host 本地时区的 5 段 cron,错过的触发点不补跑;可选且默认关闭的空闲系统睡眠保护允许屏幕熄灭,但不承诺拦截合盖、手动睡眠、休眠、关机或唤醒已睡眠机器。执行消耗 API 额度。用户提到「任务看板 / 看板 / 定时任务」时即指本插件,请据此协作。若你同时用 todo_write 维护会话顶部的可见计划列表,最终回复前必须再次调用 todo_write 收尾:没有剩余工作时不要保留 in_progress,已完成的最后一步要标为 completed。";
|
|
2520
2520
|
/**
|
|
2521
2521
|
* Settings namespace of the board's announcement capability — the section the
|
|
2522
2522
|
* web settings surface edits. Spelled here rather than imported: the browser
|
|
@@ -37,7 +37,7 @@ export interface SettingsPluginItemOwnerProps {
|
|
|
37
37
|
declare module '@deepseek-ai/cordis' {
|
|
38
38
|
interface Context {
|
|
39
39
|
/**
|
|
40
|
-
* Optional rc.6 compatibility binder provided by dsh-web-
|
|
40
|
+
* Optional rc.6 compatibility binder provided by dsh-web-settings;
|
|
41
41
|
* absent when that group plugin is not installed, so callers fall back to
|
|
42
42
|
* the official settings scope.
|
|
43
43
|
*/
|
|
@@ -173,7 +173,7 @@ export declare class CardForm<T> {
|
|
|
173
173
|
/**
|
|
174
174
|
* Write every staged edit, then re-seed from what the Host accepted.
|
|
175
175
|
*
|
|
176
|
-
* When the scope carries the optional batch surface (the dsh-web
|
|
176
|
+
* When the scope carries the optional batch surface (the dsh-web
|
|
177
177
|
* bridge scope), every planned write rides one mutation so cross-field
|
|
178
178
|
* validate hooks (baseURL+model) judge the batch as a unit instead of
|
|
179
179
|
* deadlocking on per-field writes. Otherwise the per-field loop runs.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anonymous install telemetry shared by the DSH Web UI family plugins.
|
|
3
|
+
*
|
|
4
|
+
* Once per UTC day per browser, each wired plugin sends one heartbeat to
|
|
5
|
+
* the dsh-market edge API listing its package name (and version when known).
|
|
6
|
+
* The payload carries no conversation data and no identifiers beyond a random
|
|
7
|
+
* UUID generated in localStorage; the server hashes it with a deployment salt
|
|
8
|
+
* before storage and never persists IP addresses. Sends are fire-and-forget:
|
|
9
|
+
* failures stay silent and simply retry on a later mount or day. The system
|
|
10
|
+
* is documented in docs/telemetry.md.
|
|
11
|
+
*/
|
|
12
|
+
export type TelemetryChannel = 'market' | 'npm' | 'unknown';
|
|
13
|
+
export interface TelemetryItem {
|
|
14
|
+
/** npm package name or asset id, e.g. "@linxin666/dsh-pet" or "skin:harbor". */
|
|
15
|
+
name: string;
|
|
16
|
+
/** Installed version when known; omitted otherwise. */
|
|
17
|
+
version?: string;
|
|
18
|
+
/** Install channel when determinable (market = Workshop install). */
|
|
19
|
+
channel?: TelemetryChannel;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Fire the daily heartbeat for the given items at most once per UTC day per
|
|
23
|
+
* browser. Never throws and never blocks the caller. Items without an explicit
|
|
24
|
+
* version inherit the bundle's baked build version.
|
|
25
|
+
*/
|
|
26
|
+
export declare function reportDailyHeartbeat(items: readonly TelemetryItem[]): void;
|
package/lib/types/http.d.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* edit this shared source and re-run the sync instead of editing a copy.
|
|
11
11
|
* Consumer code is migrated onto it in follow-up waves; no call site changes
|
|
12
12
|
* belong in the same change as its introduction.
|
|
13
|
-
* @module dsh-web-
|
|
13
|
+
* @module dsh-web-shared/host/http
|
|
14
14
|
*/
|
|
15
15
|
import type { IncomingMessage, OutgoingHttpHeaders, ServerResponse } from 'node:http';
|
|
16
16
|
/**
|
package/lib/types/index.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ import z from 'schemastery';
|
|
|
11
11
|
export declare const DEFAULT_PROXY_TOKEN_ENV = "DSH_TASK_BOARD_PROXY_TOKEN";
|
|
12
12
|
export declare const inject: string[];
|
|
13
13
|
/** Model-facing announcement: plugin presence, capabilities, and limits. */
|
|
14
|
-
export declare const TASK_BOARD_GUIDANCE = "\u672C\u673A\u5DF2\u5B89\u88C5 dsh-task-board \u63D2\u4EF6\uFF08DSH Web GUI \u7684\u4EFB\u52A1\u770B\u677F\uFF09\uFF1A\u4FA7\u8FB9\u680F\u300C\u4EFB\u52A1\u770B\u677F\u300D\u5165\u53E3\uFF1B\u5728 dsh-web
|
|
14
|
+
export declare const TASK_BOARD_GUIDANCE = "\u672C\u673A\u5DF2\u5B89\u88C5 dsh-task-board \u63D2\u4EF6\uFF08DSH Web GUI \u7684\u4EFB\u52A1\u770B\u677F\uFF09\uFF1A\u4FA7\u8FB9\u680F\u300C\u4EFB\u52A1\u770B\u677F\u300D\u5165\u53E3\uFF1B\u5728 dsh-web \u63D2\u4EF6\u5168\u5BB6\u6876\u4ED3\u5E93\uFF08packages/dsh-task-board\uFF09\u7EDF\u4E00\u7EF4\u62A4\uFF0C\u7ECF\u805A\u5408\u5305 web-ui-all \u4E00\u952E\u5B89\u88C5\u3002\u80FD\u529B\uFF1A\u591A\u5217\u770B\u677F\u7BA1\u7406\u4EFB\u52A1\uFF1BHost \u6743\u5A01\u8D26\u672C\uFF1B\u5173\u95ED\u6D4F\u89C8\u5668\u540E\u4ECD\u7531 Host \u6267\u884C\u548C\u7ED3\u7B97\uFF1B\u4EFB\u52A1\u53EF\u9489\u4F4F\u5DE5\u4F5C\u533A\u3001agent \u9884\u8BBE\u548C\u6743\u9650\uFF1B\u652F\u6301 Host \u672C\u5730\u65F6\u533A\u7684 5 \u6BB5 cron\uFF0C\u9519\u8FC7\u7684\u89E6\u53D1\u70B9\u4E0D\u8865\u8DD1\uFF1B\u53EF\u9009\u4E14\u9ED8\u8BA4\u5173\u95ED\u7684\u7A7A\u95F2\u7CFB\u7EDF\u7761\u7720\u4FDD\u62A4\u5141\u8BB8\u5C4F\u5E55\u7184\u706D\uFF0C\u4F46\u4E0D\u627F\u8BFA\u62E6\u622A\u5408\u76D6\u3001\u624B\u52A8\u7761\u7720\u3001\u4F11\u7720\u3001\u5173\u673A\u6216\u5524\u9192\u5DF2\u7761\u7720\u673A\u5668\u3002\u6267\u884C\u6D88\u8017 API \u989D\u5EA6\u3002\u7528\u6237\u63D0\u5230\u300C\u4EFB\u52A1\u770B\u677F / \u770B\u677F / \u5B9A\u65F6\u4EFB\u52A1\u300D\u65F6\u5373\u6307\u672C\u63D2\u4EF6\uFF0C\u8BF7\u636E\u6B64\u534F\u4F5C\u3002\u82E5\u4F60\u540C\u65F6\u7528 todo_write \u7EF4\u62A4\u4F1A\u8BDD\u9876\u90E8\u7684\u53EF\u89C1\u8BA1\u5212\u5217\u8868\uFF0C\u6700\u7EC8\u56DE\u590D\u524D\u5FC5\u987B\u518D\u6B21\u8C03\u7528 todo_write \u6536\u5C3E\uFF1A\u6CA1\u6709\u5269\u4F59\u5DE5\u4F5C\u65F6\u4E0D\u8981\u4FDD\u7559 in_progress\uFF0C\u5DF2\u5B8C\u6210\u7684\u6700\u540E\u4E00\u6B65\u8981\u6807\u4E3A completed\u3002";
|
|
15
15
|
/**
|
|
16
16
|
* Settings namespace of the board's announcement capability — the section the
|
|
17
17
|
* web settings surface edits. Spelled here rather than imported: the browser
|
package/lib/types/loopback.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* Semantics: RFC 5735 IPv4 127/8, ::1, IPv4-mapped ::ffff:127/8 (matching the
|
|
8
8
|
* remote-web-ui gate), localhost hostnames, plus the browser same-origin
|
|
9
9
|
* markers (sec-fetch-site and Origin) for the request-level fence.
|
|
10
|
-
* @module dsh-web-
|
|
10
|
+
* @module dsh-web-shared/host/loopback
|
|
11
11
|
*/
|
|
12
12
|
import type { IncomingMessage } from 'node:http';
|
|
13
13
|
/** IPv4 127/8 predicate (four decimal octets, first == 127). */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Host single-instance guard shared by the plugin family. The family bundle
|
|
3
|
-
* (dsh-web-
|
|
3
|
+
* (dsh-web-all / dsh-skins) namespaces every child row id (web-ui-*), so
|
|
4
4
|
* the loader accepts a standalone install of the same package side by side;
|
|
5
5
|
* without this guard the second instance would still re-register the same
|
|
6
6
|
* webserver routes, tools, settings namespaces, and system-prompt sections
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@linxin666/dsh-client-ui-task-board",
|
|
3
3
|
"description": "Host-authoritative task board for the DSH Web GUI with real session execution, Host cron scheduling, and optional cross-platform idle-sleep protection; mounted without DSH source changes.",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"types": "lib/types/index.d.ts",
|
|
@@ -38,8 +38,6 @@
|
|
|
38
38
|
}
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
|
-
"@deepseek-ai/dsh-agent": "^0.1.1-rc.2",
|
|
42
|
-
"@deepseek-ai/dsh-commands": "^0.1.1-rc.2",
|
|
43
41
|
"react": "^18.2.0"
|
|
44
42
|
},
|
|
45
43
|
"dependencies": {
|
|
@@ -79,7 +77,7 @@
|
|
|
79
77
|
"license": "Apache-2.0",
|
|
80
78
|
"repository": {
|
|
81
79
|
"type": "git",
|
|
82
|
-
"url": "https://github.com/zhu1090093659/dsh-web
|
|
80
|
+
"url": "https://github.com/zhu1090093659/dsh-web.git"
|
|
83
81
|
},
|
|
84
82
|
"scripts": {
|
|
85
83
|
"build": "tsc -p tsconfig.build.json && tsdown",
|
|
@@ -52,7 +52,7 @@ export function TaskBoard({ controller }: { controller: BoardController }) {
|
|
|
52
52
|
return (
|
|
53
53
|
<div className={css.board} data-dsh-taskboard-board="" data-dsh-plugin="task-board">
|
|
54
54
|
<header className={css.boardHeader}>
|
|
55
|
-
{/* Shared hook: dsh-web-
|
|
55
|
+
{/* Shared hook: dsh-web-all offsets center-view back controls beside the collapsed mobile sidebar. */}
|
|
56
56
|
<button
|
|
57
57
|
type="button"
|
|
58
58
|
className={`${css.ghostButton} ${css.backButton}`}
|
package/src/client/index.ts
CHANGED
|
@@ -24,6 +24,7 @@ import { mountSidebarEntry } from './sidebar-entry.ts'
|
|
|
24
24
|
import { TaskBoardSettingsCard, TaskBoardSettingsCardController, type TaskBoardSettings } from './TaskBoardSettingsCard.tsx'
|
|
25
25
|
import { en, zh, type TaskBoardKey } from './locales.ts'
|
|
26
26
|
import { HttpTaskBoardHostTransport } from './host-api.ts'
|
|
27
|
+
import { reportDailyHeartbeat } from './telemetry.ts'
|
|
27
28
|
|
|
28
29
|
/** Locale namespace this plugin owns. */
|
|
29
30
|
const NS = 'task-board'
|
|
@@ -57,7 +58,7 @@ export interface SettingsPluginItemOwnerProps {
|
|
|
57
58
|
declare module '@deepseek-ai/cordis' {
|
|
58
59
|
interface Context {
|
|
59
60
|
/**
|
|
60
|
-
* Optional rc.6 compatibility binder provided by dsh-web-
|
|
61
|
+
* Optional rc.6 compatibility binder provided by dsh-web-settings;
|
|
61
62
|
* absent when that group plugin is not installed, so callers fall back to
|
|
62
63
|
* the official settings scope.
|
|
63
64
|
*/
|
|
@@ -74,6 +75,10 @@ export const inject = ['slots', 'sessions', 'workspaces', 'connection', 'setting
|
|
|
74
75
|
* @param ctx - client root context (services: sessions, workspaces).
|
|
75
76
|
*/
|
|
76
77
|
export function apply(ctx: ClientContext): void {
|
|
78
|
+
// Anonymous install heartbeat (docs/telemetry.md): one beat per browser per
|
|
79
|
+
// UTC day, package name only, silent failure.
|
|
80
|
+
reportDailyHeartbeat([{ name: '@linxin666/dsh-client-ui-task-board' }])
|
|
81
|
+
|
|
77
82
|
// A duplicated client injection (module factory executed twice in one page
|
|
78
83
|
// lifetime) would otherwise mount a second sidebar entry and board view.
|
|
79
84
|
// First application wins; later calls become no-ops (see apply-guard.ts).
|
|
@@ -320,7 +320,7 @@ export class CardForm<T> {
|
|
|
320
320
|
/**
|
|
321
321
|
* Write every staged edit, then re-seed from what the Host accepted.
|
|
322
322
|
*
|
|
323
|
-
* When the scope carries the optional batch surface (the dsh-web
|
|
323
|
+
* When the scope carries the optional batch surface (the dsh-web
|
|
324
324
|
* bridge scope), every planned write rides one mutation so cross-field
|
|
325
325
|
* validate hooks (baseURL+model) judge the batch as a unit instead of
|
|
326
326
|
* deadlocking on per-field writes. Otherwise the per-field loop runs.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// Generated by scripts/sync-shared.mjs from shared/client/telemetry.ts. Do not edit this copy; edit the shared source and run "node scripts/sync-shared.mjs".
|
|
2
|
+
/**
|
|
3
|
+
* Anonymous install telemetry shared by the DSH Web UI family plugins.
|
|
4
|
+
*
|
|
5
|
+
* Once per UTC day per browser, each wired plugin sends one heartbeat to
|
|
6
|
+
* the dsh-market edge API listing its package name (and version when known).
|
|
7
|
+
* The payload carries no conversation data and no identifiers beyond a random
|
|
8
|
+
* UUID generated in localStorage; the server hashes it with a deployment salt
|
|
9
|
+
* before storage and never persists IP addresses. Sends are fire-and-forget:
|
|
10
|
+
* failures stay silent and simply retry on a later mount or day. The system
|
|
11
|
+
* is documented in docs/telemetry.md.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export type TelemetryChannel = 'market' | 'npm' | 'unknown'
|
|
15
|
+
|
|
16
|
+
export interface TelemetryItem {
|
|
17
|
+
/** npm package name or asset id, e.g. "@linxin666/dsh-pet" or "skin:harbor". */
|
|
18
|
+
name: string
|
|
19
|
+
/** Installed version when known; omitted otherwise. */
|
|
20
|
+
version?: string
|
|
21
|
+
/** Install channel when determinable (market = Workshop install). */
|
|
22
|
+
channel?: TelemetryChannel
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const VISITOR_KEY = 'dsh-web-ui-telemetry-visitor'
|
|
26
|
+
const DAY_KEY_PREFIX = 'dsh-web-ui-telemetry-day:'
|
|
27
|
+
const ENDPOINT = 'https://dsh-market.com/api/telemetry/event'
|
|
28
|
+
|
|
29
|
+
// Baked into each client bundle by shared/tsdown.client.ts (the package's own
|
|
30
|
+
// package.json version at build time). Undefined in dev/test builds.
|
|
31
|
+
declare const __DSH_PKG_VERSION__: string | undefined
|
|
32
|
+
|
|
33
|
+
/** The building package's version, when the bundle carries it. */
|
|
34
|
+
function bakedVersion(): string | undefined {
|
|
35
|
+
try {
|
|
36
|
+
return typeof __DSH_PKG_VERSION__ === 'string' && __DSH_PKG_VERSION__ !== ''
|
|
37
|
+
? __DSH_PKG_VERSION__
|
|
38
|
+
: undefined
|
|
39
|
+
} catch {
|
|
40
|
+
return undefined
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Read or lazily create the anonymous visitor id; null when storage is unavailable. */
|
|
45
|
+
function visitorId(): string | null {
|
|
46
|
+
try {
|
|
47
|
+
const existing = localStorage.getItem(VISITOR_KEY)
|
|
48
|
+
if (existing && /^[A-Za-z0-9_-]{16,64}$/.test(existing)) return existing
|
|
49
|
+
const fresh = crypto.randomUUID().replaceAll('-', '')
|
|
50
|
+
localStorage.setItem(VISITOR_KEY, fresh)
|
|
51
|
+
return fresh
|
|
52
|
+
} catch {
|
|
53
|
+
// Storage unavailable (privacy mode, sandboxed frame): report nothing.
|
|
54
|
+
return null
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Drop stale per-day dedup keys so localStorage does not grow forever. */
|
|
59
|
+
function pruneDayKeys(today: string): void {
|
|
60
|
+
try {
|
|
61
|
+
for (let index = localStorage.length - 1; index >= 0; index -= 1) {
|
|
62
|
+
const key = localStorage.key(index)
|
|
63
|
+
if (key !== null && key.startsWith(DAY_KEY_PREFIX) && key !== DAY_KEY_PREFIX + today) {
|
|
64
|
+
localStorage.removeItem(key)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
} catch { /* best effort */ }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Fire the daily heartbeat for the given items at most once per UTC day per
|
|
72
|
+
* browser. Never throws and never blocks the caller. Items without an explicit
|
|
73
|
+
* version inherit the bundle's baked build version.
|
|
74
|
+
*/
|
|
75
|
+
export function reportDailyHeartbeat(items: readonly TelemetryItem[]): void {
|
|
76
|
+
try {
|
|
77
|
+
if (items.length === 0) return
|
|
78
|
+
const today = new Date().toISOString().slice(0, 10)
|
|
79
|
+
// Automation contexts (CDP-driven QA browsers, fresh isolated profiles)
|
|
80
|
+
// mint a new visitor id per run and would inflate instance counts.
|
|
81
|
+
if (navigator.webdriver) return
|
|
82
|
+
if (localStorage.getItem(DAY_KEY_PREFIX + today) !== null) return
|
|
83
|
+
const visitor = visitorId()
|
|
84
|
+
if (visitor === null) return
|
|
85
|
+
pruneDayKeys(today)
|
|
86
|
+
const payloadItems = items.map((item) => {
|
|
87
|
+
const out: Record<string, string> = { name: item.name }
|
|
88
|
+
const version = item.version ?? bakedVersion()
|
|
89
|
+
if (version !== undefined) out.version = version
|
|
90
|
+
if (item.channel !== undefined) out.channel = item.channel
|
|
91
|
+
return out
|
|
92
|
+
})
|
|
93
|
+
const body = JSON.stringify({ kind: 'heartbeat', visitor, items: payloadItems })
|
|
94
|
+
void fetch(ENDPOINT, {
|
|
95
|
+
method: 'POST',
|
|
96
|
+
headers: { 'content-type': 'application/json' },
|
|
97
|
+
body,
|
|
98
|
+
keepalive: true,
|
|
99
|
+
}).then((response) => {
|
|
100
|
+
// Mark the day only after an accepted send, so offline browsers retry
|
|
101
|
+
// on a later mount instead of going dark until tomorrow.
|
|
102
|
+
if (response.ok) localStorage.setItem(DAY_KEY_PREFIX + today, '1')
|
|
103
|
+
}).catch(() => { /* unreachable endpoint: stay silent */ })
|
|
104
|
+
} catch { /* never break the host UI over telemetry */ }
|
|
105
|
+
}
|
package/src/http.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* edit this shared source and re-run the sync instead of editing a copy.
|
|
12
12
|
* Consumer code is migrated onto it in follow-up waves; no call site changes
|
|
13
13
|
* belong in the same change as its introduction.
|
|
14
|
-
* @module dsh-web-
|
|
14
|
+
* @module dsh-web-shared/host/http
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import type { IncomingMessage, OutgoingHttpHeaders, ServerResponse } from 'node:http'
|
package/src/index.ts
CHANGED
|
@@ -27,7 +27,7 @@ export const DEFAULT_PROXY_TOKEN_ENV = 'DSH_TASK_BOARD_PROXY_TOKEN'
|
|
|
27
27
|
export const inject = ['systemPrompt', 'apiProxy', 'webServer', 'agents', 'commands']
|
|
28
28
|
|
|
29
29
|
/** Model-facing announcement: plugin presence, capabilities, and limits. */
|
|
30
|
-
export const TASK_BOARD_GUIDANCE = '本机已安装 dsh-task-board 插件(DSH Web GUI 的任务看板):侧边栏「任务看板」入口;在 dsh-web
|
|
30
|
+
export const TASK_BOARD_GUIDANCE = '本机已安装 dsh-task-board 插件(DSH Web GUI 的任务看板):侧边栏「任务看板」入口;在 dsh-web 插件全家桶仓库(packages/dsh-task-board)统一维护,经聚合包 web-ui-all 一键安装。能力:多列看板管理任务;Host 权威账本;关闭浏览器后仍由 Host 执行和结算;任务可钉住工作区、agent 预设和权限;支持 Host 本地时区的 5 段 cron,错过的触发点不补跑;可选且默认关闭的空闲系统睡眠保护允许屏幕熄灭,但不承诺拦截合盖、手动睡眠、休眠、关机或唤醒已睡眠机器。执行消耗 API 额度。用户提到「任务看板 / 看板 / 定时任务」时即指本插件,请据此协作。若你同时用 todo_write 维护会话顶部的可见计划列表,最终回复前必须再次调用 todo_write 收尾:没有剩余工作时不要保留 in_progress,已完成的最后一步要标为 completed。'
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* Settings namespace of the board's announcement capability — the section the
|
package/src/loopback.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* Semantics: RFC 5735 IPv4 127/8, ::1, IPv4-mapped ::ffff:127/8 (matching the
|
|
9
9
|
* remote-web-ui gate), localhost hostnames, plus the browser same-origin
|
|
10
10
|
* markers (sec-fetch-site and Origin) for the request-level fence.
|
|
11
|
-
* @module dsh-web-
|
|
11
|
+
* @module dsh-web-shared/host/loopback
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import type { IncomingMessage } from 'node:http'
|
package/src/mount-once.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Generated by scripts/sync-shared.mjs from shared/host/mount-once.ts. Do not edit this copy; edit the shared source and run "node scripts/sync-shared.mjs".
|
|
2
2
|
/**
|
|
3
3
|
* Host single-instance guard shared by the plugin family. The family bundle
|
|
4
|
-
* (dsh-web-
|
|
4
|
+
* (dsh-web-all / dsh-skins) namespaces every child row id (web-ui-*), so
|
|
5
5
|
* the loader accepts a standalone install of the same package side by side;
|
|
6
6
|
* without this guard the second instance would still re-register the same
|
|
7
7
|
* webserver routes, tools, settings namespaces, and system-prompt sections
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* return value as the fiber disposer, so the unmarker is returned, not run.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
const MOUNTED = Symbol.for('dsh-web
|
|
18
|
+
const MOUNTED = Symbol.for('dsh-web.mounted-plugins')
|
|
19
19
|
|
|
20
20
|
interface MountRegistry {
|
|
21
21
|
[MOUNTED]?: Set<string>
|