dsh-peak-block 0.1.0 → 0.1.1

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.md CHANGED
@@ -1,4 +1,4 @@
1
- # dsh·梁文峰时间拦截插件
1
+ # dsh·禁止梁文峰
2
2
 
3
3
  在 DeepSeek 官方高峰时段拦截官方 provider 请求,保障安心使用梁文谷。
4
4
 
@@ -33,7 +33,7 @@ dsh plugin --profile web remove dsh-peak-block
33
33
  | 键 | 默认 | 说明 |
34
34
  |---|---|---|
35
35
  | `enabled` | `true` | 总开关 |
36
- | `officialProviders` | 未设(只认 `deepseek-official`) | 视为「官方」的 provider 精确名单,不设用默认判定 |
36
+ | `officialProviders` | 未设,只认 `deepseek-official` | 视为「官方」的 provider 精确名单,不设用默认判定 |
37
37
  | `targetProvider` | 空 | 拦截后切到的目标 provider;留空 = 阻止并提示 |
38
38
  | `peakWindow` | 工作日 9–12、14–18,周末谷 | 峰谷时段窗口,可整体或局部覆盖 |
39
39
 
@@ -52,14 +52,14 @@ plugins:
52
52
 
53
53
  ## 边界
54
54
 
55
- - 只拦对话模型请求:`agent/request` 覆盖 agent loop 的正常对话;compaction 等走 `ctx.llm.stream()` 的路径不拦。
55
+ - 只拦对话模型请求:`agent/request` 覆盖 agent loop 的正常对话;compaction 等走 `ctx.llm.stream` 的路径不拦。
56
56
  - `targetProvider` 必须是 DSH 已注册适配器路由,否则切换后以 `NO_ADAPTER` 失败。
57
57
  - `days` 用 JS `getUTCDay` 序号,1..5 为周一..周五;时区判定纯 UTC+8 数学换算,与系统时区无关。
58
58
 
59
59
  ## 要求与开发
60
60
 
61
- - 是**标准形态的 dsh 主机加客户端双半身插件**:host 在 `agent/request` waterfall 里拦截并切换/阻止,`./client` 在设置面板提供一个独立的「梁文峰拦截」标签页,内含 enabled、targetProvider、officialProviders、peakWindow 与预留转 API 端口的配置骨架。当前配置骨架不写回 host,正式生效待接线。
62
- - 无构建:`lib/index.js` 与 `lib/client.js` 均为源码即产物,改完即用。
61
+ - 是**标准形态的 dsh host 单半身插件**:host 在 `agent/request` waterfall 里拦截并切换/阻止,设置全部经 cordis 配置文件注入,见上方配置表,不提供界面配置 UI。
62
+ - 无构建:`lib/index.js` 为源码即产物,改完即用。
63
63
  - 纯函数 `isPeakBeijing` / `isOfficial` / `decide` 在 `lib/index.js` 导出,冒烟测试:
64
64
 
