@shgroup/dsh-serenity-hooks 1.26.5 → 1.26.6

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/dsh.plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "dsh-serenity-hooks",
3
- "version": "1.26.5",
3
+ "version": "1.26.6",
4
4
  "main": "lib/index.js",
5
5
  "description": "宁静号 ACC harness(Native Cordis 插件):真实 DSH 工具 cc_fs/session/acc_msm/eap/neat/cce/handyman/session_rebuild/skiff_admin + 拦截缝机械约束(safe-mode/路径守卫)+ 高级设定面板(双端口网关/账号管理)+ Skiff 认知子集角色(实验性)。适配 DSH 公开版(0.1.0-rc,deepseek-ai/deepseek-harness)。",
6
6
  "engines": {
package/lib/index.js CHANGED
@@ -12322,6 +12322,11 @@ const ASK_CSS = `
12322
12322
  .card .cmeta { opacity: .6; font-size: 12px; margin-top: 2px; }
12323
12323
  .empty { text-align: center; opacity: .7; padding: 24px 0; }
12324
12324
  .ccname { font-weight: 600; color: var(--sp-green); }
12325
+ /* key 门(v1.26.6:选容器前必填) */
12326
+ .keyGate { display: flex; align-items: center; gap: 8px; margin-bottom: 14px; background: rgba(127,127,127,.06); border: 1px solid rgba(127,127,127,.18); border-radius: 10px; padding: 10px 14px; }
12327
+ .keyGate label { font-size: 12px; opacity: .7; white-space: nowrap; }
12328
+ .keyGate input { flex: 1; border: 1px solid rgba(127,127,127,.25); border-radius: 8px; background: transparent; color: inherit; padding: 8px 12px; font-size: 14px; }
12329
+ .keyGate input:focus { outline: none; border-color: var(--sp-green); }
12325
12330
 
12326
12331
  /* ── 聊天布局(v1.26.4 体验升级:参考 ChatGPT/Claude 会话形态)── */
12327
12332
  .chat { display: flex; flex-direction: column; height: 100vh; max-width: 720px; margin: 0 auto; }
@@ -12365,9 +12370,6 @@ const ASK_CSS = `
12365
12370
  .msg .err { padding: 0 4px; }
12366
12371
  /* 输入区 */
12367
12372
  .chatInput { border-top: 1px solid rgba(127,127,127,.18); padding: 10px 16px calc(12px + env(safe-area-inset-bottom)); background: rgba(127,127,127,.04); }
12368
- .chatInput .keyRow { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
12369
- .chatInput .keyRow label { font-size: 12px; opacity: .7; white-space: nowrap; }
12370
- .chatInput .keyRow input { flex: 1; border: 1px solid rgba(127,127,127,.25); border-radius: 8px; background: transparent; color: inherit; padding: 6px 10px; font-size: 13px; }
12371
12373
  .inputRow { display: flex; align-items: flex-end; gap: 8px; }
12372
12374
  .inputRow textarea { flex: 1; border: 1px solid rgba(127,127,127,.25); border-radius: 12px; background: #fff; color: inherit; padding: 10px 12px; font-size: 14px; resize: none; min-height: 44px; max-height: 140px; line-height: 1.5; }
12373
12375
  @media (prefers-color-scheme: dark) { .inputRow textarea { background: #26282c; border-color: #3a3d42; } }
@@ -12376,11 +12378,35 @@ const ASK_CSS = `
12376
12378
  .inputRow .sendBtn:disabled { opacity: .5; cursor: wait; }
12377
12379
  .inputRow .sendBtn:hover:not(:disabled) { background: var(--sp-green-dim); }
12378
12380
  .hint { text-align: center; font-size: 12px; opacity: .55; padding: 20px 0; }
12381
+
12382
+ /* ── 移动端适配(v1.26.6:手机/平板——iOS 防放大 16px / 触控 ≥44px / 100dvh / safe-area)── */
12383
+ @media (max-width: 640px) {
12384
+ main { padding: 20px 16px calc(28px + env(safe-area-inset-bottom)); }
12385
+ .sub { font-size: 14px; margin-bottom: 14px; }
12386
+ .keyGate { flex-wrap: wrap; gap: 6px; }
12387
+ .keyGate input { flex: 1 1 100%; font-size: 16px; padding: 12px 14px; min-height: 48px; } /* 16px 防 iOS 聚焦放大 + 触控 ≥44px */
12388
+ .card { padding: 16px; border-radius: 12px; }
12389
+ .card .cname { font-size: 16px; }
12390
+ .card .cmeta { font-size: 13px; }
12391
+ .chat { height: 100vh; height: 100dvh; } /* dvh:iOS 地址栏收起/展开不跳动 */
12392
+ .chatHead { gap: 8px; padding: 8px 12px calc(8px + env(safe-area-inset-top)); }
12393
+ .chatHead .back { font-size: 14px; padding: 10px 4px; } /* 触控目标 ≥44px */
12394
+ .chatHead .title { font-size: 14px; }
12395
+ .chatHead select { font-size: 16px; padding: 8px 6px; min-height: 44px; } /* 16px 防放大 + 触控 */
12396
+ .chatHead .newBtn { font-size: 14px; padding: 10px 12px; min-height: 44px; }
12397
+ .msgList { padding: 14px 12px calc(20px + env(safe-area-inset-bottom)); gap: 14px; }
12398
+ .msg { max-width: 94%; }
12399
+ .msg .bubble { font-size: 15px; padding: 12px 14px; }
12400
+ .msg .who { font-size: 12px; }
12401
+ .chatInput { padding: 8px 12px calc(10px + env(safe-area-inset-bottom)); }
12402
+ .inputRow textarea { font-size: 16px; padding: 12px 14px; min-height: 48px; } /* 16px 防放大 + 触控 */
12403
+ .inputRow .sendBtn { font-size: 16px; padding: 12px 20px; min-height: 48px; }
12404
+ }
12379
12405
  `;
12380
- /** 容器列表页(v1.26.2):只列已开放容器,点击进入 /c/<name> */
12406
+ /** 容器列表页(v1.26.2 v1.26.6):key 在选容器前填写(v1.26.6 用户拍板:不填 key 不让选容器) */
12381
12407
  function publicAskListPage(cccs) {
12382
12408
  const cards = cccs.map((c) => `
12383
- <a class="card" href="/c/${encodeURIComponent(c.name)}">
12409
+ <a class="card" data-name="${c.name}" href="/c/${encodeURIComponent(c.name)}">
12384
12410
  <div class="cname">${c.name}</div>
12385
12411
  <div class="cmeta">${c.roles.length} 个问答角色 · 点击进入</div>
12386
12412
  </a>`).join("") || "<div class=\"empty\">暂无可问答的认知容器(管理员尚未开放)</div>";
@@ -12388,20 +12414,46 @@ function publicAskListPage(cccs) {
12388
12414
  <html lang="zh">
12389
12415
  <head>
12390
12416
  <meta charset="utf-8">
12391
- <meta name="viewport" content="width=device-width, initial-scale=1">
12417
+ <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
12392
12418
  <title>Serenity Public Ask</title>
12393
12419
  <style>${ASK_CSS}</style>
12394
12420
  </head>
12395
12421
  <body>
12396
12422
  <main>
12397
12423
  <h1>Serenity Public Ask</h1>
12398
- <div class="sub">选择认知容器开始提问(访问需 key,key 由管理员提供)</div>
12399
- ${cards}
12424
+ <div class="sub">先填写访问 key,再选择认知容器开始提问</div>
12425
+ <div class="keyGate">
12426
+ <label for="gateKey">访问 Key</label>
12427
+ <input id="gateKey" type="password" placeholder="请输入访问 key(仅本次浏览器记忆)" autocomplete="off" autocapitalize="none" enterkeyhint="done">
12428
+ </div>
12429
+ <div id="cards">${cards}</div>
12400
12430
  </main>
12431
+ <script>
12432
+ const KEY_STORE = 'serenity-public-ask-key'
12433
+ const gateKey = document.getElementById('gateKey')
12434
+ const cardList = document.getElementById('cards')
12435
+ // 容器卡片(key 未填时禁用——v1.26.6 用户拍板:key 在选容器前填写)
12436
+ function applyGate() {
12437
+ const ok = gateKey.value.trim().length > 0
12438
+ for (const card of cardList.querySelectorAll('a.card')) {
12439
+ card.classList.toggle('locked', !ok)
12440
+ card.setAttribute('aria-disabled', ok ? 'false' : 'true')
12441
+ if (!ok) { card.removeAttribute('href'); card.style.pointerEvents = 'none'; card.style.opacity = '.4' }
12442
+ else { card.setAttribute('href', '/c/' + encodeURIComponent(card.dataset.name)); card.style.pointerEvents = ''; card.style.opacity = '' }
12443
+ }
12444
+ }
12445
+ gateKey.addEventListener('input', applyGate)
12446
+ // key 自动从 localStorage 恢复
12447
+ let hasSavedKey = false
12448
+ try { const saved = localStorage.getItem(KEY_STORE); if (saved) { gateKey.value = saved; hasSavedKey = true } } catch {}
12449
+ if (hasSavedKey) gateKey.placeholder = '访问 Key(已记忆,可修改)'
12450
+ applyGate()
12451
+ gateKey.focus()
12452
+ <\/script>
12401
12453
  </body>
12402
12454
  </html>`;
12403
12455
  }
12404
- /** 单容器问答页(v1.26.2→v1.26.4):URL 锁定容器;聊天 UI——消息流 + 连续对话 + key 自动记忆 */
12456
+ /** 单容器问答页(v1.26.2→v1.26.6):URL 锁定容器;聊天 UI——消息流 + 连续对话 + key 从列表页记忆(v1.26.6 用户拍板:对话页不再填 key) */
12405
12457
  function publicAskContainerPage(ccc) {
12406
12458
  const data = JSON.stringify({
12407
12459
  name: ccc.name,
@@ -12412,7 +12464,7 @@ function publicAskContainerPage(ccc) {
12412
12464
  <html lang="zh">
12413
12465
  <head>
12414
12466
  <meta charset="utf-8">
12415
- <meta name="viewport" content="width=device-width, initial-scale=1">
12467
+ <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
12416
12468
  <title>Serenity · ${ccc.name}</title>
12417
12469
  <style>${ASK_CSS}</style>
12418
12470
  </head>
@@ -12429,12 +12481,8 @@ function publicAskContainerPage(ccc) {
12429
12481
  <div id="msgs" class="msgList"></div>
12430
12482
 
12431
12483
  <div class="chatInput">
12432
- <div class="keyRow" id="keyRow">
12433
- <label for="key">访问 Key</label>
12434
- <input id="key" type="password" placeholder="请输入访问 key(自动记忆)" autocomplete="off">
12435
- </div>
12436
12484
  <div class="inputRow">
12437
- <textarea id="q" placeholder="向 ${ccc.name} 提问…(Enter 发送,Shift+Enter 换行)" rows="1"></textarea>
12485
+ <textarea id="q" placeholder="向 ${ccc.name} 提问…(Enter 发送,Shift+Enter 换行)" rows="1" enterkeyhint="send" autocapitalize="sentences"></textarea>
12438
12486
  <button id="ask" class="sendBtn">发送</button>
12439
12487
  </div>
12440
12488
  </div>
@@ -12443,22 +12491,19 @@ function publicAskContainerPage(ccc) {
12443
12491
  <script>
12444
12492
  const CCC = JSON.parse(document.getElementById('ask-data').textContent)
12445
12493
  const KEY_STORE = 'serenity-public-ask-key'
12446
- const keyInput = document.getElementById('key')
12447
12494
  const roleSel = document.getElementById('role')
12448
12495
  const btn = document.getElementById('ask')
12449
12496
  const msgs = document.getElementById('msgs')
12450
12497
  const qInput = document.getElementById('q')
12451
- const keyRow = document.getElementById('keyRow')
12452
12498
  let sessionId = ''
12453
12499
  let busy = false
12454
12500
 
12455
12501
  // 角色下拉
12456
12502
  roleSel.innerHTML = (CCC.roles || []).map((r) => '<option value="' + r + '">' + r + '</option>').join('') || '<option value="">(无角色)</option>'
12457
- // key 自动从 localStorage 恢复(v1.26.5:**常驻可见**——只预填不隐藏,
12458
- // 用户随时可查看/修改 key;saved 时 placeholder 提示已记忆)
12459
- let hasSavedKey = false
12460
- try { const saved = localStorage.getItem(KEY_STORE); if (saved) { keyInput.value = saved; hasSavedKey = true } } catch {}
12461
- if (hasSavedKey) keyInput.placeholder = '访问 Key(已记忆,可修改)'
12503
+ // key localStorage 读取(列表页填写时记忆;对话页不填——v1.26.6 用户拍板)
12504
+ function getStoredKey() {
12505
+ try { return (localStorage.getItem(KEY_STORE) || '').trim() } catch { return '' }
12506
+ }
12462
12507
 
12463
12508
  /** 追加一条消息气泡(role: user|assistant) */
12464
12509
  function addMsg(role, htmlOrText, isHtml) {
@@ -12497,13 +12542,11 @@ function addTyping() {
12497
12542
 
12498
12543
  async function ask() {
12499
12544
  const q = qInput.value.trim()
12500
- const key = keyInput.value.trim()
12545
+ const key = getStoredKey()
12501
12546
  const role = roleSel.value || undefined
12502
12547
  if (!q) return
12503
- if (!key) { keyInput.focus(); return }
12548
+ if (!key) { addMsg('assistant', '⚠️ 未找到访问 key,请先回到 <a href="/">容器列表页</a> 填写 key。', true); return }
12504
12549
  if (busy) return
12505
- // 保存 key(下次自动记忆;v1.26.5:不隐藏 key 行——常驻可见可修改)
12506
- try { localStorage.setItem(KEY_STORE, key) } catch {}
12507
12550
  // 追加用户消息 + 打字指示
12508
12551
  addMsg('user', q, false)
12509
12552
  qInput.value = ''
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shgroup/dsh-serenity-hooks",
3
- "version": "1.26.5",
3
+ "version": "1.26.6",
4
4
  "description": "宁静号 ACC harness — Native Cordis 插件(DeepSeek Harness 运行时)。真实 DSH 工具注册(cc_fs/session/acc_msm 等 9 工具)+ 拦截缝机械约束(safe-mode/路径守卫/会话落盘)+ 系统提示词注入(ACC/CCE/Constraints/SKILL/Session 五块)。适配 DSH 公开版(deepseek-ai/deepseek-harness 0.1.0-rc)。",
5
5
  "license": "MIT",
6
6
  "repository": {