dsh-task-dispatch-table 0.1.12 → 0.1.13

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/dist/config.d.ts CHANGED
@@ -28,7 +28,17 @@ export interface PluginConfig {
28
28
  */
29
29
  /** 上传临时区保留期(天):到期文件由 tick 内清道夫删除(默认 7)。 */
30
30
  attachmentTmpRetentionDays: number;
31
+ /** 侧栏显示名;空串 = 用词典默认名(`panelTitle`)。 */
32
+ displayName: string;
33
+ /** 侧栏入口位置:`first` = 一级菜单(默认);`more` = 收进「更多」菜单。 */
34
+ entryMode: EntryMode;
35
+ /** 屏蔽官方「自动化任务」入口(`@deepseek-ai/dsh-client-ui-schedule`);false = 不屏蔽(默认)。 */
36
+ hideOfficialSchedule: boolean;
31
37
  }
38
+ /** 侧栏入口的两档位置(设置区下拉的取值,别用自由字符串)。 */
39
+ export type EntryMode = 'first' | 'more';
40
+ /** `entryMode` 的合法取值(服务端校验 + 前端下拉共用,防两处漂移)。 */
41
+ export declare const ENTRY_MODES: readonly EntryMode[];
32
42
  /**
33
43
  * **系统默认值**(全量,含字符串路径类)—— `Config` schema 与设置页「用户没设时显示什么」的唯一真源。
34
44
  *
@@ -50,6 +60,9 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
50
60
  defaultModel: z<string, string, "defined">;
51
61
  logRetentionDays: z<number, number, "defined">;
52
62
  attachmentTmpRetentionDays: z<number, number, "defined">;
63
+ displayName: z<string, string, "defined">;
64
+ entryMode: z<string, string, "defined">;
65
+ hideOfficialSchedule: z<boolean, boolean, "defined">;
53
66
  }>>, Schemastery.ObjectT<NoInfer<{
54
67
  statePath: z<string, string, "defined">;
55
68
  tickMs: z<number, number, "defined">;
@@ -63,6 +76,9 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
63
76
  defaultModel: z<string, string, "defined">;
64
77
  logRetentionDays: z<number, number, "defined">;
65
78
  attachmentTmpRetentionDays: z<number, number, "defined">;
79
+ displayName: z<string, string, "defined">;
80
+ entryMode: z<string, string, "defined">;
81
+ hideOfficialSchedule: z<boolean, boolean, "defined">;
66
82
  }>>, "plain">;
67
83
  /**
68
84
  * rc.1 volatile 字段的解析结果是**带 get() 的引用**(非纯值);读取时解包(与参考插件
package/dist/config.js CHANGED
@@ -4,6 +4,8 @@
4
4
  import { homedir } from 'node:os';
5
5
  import { join, resolve } from 'node:path';
6
6
  import z from '@deepseek-ai/schemastery';
7
+ /** `entryMode` 的合法取值(服务端校验 + 前端下拉共用,防两处漂移)。 */
8
+ export const ENTRY_MODES = ['first', 'more'];
7
9
  /**
8
10
  * **系统默认值**(全量,含字符串路径类)—— `Config` schema 与设置页「用户没设时显示什么」的唯一真源。
9
11
  *
@@ -24,6 +26,9 @@ export const CONFIG_DEFAULTS = {
24
26
  unknownGraceMs: 5 * 60_000,
25
27
  logRetentionDays: 30,
26
28
  attachmentTmpRetentionDays: 7,
29
+ displayName: '',
30
+ entryMode: 'first',
31
+ hideOfficialSchedule: false,
27
32
  };
28
33
  // ⚠️ rc.1(0.1.7-rc.1)约束:宿主插件配置字段**不能标 .volatile()**。
29
34
  // 实测根因(set717/lib/index.js:417 + types/index.js:368-380):configForms 的读写都要求字段
@@ -48,6 +53,12 @@ export const Config = z.object({
48
53
  defaultModel: z.string().default(CONFIG_DEFAULTS.defaultModel),
49
54
  logRetentionDays: z.number().min(1).default(CONFIG_DEFAULTS.logRetentionDays),
50
55
  attachmentTmpRetentionDays: z.number().min(1).default(CONFIG_DEFAULTS.attachmentTmpRetentionDays),
56
+ // ── 设置区(插件详情页)三个字段:显示名 / 入口位置 / 屏蔽官方自动化 ──
57
+ // entryMode 用 string 而非字面量联合:schemastery 的 union 在宿主界面上没好处,
58
+ // 合法性由服务端白名单(ENTRY_MODES)与前端下拉共同保证。
59
+ displayName: z.string().default(CONFIG_DEFAULTS.displayName),
60
+ entryMode: z.string().default(CONFIG_DEFAULTS.entryMode),
61
+ hideOfficialSchedule: z.boolean().default(CONFIG_DEFAULTS.hideOfficialSchedule),
51
62
  });
52
63
  /**
53
64
  * rc.1 volatile 字段的解析结果是**带 get() 的引用**(非纯值);读取时解包(与参考插件
@@ -71,7 +82,7 @@ export function readConfigField(field, fallback) {
71
82
  export function resolveStatePath(statePath) {
72
83
  if (statePath.trim().length > 0)
73
84
  return resolve(statePath);
74
- const raw = process.env['DSH_HOME'];
85
+ const raw = process.env.DSH_HOME;
75
86
  const selected = raw !== undefined && raw.trim().length > 0 ? raw : join(homedir(), '.dsh');
76
87
  const home = selected === '~' || selected.startsWith('~/')
77
88
  ? join(homedir(), selected.slice(selected.length === 1 ? 1 : 2))
package/dist/index.d.ts CHANGED
@@ -17,8 +17,8 @@ export type { PluginConfig };
17
17
  * `tasksInline`(整份任务表 JSON)与 `debugSnapshot`(宿主调试数据),不能整份吐给浏览器。
18
18
  */