65
65
  ```powershell
package/cordis.patch.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  # dsh-peak-block bundle patch: inserts this plugin into a profile's layer stack.
2
- # Applied when a profile lists this bundle (or wired by dev_install_package).
2
+ # Applied when a profile lists this bundle or wired by dev_install_package.
3
3
  # targetProvider 留空即「未配置拦截目标」,梁文峰时间拦截到时走「阻止并提示」。
4
4
  - insert:
5
5
  - id: dsh-peak-block
package/lib/index.js CHANGED
@@ -3,14 +3,14 @@
3
3
  // 在「梁文峰时间」,即 DeepSeek 官方高峰时段——北京时间工作日 09:00–12:00、14:00–18:00、周末全天谷价——拦截原本发往官方 provider 的对话请求。
4
4
  // 已配置 targetProvider 则切换路由,未配置则阻止并抛出带文案的错误提示。非高峰时段不拦截,正常走官方。
5
5
  //
6
- // 拦截 seam:agent/request waterfall。它对每次对话模型请求携带冻结的调用配置种子 LlmCallConfig(provider/model/reasoningEffort/temperature/maxTokens/stop)。
7
- // listener 可返回替代 config 切换 provider。要判断请求是否官方必须先调用 next() 拿到 config,故实现为「先取 config 再决策」:切换时返回替代 config,阻止时抛带提示文案的错误。
8
- // compaction 等走 ctx.llm.stream() 直接调用的路径不经此 waterfall,本插件不拦。
6
+ // 拦截 seam:agent/request waterfall。它对每次对话模型请求携带冻结的调用配置种子 LlmCallConfig,含 provider/model/reasoningEffort/temperature/maxTokens/stop。
7
+ // listener 可返回替代 config 切换 provider。要判断请求是否官方必须先调用 next 拿到 config,故实现为「先取 config 再决策」:切换时返回替代 config,阻止时抛带提示文案的错误。
8
+ // compaction 等走 ctx.llm.stream 直接调用的路径不经此 waterfall,本插件不拦。
9
9
 
10
10
  export const name = 'dsh-peak-block'
11
11
  export const inject = []
12
12
 
13
- /** 梁文峰时间默认窗口:工作日 09:00–12:00、14:00–18:00(UTC+8),周末全天谷。 */
13
+ /** 梁文峰时间默认窗口:工作日 09:00–12:00、14:00–18:00,UTC+8,周末全天谷。 */
14
14
  export const DEFAULT_PEAK = {
15
15
  days: [1, 2, 3, 4, 5], // JS getUTCDay:0=周日 … 6=周六,1..5=周一..周五
16
16
  hourRanges: [[9, 12], [14, 18]],
@@ -40,7 +40,7 @@ export function isPeakBeijing(timeMs, peak = DEFAULT_PEAK) {
40
40
  return false
41
41
  }
42
42
 
43
- /** provider 是否视为官方。显式名单用精确匹配;未提供名单用默认判定(仅 deepseek-official)。 */
43
+ /** provider 是否视为官方。显式名单用精确匹配;未提供名单用默认判定,即仅 deepseek-official。 */
44
44
  export function isOfficial(provider, officialProviders) {
45
45
  if (!provider) return false
46
46
  if (Array.isArray(officialProviders)) {
@@ -49,15 +49,15 @@ export function isOfficial(provider, officialProviders) {
49
49
  return defaultIsOfficial(provider)
50
50
  }
51
51
 
52
- /** 阻止时抛出的提示文案(用户可见,随界面失败信息呈现)。 */
52
+ /** 阻止时抛出的提示文案,用户可见,随界面失败信息呈现。 */
53
53
  export const BLOCK_MESSAGE =
54
- '【梁文峰时间拦截 · dsh-peak-block】当前为 DeepSeek 官方高峰时段,且未配置拦截目标(targetProvider),请求已阻止。请为 dsh-peak-block 配置 targetProvider,或将请求留到梁文谷时段再发。'
54
+ '【梁文峰时间拦截 · dsh-peak-block】当前为 DeepSeek 官方高峰时段,且未配置拦截目标 targetProvider,请求已阻止。请为 dsh-peak-block 配置 targetProvider,或将请求留到梁文谷时段再发。'
55
55
 
56
56
  /**
57
- * 纯拦截决策(可单测):返回 { action: 'pass' | 'switch' | 'block', config? }。
58
- * - 非梁文峰时间或非官方 → pass(放行)
59
- * - 梁文峰时间 + 官方 + 有目标 → switch(切 provider 到目标)
60
- * - 梁文峰时间 + 官方 + 无目标 → block(阻止并提示)
57
+ * 纯拦截决策,可单测:返回 { action: 'pass' | 'switch' | 'block', config? }。
58
+ * - 非梁文峰时间或非官方 → pass,放行
59
+ * - 梁文峰时间 + 官方 + 有目标 → switch,切 provider 到目标
60
+ * - 梁文峰时间 + 官方 + 无目标 → block,阻止并提示
61
61
  */
62
62
  export function decide(seed, opts) {
63
63
  if (!isPeakBeijing(opts.timeMs, opts.peakWindow)) return { action: 'pass' }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-peak-block",
3
- "version": "0.1.0",
4
- "description": "梁文峰时间拦截官方 DeepSeek API 请求:北京时间工作日高峰时段 09:00-12:00、14:00-18:00 自动拦截发往官方 provider `deepseek-official` 的模型请求,可切换到第三方中转或预留的本机转 API 端口,未配置则阻止并提示;非高峰不拦、正常走官方,专治高峰掉速与刷屏。标准可安装 dsh 插件,host+client 双半身。",
3
+ "version": "0.1.1",
4
+ "description": "梁文峰时间拦截官方 DeepSeek API 请求:北京时间工作日高峰时段 09:00-12:00、14:00-18:00 自动拦截发往官方 provider `deepseek-official` 的模型请求,可切换到第三方中转或预留的本机转 API 端口,未配置则阻止并提示;非高峰不拦、正常走官方,专治高峰掉速与刷屏。标准可安装 dsh 插件,host 单半身,设置经 cordis 配置文件注入。",
5
5
  "keywords": [
6
6
  "deepseek-harness",
7
7
  "dsh",
@@ -21,26 +21,18 @@
21
21
  "main": "lib/index.js",
22
22
  "exports": {
23
23
  ".": "./lib/index.js",
24
- "./client": "./lib/client.js",
25
24
  "./cordis.patch.yml": "./cordis.patch.yml",
26
25
  "./package.json": "./package.json"
27
26
  },
28
27
  "dsh": {
29
28
  "bundle": {
30
29
  "patch": "./cordis.patch.yml"
31
- },
32
- "client": {
33
- "platform": "web",
34
- "inject": [
35
- "@deepseek-ai/dsh-client-ui-slots"
36
- ]
37
30
  }
38
31
  },
39
32
  "files": [
40
33
  "lib/index.js",
41
- "lib/client.js",
42
34
  "cordis.patch.yml",
43
35
  "docs/"
44
36
  ],
45
37
  "license": "MIT"
46
- }
38
+ }
package/lib/client.js DELETED
@@ -1,191 +0,0 @@
1
- // dsh-peak-block 浏览器半身:设置面板里的一个独立标签页。
2
- // host 侧(lib/index.js)完成真正的拦截与路由切换。本半身提供配置入口的 UI 骨架:
3
- // enabled、targetProvider、officialProviders、peakWindow 与预留的「转 API 端口」。
4
- // 当前仅为界面演示,字段值不写回 host;正式生效需后续接线 host 的配置读写通道。
5
- // 真正的「被拦截且未配置目标」提示,由 host 侧抛出的失败文案随界面失败信息呈现,本半身不重复注入,避免易碎的 UI 依赖。
6
-
7
- window.__ModuleLoader__.load({
8
- id: 'dsh-peak-block',
9
- factory: (require) => {
10
- const module = { exports: {} }
11
- const exports = module.exports
12
-
13
- const React = require('react')
14
-
15
- const plugin = {
16
- name: 'dsh-peak-block',
17
- inject: ['slots'],
18
- apply(ctx) {
19
- const slots = ctx.get && ctx.get('slots')
20
- if (!slots) return
21
-
22
- const DOC = typeof document !== 'undefined' ? document : null
23
- let styleTag = null
24
-
25
- function ensureStyle() {
26
- if (!DOC || styleTag) return
27
- const css = [
28
- '.dshpb-section{display:flex;flex-direction:column;gap:12px;max-width:720px;color:var(--dsw-alias-label-primary)}',
29
- '.dshpb-title{margin:0;font-size:16px;line-height:24px;font-weight:500;color:var(--dsw-alias-label-primary)}',
30
- '.dshpb-intro{margin:0;font-size:14px;line-height:22px;color:var(--dsw-alias-label-tertiary)}',
31
- '.dshpb-notice{margin:0;font-size:12px;line-height:18px;color:var(--dsw-alias-state-warn-label)}',
32
- '.dshpb-card{border:1px solid var(--dsw-alias-border-l2);border-radius:12px;padding:14px 16px;display:flex;flex-direction:column;gap:14px}',
33
- '.dshpb-field{display:flex;flex-direction:column;gap:6px}',
34
- '.dshpb-fieldLabel{font-size:12px;line-height:18px;font-weight:500;color:var(--dsw-alias-label-secondary)}',
35
- '.dshpb-hint{margin:0;font-size:12px;line-height:18px;color:var(--dsw-alias-label-tertiary)}',
36
- '.dshpb-input{box-sizing:border-box;width:100%;height:32px;padding:0 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;font:inherit;font-size:14px;line-height:22px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary)}',
37
- '.dshpb-input:focus{outline:none;border-color:var(--dsw-alias-brand-primary)}',
38
- '.dshpb-input::placeholder{color:var(--dsw-alias-label-dimmed)}',
39
- 'select.dshpb-input{max-width:320px;cursor:pointer}',
40
- '.dshpb-rowInput{max-width:320px}',
41
- '.dshpb-actions{display:flex;justify-content:flex-end;gap:8px}',
42
- '.dshpb-button{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;gap:4px;height:36px;padding:0 14px;border:none;border-radius:18px;font:inherit;font-size:14px;line-height:22px;cursor:pointer}',
43
- '.dshpb-buttonPrimary{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}',
44
- '.dshpb-buttonPrimary:hover{background:var(--dsw-alias-button-primary-hover)}',
45
- '.dshpb-switch{display:inline-flex;align-items:center;gap:8px;cursor:pointer;font-size:14px;line-height:22px}',
46
- ].join('')
47
- const tag = DOC.createElement('style')
48
- tag.textContent = css
49
- DOC.head.appendChild(tag)
50
- styleTag = tag
51
- }
52
-
53
- const TARGET_TYPES = {
54
- none: '未配置(高峰阻止并提示)',
55
- proxy: '第三方中转路由',
56
- port: '转 API 端口',
57
- }
58
-
59
- function Section() {
60
- const [enabled, setEnabled] = React.useState(true)
61
- const [targetType, setTargetType] = React.useState('none')
62
- const [proxyRoute, setProxyRoute] = React.useState('opencode-go')
63
- const [apiPort, setApiPort] = React.useState('127.0.0.1:8080')
64
- const [official, setOfficial] = React.useState('deepseek-official')
65
- const [savedHint, setSavedHint] = React.useState('')
66
-
67
- function onSave() {
68
- setSavedHint('已保存到界面状态,尚未写回 host,正式生效需接线后端。')
69
- }
70
-
71
- return React.createElement(
72
- 'div',
73
- { className: 'dshpb-section', role: 'region', 'aria-label': '梁文峰拦截设置' },
74
- React.createElement('h2', { className: 'dshpb-title' }, '梁文峰时间拦截'),
75
- React.createElement('p', { className: 'dshpb-intro' }, '在 DeepSeek 官方高峰时段拦截官方 provider 请求,可切换到第三方中转或本机转 API 端口。'),
76
- React.createElement('p', { className: 'dshpb-notice' }, '当前为配置界面骨架,改动不写回 host,正式生效需后续接线。'),
77
- React.createElement(
78
- 'div',
79
- { className: 'dshpb-card' },
80
- React.createElement(
81
- 'label',
82
- { className: 'dshpb-switch' },
83
- React.createElement('input', {
84
- type: 'checkbox',
85
- checked: enabled,
86
- onChange: function (e) { setEnabled(e.target.checked) },
87
- }),
88
- '启用拦截'
89
- ),
90
- React.createElement(
91
- 'div',
92
- { className: 'dshpb-field' },
93
- React.createElement('label', { className: 'dshpb-fieldLabel', htmlFor: 'dshpb-target' }, '拦截目标 targetProvider'),
94
- React.createElement(
95
- 'select',
96
- {
97
- id: 'dshpb-target',
98
- className: 'dshpb-input',
99
- value: targetType,
100
- onChange: function (e) { setTargetType(e.target.value) },
101
- },
102
- React.createElement('option', { value: 'none' }, TARGET_TYPES.none),
103
- React.createElement('option', { value: 'proxy' }, TARGET_TYPES.proxy),
104
- React.createElement('option', { value: 'port' }, TARGET_TYPES.port)
105
- ),
106
- targetType === 'proxy' &&
107
- React.createElement('input', {
108
- className: 'dshpb-input dshpb-rowInput',
109
- value: proxyRoute,
110
- placeholder: '如 opencode-go',
111
- 'aria-label': '第三方中转路由',
112
- onChange: function (e) { setProxyRoute(e.target.value) },
113
- }),
114
- targetType === 'port' &&
115
- React.createElement(
116
- 'div',
117
- { className: 'dshpb-field' },
118
- React.createElement('label', { className: 'dshpb-fieldLabel', htmlFor: 'dshpb-port' }, '转 API 端口'),
119
- React.createElement('input', {
120
- id: 'dshpb-port',
121
- className: 'dshpb-input dshpb-rowInput',
122
- value: apiPort,
123
- placeholder: '127.0.0.1:8080',
124
- onChange: function (e) { setApiPort(e.target.value) },
125
- }),
126
- React.createElement('p', { className: 'dshpb-hint' }, '预留:把被拦请求转发到本机 OpenAI 兼容端口。')
127
- )
128
- ),
129
- React.createElement(
130
- 'div',
131
- { className: 'dshpb-field' },
132
- React.createElement('label', { className: 'dshpb-fieldLabel', htmlFor: 'dshpb-official' }, '官方判定 provider 名单(逗号分隔)'),
133
- React.createElement('input', {
134
- id: 'dshpb-official',
135
- className: 'dshpb-input dshpb-rowInput',
136
- value: official,
137
- onChange: function (e) { setOfficial(e.target.value) },
138
- })
139
- ),
140
- React.createElement(
141
- 'div',
142
- { className: 'dshpb-field' },
143
- React.createElement('span', { className: 'dshpb-fieldLabel' }, '高峰时段'),
144
- React.createElement('p', { className: 'dshpb-hint' }, '北京时间工作日 09:00–12:00、14:00–18:00,周末全天谷价。')
145
- ),
146
- React.createElement(
147
- 'div',
148
- { className: 'dshpb-actions' },
149
- React.createElement(
150
- 'button',
151
- { type: 'button', className: 'dshpb-button dshpb-buttonPrimary', onClick: onSave },
152
- '保存(演示)'
153
- )
154
- ),
155
- savedHint !== '' &&
156
- React.createElement('p', { className: 'dshpb-hint' }, savedHint)
157
- )
158
- )
159
- }
160
-
161
- slots.inject('settings.section', function () {
162
- return slots.register(
163
- {
164
- name: 'settings.section',
165
- id: 'peak-block',
166
- order: 90,
167
- label: '梁文峰拦截',
168
- },
169
- () => React.createElement(Section)
170
- )
171
- })
172
-
173
- ctx.effect(function () {
174
- ensureStyle()
175
- return function () {
176
- if (styleTag && styleTag.parentNode) styleTag.parentNode.removeChild(styleTag)
177
- styleTag = null
178
- }
179
- })
180
- },
181
- }
182
-
183
- exports.default = plugin
184
- exports.name = plugin.name
185
- exports.inject = plugin.inject
186
- exports.apply = plugin.apply
187
-
188
- Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' })
189
- return module.exports
190
- },
191
- })