19
19
  export declare function configView(config: PluginConfig): {
20
- config: Record<string, string | number>;
21
- defaults: Record<string, string | number>;
20
+ config: Record<string, string | number | boolean>;
21
+ defaults: Record<string, string | number | boolean>;
22
22
  };
23
23
  /** 附件约束(白名单/上限/扩展名解析)与浏览器端预检**共用同一份**,防两处漂移。 */
24
24
  export { ATTACHMENT_MAX_BYTES, ALLOWED_ATTACHMENT_EXT, extOf } from './attachment-allowlist.js';
package/dist/index.js CHANGED
Binary file
@@ -0,0 +1,49 @@
1
+ /**
2
+ * 官方「自动化任务」入口的开关(宿主 0.2.2-rc.1 源码核实,结论见
3
+ * `docs/design/external/official-schedule-toggle.md`)。
4
+ *
5
+ * 为什么必须借道宿主的插件管理器:官方 slots 没有「隐藏他人条目」的接口,唯一的正路是把
6
+ * `@deepseek-ai/dsh-client-ui-schedule` 这条组合行停用(写 profile 的 `disabled` 覆盖项)。
7
+ * 停用后该行仍留在 loader 的 entry 表里(只是没有 fiber),所以插件清单看得到、也还能再启用。
8
+ *
9
+ * ⚠️ 不写进 inject:`pluginManager` 缺失时整块要能安静降级(决策 17:组合满足不了的依赖会让
10
+ * entry 一直 pending)。
11
+ */
12
+ import type { HostContext, HostLogger } from './host.js';
13
+ /** 官方自动化任务界面所在的包(组合行 id `ui-schedule`,声明在 `@deepseek-ai/dsh-web-app` 的 patch)。 */
14
+ export declare const OFFICIAL_SCHEDULE_PACKAGE = "@deepseek-ai/dsh-client-ui-schedule";
15
+ /** 插件清单行(`pluginManager.listPlugins()` 投影的子集)。 */
16
+ interface PluginRow {
17
+ entryId: string;
18
+ moduleName: string;
19
+ enabled: boolean;
20
+ readOnlyReason?: string;
21
+ }
22
+ /** `ctx.pluginManager` 用到的最小面(TypertRemoteService,宿主 0.2.2-rc.1 `lib/types/index.d.ts:187`)。 */
23
+ export interface PluginManagerFace {
24
+ listPlugins(): Promise<PluginRow[]>;
25
+ setPluginEnabled(id: string, enabled: boolean): Promise<unknown>;
26
+ }
27
+ /**
28
+ * 取宿主插件管理器;缺失 / 面不齐 ⇒ null(调用方降级并只记一条日志)。
29
+ * @param ctx - 宿主上下文。
30
+ */
31
+ export declare function pluginManagerOf(ctx: HostContext): PluginManagerFace | null;
32
+ /**
33
+ * 让官方自动化入口处在 `hidden` 说的状态(幂等:本来就对就一次写都不发)。
34
+ * @param ctx - 宿主上下文(取 `pluginManager`)。
35
+ * @param logger - 宿主 logger(降级/失败原因留痕,别静默)。
36
+ * @param hidden - true = 屏蔽官方入口;false = 放出来。
37
+ * @returns 是否已对齐;false 表示宿主不支持或该行不可寻址。
38
+ */
39
+ export declare function syncOfficialSchedule(ctx: HostContext, logger: HostLogger, hidden: boolean): Promise<boolean>;
40
+ /**
41
+ * 卸载前放回官方入口(只在我们自己设过「屏蔽」时调用)。
42
+ *
43
+ * ⚠️ 不能同步等:卸载正是插件管理器持着 profile 文件锁做 reload 时触发的,此处再调一次
44
+ * `setPluginEnabled` 会去等同一把锁(120s)。故丢一个延后调用出去,等外层操作放锁后再跑。
45
+ * 宿主进程紧接退出时这一枪可能没打出去 —— 兜底是用户在插件页手动把那行打开。
46
+ * @param logger - 宿主 logger。
47
+ */
48
+ export declare function releaseOfficialSchedule(logger: HostLogger): void;
49
+ export {};
@@ -0,0 +1,74 @@
1
+ /** 官方自动化任务界面所在的包(组合行 id `ui-schedule`,声明在 `@deepseek-ai/dsh-web-app` 的 patch)。 */
2
+ export const OFFICIAL_SCHEDULE_PACKAGE = '@deepseek-ai/dsh-client-ui-schedule';
3
+ /**
4
+ * 取宿主插件管理器;缺失 / 面不齐 ⇒ null(调用方降级并只记一条日志)。
5
+ * @param ctx - 宿主上下文。
6
+ */
7
+ export function pluginManagerOf(ctx) {
8
+ const service = ctx.get('pluginManager');
9
+ if (typeof service !== 'object' || service === null)
10
+ return null;
11
+ const face = service;
12
+ if (typeof face.listPlugins !== 'function' || typeof face.setPluginEnabled !== 'function')
13
+ return null;
14
+ return face;
15
+ }
16
+ /** 上次拿到的管理器面:dispose 之后 `ctx.get` 未必还可用,回滚要能用旧引用。 */
17
+ let cached = null;
18
+ /** 找到官方自动化那一行(找不到 = 宿主改版换了包名/行,只记 warn 不抛)。 */
19
+ async function scheduleRow(manager) {
20
+ return (await manager.listPlugins()).find((row) => row.moduleName === OFFICIAL_SCHEDULE_PACKAGE);
21
+ }
22
+ /**
23
+ * 让官方自动化入口处在 `hidden` 说的状态(幂等:本来就对就一次写都不发)。
24
+ * @param ctx - 宿主上下文(取 `pluginManager`)。
25
+ * @param logger - 宿主 logger(降级/失败原因留痕,别静默)。
26
+ * @param hidden - true = 屏蔽官方入口;false = 放出来。
27
+ * @returns 是否已对齐;false 表示宿主不支持或该行不可寻址。
28
+ */
29
+ export async function syncOfficialSchedule(ctx, logger, hidden) {
30
+ const manager = pluginManagerOf(ctx);
31
+ if (manager === null) {
32
+ logger.warn('[官方自动化] 宿主没有 pluginManager 服务,屏蔽开关不生效');
33
+ return false;
34
+ }
35
+ cached = manager;
36
+ const row = await scheduleRow(manager);
37
+ if (row === undefined) {
38
+ logger.warn(`[官方自动化] 插件清单里找不到 ${OFFICIAL_SCHEDULE_PACKAGE},屏蔽开关不生效`);
39
+ return false;
40
+ }
41
+ if (row.readOnlyReason !== undefined) {
42
+ logger.warn(`[官方自动化] 该行不可管理(${row.readOnlyReason}),屏蔽开关不生效`);
43
+ return false;
44
+ }
45
+ if (row.enabled === !hidden)
46
+ return true;
47
+ await manager.setPluginEnabled(row.entryId, !hidden);
48
+ logger.info(`[官方自动化] 已${hidden ? '屏蔽' : '放出'}官方自动化入口(重启或 HMR 后生效)`);
49
+ return true;
50
+ }
51
+ /**
52
+ * 卸载前放回官方入口(只在我们自己设过「屏蔽」时调用)。
53
+ *
54
+ * ⚠️ 不能同步等:卸载正是插件管理器持着 profile 文件锁做 reload 时触发的,此处再调一次
55
+ * `setPluginEnabled` 会去等同一把锁(120s)。故丢一个延后调用出去,等外层操作放锁后再跑。
56
+ * 宿主进程紧接退出时这一枪可能没打出去 —— 兜底是用户在插件页手动把那行打开。
57
+ * @param logger - 宿主 logger。
58
+ */
59
+ export function releaseOfficialSchedule(logger) {
60
+ const manager = cached;
61
+ if (manager === null)
62
+ return;
63
+ setTimeout(() => {
64
+ void (async () => {
65
+ const row = await scheduleRow(manager);
66
+ if (row === undefined || row.enabled || row.readOnlyReason !== undefined)
67
+ return;
68
+ await manager.setPluginEnabled(row.entryId, true);
69
+ logger.info('[官方自动化] 插件卸载,已放回官方自动化入口');
70
+ })().catch((error) => {
71
+ logger.warn(`[官方自动化] 卸载回滚失败:${error instanceof Error ? error.message : String(error)}`);
72
+ });
73
+ }, 0);
74
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-task-dispatch-table",
3
- "version": "0.1.12",
3
+ "version": "0.1.13",
4
4
  "description": "Scheduled task dispatcher: a dsh host plugin that drives recurring agent tasks from a single task table, dispatching each run as an independent dsh session (scheduling itself uses zero model calls)",
5
5
  "icon": "./assets/icon-scheduler.svg",
6
6
  "keywords": [