@shgroup/dsh-serenity-hooks 1.28.2 → 1.29.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/dsh.plugin.json +1 -1
- package/lib/client.js +281 -76
- package/lib/index.js +125 -23
- package/lib/msm-ops.d.ts +1 -1
- package/lib/seams/keeper.d.ts +1 -1
- package/lib/seams/system-prompt.d.ts +4 -1
- package/lib/session-cleanup-PahSNvjI.js +113 -0
- package/lib/session-cleanup.d.ts +60 -0
- package/lib/trajectory-assistant.d.ts +54 -0
- package/package.json +1 -1
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-serenity-hooks",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.29.0",
|
|
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/client.js
CHANGED
|
@@ -4587,7 +4587,7 @@ Instruction-following style:
|
|
|
4587
4587
|
}
|
|
4588
4588
|
//#endregion
|
|
4589
4589
|
//#region \0sp-css:/home/yh/home/home-serenity/AI_LAB/dsh-serenity-plugin/hooks/dsh-serenity-hooks/src/client/SettingsSection
|
|
4590
|
-
const css = "/* SettingsSection — dsh 原生设置面板 serenity-hooks 简单配置页\n v1.21.1 看齐 dsh 自身:官方 settings 设计语言——\n section > title + intro + group(groupTitle) + rowCard 行卡;\n 全部 --dsw-alias-* token(与 ui-settings-models 同词汇表)。 */\n\n/* 页面容器(官方 .section:flex column gap 12) */\n.ss-section {\n display: flex;\n flex-direction: column;\n gap: 14px;\n max-width: 720px;\n color: var(--dsw-alias-label-primary);\n}\n\n/* 页面标题(官方 .title:16px/24 500) */\n.ss-title {\n margin: 0;\n font-size: 16px;\n line-height: 24px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n/* 页面说明(官方 .intro:14px/22 tertiary) */\n.ss-intro {\n margin: 0;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* 分组(多级标题:分组标题 + 行卡列表) */\n.ss-group {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n/* 分组标题(二级:12px/18 500 secondary——官方 fieldLabel 风格) */\n.ss-groupTitle {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n font-weight: 600;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* 行卡列表(官方 .rows:无 marker,gap 8) */\n.ss-rows {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n/* 行卡(官方 .rowCard:border-l2 r12 padding 12/14) */\n.ss-rowCard {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n padding: 12px 14px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n}\n\n/* 行卡文本(标题 + 说明 左列) */\n.ss-rowText {\n display: flex;\n flex-direction: column;\n gap: 3px;\n min-width: 0;\n flex: 1;\n}\n\n/* 行卡标题(官方 .rowName:14px/22 500) */\n.ss-rowName {\n font-size: 14px;\n line-height: 22px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n/* 行卡说明(12px/18 tertiary;v1.27.5 紧凑化:默认单行截断,hover title 看全文) */\n.ss-rowDesc {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n/* 行卡控件(右置) */\n.ss-rowControl {\n flex: none;\n display: flex;\n align-items: center;\n}\n\n/* 开关(官方 token 的自绘 toggle:track 22px,thumb 16px) */\n.ss-switch {\n position: relative;\n flex: none;\n width: 40px;\n height: 22px;\n cursor: pointer;\n}\n\n.ss-switch input {\n position: absolute;\n opacity: 0;\n width: 100%;\n height: 100%;\n margin: 0;\n cursor: pointer;\n}\n\n.ss-switchTrack {\n position: absolute;\n inset: 0;\n border-radius: 11px;\n background: var(--dsw-alias-border-l3);\n transition: background var(--ds-transition-duration-fast, 0.15s) var(--ds-ease-in-out, ease);\n}\n\n.ss-switchTrack::after {\n content: '';\n position: absolute;\n top: 3px;\n left: 3px;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: var(--dsw-alias-label-primary-foreground);\n transition: transform var(--ds-transition-duration-fast, 0.15s) var(--ds-ease-in-out, ease);\n}\n\n.ss-switch input:checked + .ss-switchTrack {\n background: var(--dsw-alias-brand-primary);\n}\n\n.ss-switch input:checked + .ss-switchTrack::after {\n transform: translateX(18px);\n}\n\n.ss-switch input:disabled + .ss-switchTrack {\n opacity: 0.4;\n cursor: default;\n}\n\n/* 阈值行(滑块 + 值) */\n.ss-threshold {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.ss-threshold input[type='range'] {\n width: 160px;\n}\n\n/* Skiff 调试端口输入(number;关闭时跟随 disabled 半透明) */\n.ss-portInput {\n width: 96px;\n padding: 6px 8px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n font-variant-numeric: tabular-nums;\n text-align: right;\n}\n\n.ss-portInput:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n.ss-value {\n min-width: 40px;\n font-variant-numeric: tabular-nums;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n text-align: right;\n}\n\n/* 自主轨迹「立即唤起」按钮(v1.26.14 调试语义;官方 button 语言:primary 弱化) */\n.ss-wakeBtn {\n flex: none;\n padding: 5px 12px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.12));\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n cursor: pointer;\n transition: opacity var(--ds-transition-duration-fast, 0.15s) ease;\n}\n\n.ss-wakeBtn:hover:not(:disabled) {\n border-color: var(--dsw-alias-state-success-primary, #22c55e);\n color: var(--dsw-alias-state-success-primary, #22c55e);\n}\n\n.ss-wakeBtn:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n/* 底部帮助行 */\n.ss-hint {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* 降级提示 */\n.ss-degrade {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-warn-label);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* ── v1.27.5 紧凑化:折叠组(details/summary)── */\n.ss-collapse {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n overflow: hidden;\n}\n\n.ss-collapseHead {\n display: flex;\n align-items: baseline;\n gap: 10px;\n padding: 10px 14px;\n cursor: pointer;\n list-style: none;\n user-select: none;\n}\n\n.ss-collapseHead::-webkit-details-marker {\n display: none;\n}\n\n.ss-collapseHead::before {\n content: '▸';\n flex: none;\n font-size: 11px;\n color: var(--dsw-alias-label-tertiary);\n transition: transform 0.15s ease;\n}\n\n.ss-collapse[open] > .ss-collapseHead::before {\n transform: rotate(90deg);\n}\n\n.ss-collapseHead:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(128, 128, 128, 0.06));\n}\n\n.ss-collapseTitle {\n font-size: 13px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n.ss-collapseDesc {\n font-size: 12px;\n color: var(--dsw-alias-label-tertiary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n min-width: 0;\n}\n\n.ss-collapseBody {\n padding: 10px 14px 14px;\n border-top: 1px solid var(--dsw-alias-border-l1);\n}\n\n/* ── v1.27.5 紧凑化:只读定义列表(dl/dt/dd 2 列网格)── */\n.ss-defList {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 6px 20px;\n margin: 0;\n width: 100%;\n min-width: 0;\n}\n\n.ss-defItem {\n display: flex;\n flex-direction: column;\n gap: 1px;\n min-width: 0;\n}\n\n.ss-defTerm {\n font-size: 11px;\n line-height: 16px;\n font-weight: 500;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n color: var(--dsw-alias-label-tertiary);\n}\n\n.ss-defValue {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-primary);\n word-break: break-word;\n overflow-wrap: anywhere;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n/* ── v1.27.5 紧凑化:开关 + 端口内联行 ── */\n.ss-switchRow {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n/* ── v1.27.6 「?」帮助浮层(hover/焦点显示三行以上严谨说明)── */\n.ss-help {\n position: relative;\n display: inline-flex;\n align-items: center;\n margin-top: 2px;\n}\n\n.ss-helpMark {\n flex: none;\n width: 16px;\n height: 16px;\n padding: 0;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 50%;\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.12));\n color: var(--dsw-alias-label-tertiary);\n font-size: 10px;\n line-height: 1;\n font-weight: 600;\n cursor: help;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n transition: border-color 0.15s ease, color 0.15s ease;\n}\n\n.ss-helpMark:hover,\n.ss-helpMark:focus-visible {\n border-color: var(--dsw-alias-state-success-primary, #22c55e);\n color: var(--dsw-alias-state-success-primary, #22c55e);\n outline: none;\n}\n\n.ss-helpTip {\n position: absolute;\n left: 0;\n top: calc(100% + 6px);\n z-index: 30;\n width: 300px;\n max-width: 60vw;\n padding: 10px 12px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 10px;\n background: var(--dsw-alias-bg-overlay);\n box-shadow: 0 6px 24px rgba(0, 0, 0, 0.28);\n font-size: 12px;\n line-height: 19px;\n font-weight: 400;\n color: var(--dsw-alias-label-primary);\n white-space: pre-line;\n word-break: break-word;\n opacity: 0;\n pointer-events: none;\n transform: translateY(-4px);\n transition: opacity 0.15s ease, transform 0.15s ease;\n}\n\n.ss-help:hover .ss-helpTip,\n.ss-helpMark:focus-visible + .ss-helpTip {\n opacity: 1;\n pointer-events: auto;\n transform: translateY(0);\n}\n\n/* 折叠组内帮助浮层定位修正(左侧行卡不会溢出面板) */\n.ss-rowCard .ss-helpTip {\n left: 0;\n}\n\n/* ── 微信桥(F4c-3,v1.27.0 实验性)── */\n\n/* CCC 选择器(下拉) */\n.ss-select {\n max-width: 280px;\n padding: 6px 8px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n/* 扫码绑定按钮(复用 wakeBtn 语言) */\n.ss-loginBtn {\n flex: none;\n padding: 5px 12px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.12));\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n cursor: pointer;\n transition: opacity var(--ds-transition-duration-fast, 0.15s) ease;\n}\n\n.ss-loginBtn:hover:not(:disabled) {\n border-color: var(--dsw-alias-state-success-primary, #22c55e);\n color: var(--dsw-alias-state-success-primary, #22c55e);\n}\n\n.ss-loginBtn:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n/* 移除账号按钮(危险语义:红边框) */\n.ss-removeBtn {\n flex: none;\n padding: 5px 12px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.12));\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n cursor: pointer;\n transition: opacity var(--ds-transition-duration-fast, 0.15s) ease;\n}\n\n.ss-removeBtn:hover:not(:disabled) {\n border-color: var(--dsw-alias-state-error-primary, #ef4444);\n color: var(--dsw-alias-state-error-primary, #ef4444);\n}\n\n/* 二维码展示行 */\n.ss-qrRow {\n align-items: center;\n}\n\n.ss-qrSvg {\n flex: none;\n width: 120px; /* v1.27.5 紧凑化:160 → 120 */\n height: 120px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: #fff; /* 二维码需要白底才能被微信扫出 */\n padding: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.ss-qrSvg svg {\n width: 100%;\n height: 100%;\n}\n\n/* 路由表 JSON 编辑框 */\n.ss-routesEditor {\n width: 100%;\n box-sizing: border-box;\n margin-top: 6px;\n padding: 8px 10px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n line-height: 18px;\n font-family: var(--ds-font-family-code);\n resize: vertical;\n}\n";
|
|
4590
|
+
const css = "/* SettingsSection — dsh 原生设置面板 serenity-hooks 简单配置页\n v1.21.1 看齐 dsh 自身:官方 settings 设计语言——\n section > title + intro + group(groupTitle) + rowCard 行卡;\n 全部 --dsw-alias-* token(与 ui-settings-models 同词汇表)。 */\n\n/* 页面容器(官方 .section:flex column gap 12) */\n.ss-section {\n display: flex;\n flex-direction: column;\n gap: 14px;\n max-width: 720px;\n color: var(--dsw-alias-label-primary);\n}\n\n/* 页面标题(官方 .title:16px/24 500) */\n.ss-title {\n margin: 0;\n font-size: 16px;\n line-height: 24px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n/* 页面说明(官方 .intro:14px/22 tertiary) */\n.ss-intro {\n margin: 0;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* 分组(多级标题:分组标题 + 行卡列表) */\n.ss-group {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n/* 分组标题(二级:12px/18 500 secondary——官方 fieldLabel 风格) */\n.ss-groupTitle {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n font-weight: 600;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* 行卡列表(官方 .rows:无 marker,gap 8) */\n.ss-rows {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n/* 行卡(官方 .rowCard:border-l2 r12 padding 12/14) */\n.ss-rowCard {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n padding: 12px 14px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n}\n\n/* ── v1.29 需求②:可展开行(整行点击 → 行内详设)── */\n.ss-expandable {\n flex-wrap: wrap; /* detail 换行占满整行 */\n cursor: default;\n}\n.ss-expandable .ss-rowText {\n cursor: pointer;\n}\n.ss-expandable .ss-rowText:hover .ss-rowName {\n color: var(--dsw-alias-state-success-primary, #22c55e);\n}\n.ss-expanded {\n border-color: var(--dsw-alias-state-success-primary, #22c55e);\n}\n.ss-expandMark {\n display: inline-block;\n margin-left: 6px;\n font-size: 10px;\n color: var(--dsw-alias-label-tertiary);\n transition: transform 0.15s ease;\n}\n.ss-expanded .ss-expandMark {\n transform: rotate(90deg);\n}\n.ss-rowDetail {\n flex-basis: 100%;\n width: 100%;\n border-top: 1px solid var(--dsw-alias-border-l2);\n margin-top: 10px;\n padding-top: 12px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n min-width: 0;\n}\n.ss-detailStack {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n.ss-detailIntro {\n margin: 0;\n font-size: 12px;\n line-height: 19px;\n color: var(--dsw-alias-label-secondary);\n white-space: pre-line;\n word-break: break-word;\n overflow-wrap: anywhere;\n padding: 8px 10px;\n border-radius: 8px;\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.06));\n}\n\n/* 行卡文本(标题 + 说明 左列) */\n.ss-rowText {\n display: flex;\n flex-direction: column;\n gap: 3px;\n min-width: 0;\n flex: 1;\n}\n\n/* 行卡标题(官方 .rowName:14px/22 500) */\n.ss-rowName {\n font-size: 14px;\n line-height: 22px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n/* 行卡说明(12px/18 tertiary;v1.27.5 紧凑化:默认单行截断,hover title 看全文) */\n.ss-rowDesc {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n/* 行卡控件(右置) */\n.ss-rowControl {\n flex: none;\n display: flex;\n align-items: center;\n}\n\n/* 开关(官方 token 的自绘 toggle:track 22px,thumb 16px) */\n.ss-switch {\n position: relative;\n flex: none;\n width: 40px;\n height: 22px;\n cursor: pointer;\n}\n\n.ss-switch input {\n position: absolute;\n opacity: 0;\n width: 100%;\n height: 100%;\n margin: 0;\n cursor: pointer;\n}\n\n.ss-switchTrack {\n position: absolute;\n inset: 0;\n border-radius: 11px;\n background: var(--dsw-alias-border-l3);\n transition: background var(--ds-transition-duration-fast, 0.15s) var(--ds-ease-in-out, ease);\n}\n\n.ss-switchTrack::after {\n content: '';\n position: absolute;\n top: 3px;\n left: 3px;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: var(--dsw-alias-label-primary-foreground);\n transition: transform var(--ds-transition-duration-fast, 0.15s) var(--ds-ease-in-out, ease);\n}\n\n.ss-switch input:checked + .ss-switchTrack {\n background: var(--dsw-alias-brand-primary);\n}\n\n.ss-switch input:checked + .ss-switchTrack::after {\n transform: translateX(18px);\n}\n\n.ss-switch input:disabled + .ss-switchTrack {\n opacity: 0.4;\n cursor: default;\n}\n\n/* 阈值行(滑块 + 值) */\n.ss-threshold {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.ss-threshold input[type='range'] {\n width: 160px;\n}\n\n/* Skiff 调试端口输入(number;关闭时跟随 disabled 半透明) */\n.ss-portInput {\n width: 96px;\n padding: 6px 8px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n font-variant-numeric: tabular-nums;\n text-align: right;\n}\n\n.ss-portInput:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n.ss-value {\n min-width: 40px;\n font-variant-numeric: tabular-nums;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n text-align: right;\n}\n\n/* 自主轨迹「立即唤起」按钮(v1.26.14 调试语义;官方 button 语言:primary 弱化) */\n.ss-wakeBtn {\n flex: none;\n padding: 5px 12px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.12));\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n cursor: pointer;\n transition: opacity var(--ds-transition-duration-fast, 0.15s) ease;\n}\n\n.ss-wakeBtn:hover:not(:disabled) {\n border-color: var(--dsw-alias-state-success-primary, #22c55e);\n color: var(--dsw-alias-state-success-primary, #22c55e);\n}\n\n.ss-wakeBtn:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n/* 底部帮助行 */\n.ss-hint {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* 降级提示 */\n.ss-degrade {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-warn-label);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* 错误提示(v1.29 会话清理等) */\n.ss-error {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-error-primary, #ef4444);\n background: rgba(239, 68, 68, 0.08);\n border-radius: 8px;\n padding: 8px 10px;\n white-space: pre-line;\n word-break: break-word;\n}\n\n/* ── v1.27.5 紧凑化:折叠组(details/summary)── */\n.ss-collapse {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n overflow: hidden;\n}\n\n.ss-collapseHead {\n display: flex;\n align-items: baseline;\n gap: 10px;\n padding: 10px 14px;\n cursor: pointer;\n list-style: none;\n user-select: none;\n}\n\n.ss-collapseHead::-webkit-details-marker {\n display: none;\n}\n\n.ss-collapseHead::before {\n content: '▸';\n flex: none;\n font-size: 11px;\n color: var(--dsw-alias-label-tertiary);\n transition: transform 0.15s ease;\n}\n\n.ss-collapse[open] > .ss-collapseHead::before {\n transform: rotate(90deg);\n}\n\n.ss-collapseHead:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(128, 128, 128, 0.06));\n}\n\n.ss-collapseTitle {\n font-size: 13px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n.ss-collapseDesc {\n font-size: 12px;\n color: var(--dsw-alias-label-tertiary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n min-width: 0;\n}\n\n.ss-collapseBody {\n padding: 10px 14px 14px;\n border-top: 1px solid var(--dsw-alias-border-l1);\n}\n\n/* ── v1.27.5 紧凑化:只读定义列表(dl/dt/dd 2 列网格)── */\n.ss-defList {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 6px 20px;\n margin: 0;\n width: 100%;\n min-width: 0;\n}\n\n.ss-defItem {\n display: flex;\n flex-direction: column;\n gap: 1px;\n min-width: 0;\n}\n\n.ss-defTerm {\n font-size: 11px;\n line-height: 16px;\n font-weight: 500;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n color: var(--dsw-alias-label-tertiary);\n}\n\n.ss-defValue {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-primary);\n word-break: break-word;\n overflow-wrap: anywhere;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n/* ── v1.27.5 紧凑化:开关 + 端口内联行 ── */\n.ss-switchRow {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n/* ── v1.27.6 「?」帮助浮层(hover/焦点显示三行以上严谨说明)── */\n.ss-help {\n position: relative;\n display: inline-flex;\n align-items: center;\n margin-top: 2px;\n}\n\n.ss-helpMark {\n flex: none;\n width: 16px;\n height: 16px;\n padding: 0;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 50%;\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.12));\n color: var(--dsw-alias-label-tertiary);\n font-size: 10px;\n line-height: 1;\n font-weight: 600;\n cursor: help;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n transition: border-color 0.15s ease, color 0.15s ease;\n}\n\n.ss-helpMark:hover,\n.ss-helpMark:focus-visible {\n border-color: var(--dsw-alias-state-success-primary, #22c55e);\n color: var(--dsw-alias-state-success-primary, #22c55e);\n outline: none;\n}\n\n.ss-helpTip {\n position: absolute;\n left: 0;\n top: calc(100% + 6px);\n z-index: 30;\n width: 300px;\n max-width: 60vw;\n padding: 10px 12px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 10px;\n background: var(--dsw-alias-bg-overlay);\n box-shadow: 0 6px 24px rgba(0, 0, 0, 0.28);\n font-size: 12px;\n line-height: 19px;\n font-weight: 400;\n color: var(--dsw-alias-label-primary);\n white-space: pre-line;\n word-break: break-word;\n opacity: 0;\n pointer-events: none;\n transform: translateY(-4px);\n transition: opacity 0.15s ease, transform 0.15s ease;\n}\n\n.ss-help:hover .ss-helpTip,\n.ss-helpMark:focus-visible + .ss-helpTip {\n opacity: 1;\n pointer-events: auto;\n transform: translateY(0);\n}\n\n/* 折叠组内帮助浮层定位修正(左侧行卡不会溢出面板) */\n.ss-rowCard .ss-helpTip {\n left: 0;\n}\n\n/* ── 微信桥(F4c-3,v1.27.0 实验性)── */\n\n/* CCC 选择器(下拉) */\n.ss-select {\n max-width: 280px;\n padding: 6px 8px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n/* 扫码绑定按钮(复用 wakeBtn 语言) */\n.ss-loginBtn {\n flex: none;\n padding: 5px 12px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.12));\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n cursor: pointer;\n transition: opacity var(--ds-transition-duration-fast, 0.15s) ease;\n}\n\n.ss-loginBtn:hover:not(:disabled) {\n border-color: var(--dsw-alias-state-success-primary, #22c55e);\n color: var(--dsw-alias-state-success-primary, #22c55e);\n}\n\n.ss-loginBtn:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n/* 移除账号按钮(危险语义:红边框) */\n.ss-removeBtn {\n flex: none;\n padding: 5px 12px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.12));\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n cursor: pointer;\n transition: opacity var(--ds-transition-duration-fast, 0.15s) ease;\n}\n\n.ss-removeBtn:hover:not(:disabled) {\n border-color: var(--dsw-alias-state-error-primary, #ef4444);\n color: var(--dsw-alias-state-error-primary, #ef4444);\n}\n\n/* 二维码展示行 */\n.ss-qrRow {\n align-items: center;\n}\n\n.ss-qrSvg {\n flex: none;\n width: 120px; /* v1.27.5 紧凑化:160 → 120 */\n height: 120px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: #fff; /* 二维码需要白底才能被微信扫出 */\n padding: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.ss-qrSvg svg {\n width: 100%;\n height: 100%;\n}\n\n/* 路由表 JSON 编辑框 */\n.ss-routesEditor {\n width: 100%;\n box-sizing: border-box;\n margin-top: 6px;\n padding: 8px 10px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n line-height: 18px;\n font-family: var(--ds-font-family-code);\n resize: vertical;\n}\n";
|
|
4591
4591
|
if (typeof document !== "undefined" && document.querySelector("style[data-sp-css=\"SettingsSection\"]") === null) {
|
|
4592
4592
|
const tag = document.createElement("style");
|
|
4593
4593
|
tag.setAttribute("data-sp-css", "SettingsSection");
|
|
@@ -4612,39 +4612,70 @@ Instruction-following style:
|
|
|
4612
4612
|
});
|
|
4613
4613
|
}
|
|
4614
4614
|
/** 一个配置行卡(官方 rowCard:标题+说明 左列 / 控件右置)
|
|
4615
|
-
* help:可选——desc 下方渲染「?」帮助浮层(hover/焦点显示三行以上严谨说明)
|
|
4615
|
+
* help:可选——desc 下方渲染「?」帮助浮层(hover/焦点显示三行以上严谨说明)
|
|
4616
|
+
* expandable:可选——整行点击展开 detail 内联详设(需求②:开关与详设合一)。
|
|
4617
|
+
* 点击行(标题/desc 区)toggle 展开态;detail 渲染在行内下方(含 help 内容 +
|
|
4618
|
+
* 该功能全部配置项/重型编辑器)。展开时行头右置 ▾ 指示。 */
|
|
4616
4619
|
function RowCard(props) {
|
|
4617
|
-
const { title, desc, control, help } = props;
|
|
4620
|
+
const { title, desc, control, help, expandable, detail } = props;
|
|
4621
|
+
const isControlled = props.open !== void 0;
|
|
4622
|
+
const [selfOpen, setSelfOpen] = (0, react.useState)(false);
|
|
4623
|
+
const open = isControlled ? !!props.open : selfOpen;
|
|
4624
|
+
const toggle = () => {
|
|
4625
|
+
if (!expandable) return;
|
|
4626
|
+
if (isControlled) props.onToggle?.(!open);
|
|
4627
|
+
else setSelfOpen(!open);
|
|
4628
|
+
};
|
|
4618
4629
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4619
|
-
className:
|
|
4620
|
-
children: [
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4630
|
+
className: `ss-rowCard${expandable ? " ss-expandable" : ""}${expandable && open ? " ss-expanded" : ""}`,
|
|
4631
|
+
children: [
|
|
4632
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4633
|
+
className: "ss-rowText",
|
|
4634
|
+
role: expandable ? "button" : void 0,
|
|
4635
|
+
tabIndex: expandable ? 0 : void 0,
|
|
4636
|
+
onClick: toggle,
|
|
4637
|
+
onKeyDown: (e) => {
|
|
4638
|
+
if (expandable && (e.key === "Enter" || e.key === " ")) {
|
|
4639
|
+
e.preventDefault();
|
|
4640
|
+
toggle();
|
|
4641
|
+
}
|
|
4642
|
+
},
|
|
4643
|
+
children: [
|
|
4644
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4645
|
+
className: "ss-rowName",
|
|
4646
|
+
children: [title, expandable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4647
|
+
className: "ss-expandMark",
|
|
4648
|
+
"aria-hidden": true,
|
|
4649
|
+
children: open ? "▾" : "▸"
|
|
4650
|
+
})]
|
|
4651
|
+
}),
|
|
4652
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4653
|
+
className: "ss-rowDesc",
|
|
4654
|
+
children: desc
|
|
4655
|
+
}),
|
|
4656
|
+
help && !expandable && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4657
|
+
className: "ss-help",
|
|
4658
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4659
|
+
type: "button",
|
|
4660
|
+
className: "ss-helpMark",
|
|
4661
|
+
"aria-label": `${title} 帮助`,
|
|
4662
|
+
children: "?"
|
|
4663
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4664
|
+
className: "ss-helpTip",
|
|
4665
|
+
children: help
|
|
4666
|
+
})]
|
|
4667
|
+
})
|
|
4668
|
+
]
|
|
4669
|
+
}),
|
|
4670
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4671
|
+
className: "ss-rowControl",
|
|
4672
|
+
children: control
|
|
4673
|
+
}),
|
|
4674
|
+
expandable && open && detail !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4675
|
+
className: "ss-rowDetail",
|
|
4676
|
+
children: detail
|
|
4677
|
+
})
|
|
4678
|
+
]
|
|
4648
4679
|
});
|
|
4649
4680
|
}
|
|
4650
4681
|
/** 分组(多级标题:分组标题 + 一组行卡) */
|
|
@@ -4736,6 +4767,12 @@ Instruction-following style:
|
|
|
4736
4767
|
const acpPort = value?.acpHttpPort ?? 3100;
|
|
4737
4768
|
const publicAskOn = value?.publicAskEnabled ?? false;
|
|
4738
4769
|
const autopilotOn = value?.autopilotEnabled ?? false;
|
|
4770
|
+
const [openGateway, setOpenGateway] = (0, react.useState)(false);
|
|
4771
|
+
const [openRebuild, setOpenRebuild] = (0, react.useState)(false);
|
|
4772
|
+
const [openSkiff, setOpenSkiff] = (0, react.useState)(false);
|
|
4773
|
+
const [openAcp, setOpenAcp] = (0, react.useState)(false);
|
|
4774
|
+
const [openPublicAsk, setOpenPublicAsk] = (0, react.useState)(false);
|
|
4775
|
+
const [openAutopilot, setOpenAutopilot] = (0, react.useState)(false);
|
|
4739
4776
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4740
4777
|
className: "ss-section",
|
|
4741
4778
|
children: [
|
|
@@ -4745,46 +4782,66 @@ Instruction-following style:
|
|
|
4745
4782
|
}),
|
|
4746
4783
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4747
4784
|
className: "ss-intro",
|
|
4748
|
-
children: "宁静号的 plugin 级配置(全局生效,不依赖具体 CCC
|
|
4785
|
+
children: "宁静号的 plugin 级配置(全局生效,不依赖具体 CCC)。点击任一行展开该功能的详细设定;改动即时保存。"
|
|
4749
4786
|
}),
|
|
4750
4787
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Group, {
|
|
4751
4788
|
title: "访问",
|
|
4752
4789
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
|
|
4753
4790
|
title: "双端口网关",
|
|
4754
4791
|
desc: "额外监听端口 3081,登录后可从外部访问 Web UI",
|
|
4755
|
-
|
|
4792
|
+
expandable: true,
|
|
4793
|
+
open: openGateway,
|
|
4794
|
+
onToggle: setOpenGateway,
|
|
4795
|
+
expandHint: "配置",
|
|
4756
4796
|
control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Toggle, {
|
|
4757
4797
|
checked: gatewayOn,
|
|
4758
4798
|
onChange: (on) => toggle("gatewayEnabled", on)
|
|
4799
|
+
}),
|
|
4800
|
+
detail: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4801
|
+
className: "ss-detailStack",
|
|
4802
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4803
|
+
className: "ss-detailIntro",
|
|
4804
|
+
children: "双端口网关(端口 3081)让外网/局域网用户经登录页访问本 DSH Web UI:\n· 适用范围:跨网络访问(本机默认端口 3080 仅监听本机)\n· 安全:登录账号 + 可选 TOTP 第二因素\n· 工作区白名单:登录后仅白名单内工作区可见(可留空=全部)\n· 变更立即生效(热重建,无需重启)"
|
|
4805
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountsEditor, { gatewayOn })]
|
|
4759
4806
|
})
|
|
4760
4807
|
}) })
|
|
4761
4808
|
}),
|
|
4762
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
4809
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Group, {
|
|
4763
4810
|
title: "上下文",
|
|
4764
|
-
children:
|
|
4811
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
|
|
4765
4812
|
title: "超限重建",
|
|
4766
4813
|
desc: "上下文接近上限时提示调用 session_rebuild 清空重建",
|
|
4767
|
-
|
|
4814
|
+
expandable: true,
|
|
4815
|
+
open: openRebuild,
|
|
4816
|
+
onToggle: setOpenRebuild,
|
|
4817
|
+
expandHint: "配置",
|
|
4768
4818
|
control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Toggle, {
|
|
4769
4819
|
checked: rebuildOn,
|
|
4770
4820
|
onChange: (on) => toggle("rebuildEnabled", on)
|
|
4821
|
+
}),
|
|
4822
|
+
detail: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4823
|
+
className: "ss-detailStack",
|
|
4824
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4825
|
+
className: "ss-detailIntro",
|
|
4826
|
+
children: "上下文超限自动重建(session_rebuild):\n· 机制:agent 上下文占用达到阈值时,由 LLM 主动调用重建工具\n· 语义:完全丢弃当前 dsh 会话 + 自动新建 + 注入「继续原 SESSION 的工作」\n· 效果:SESSION.md 原位不动,认知轨迹延续,上下文归零\n· 关闭后:上下文超限时不再提示,可能导致会话卡顿或丢失"
|
|
4827
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
|
|
4828
|
+
title: "重建阈值",
|
|
4829
|
+
desc: "上下文占用达到该 K 数值时提示(单位 K token,默认 400)",
|
|
4830
|
+
help: "重建触发阈值(需求①:K 数值,默认 400K,范围 50~4000K):\n· 含义:上下文 projected tokens 达到 thresholdK × 1000 时触发提醒\n· 纯绝对数值(不再依赖窗口比例)\n· 迁移:旧版 0~1 比例(settings.yaml rebuildThreshold)已废弃被忽略\n· 调低更早触发 / 调高更晚触发;仅「超限重建」开启时有意义",
|
|
4831
|
+
control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4832
|
+
className: "ss-portInput",
|
|
4833
|
+
type: "number",
|
|
4834
|
+
min: 50,
|
|
4835
|
+
max: 4e3,
|
|
4836
|
+
step: 50,
|
|
4837
|
+
value: thresholdK,
|
|
4838
|
+
disabled: !rebuildOn,
|
|
4839
|
+
title: "重建阈值(K token,默认 400)",
|
|
4840
|
+
onChange: (e) => setThreshold(Number(e.target.value))
|
|
4841
|
+
})
|
|
4842
|
+
})]
|
|
4771
4843
|
})
|
|
4772
|
-
}) })
|
|
4773
|
-
title: "重建阈值",
|
|
4774
|
-
desc: "上下文占用达到该 K 数值时提示(单位 K token,默认 400)",
|
|
4775
|
-
help: "重建触发阈值(需求①:K 数值,默认 400K,范围 50~4000K):\n· 含义:上下文 projected tokens 达到 thresholdK × 1000 时,轨迹跟踪器开始提醒重建\n· 纯绝对数值(不再依赖窗口比例)——配多大就多大,无窗口上限保护\n· 迁移:旧版 0~1 比例(settings.yaml rebuildThreshold,如 0.9)已废弃并被忽略——\n 请按 K 数值在此重设(如 0.9 → 900);若从未设置则默认 400K 生效\n· 调低:更早触发(适合长任务,避免上下文耗尽前措手不及)\n· 调高:更晚触发(适合短对话,减少不必要的重建提示)\n· 仅「超限重建」开启时有意义",
|
|
4776
|
-
control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4777
|
-
className: "ss-portInput",
|
|
4778
|
-
type: "number",
|
|
4779
|
-
min: 50,
|
|
4780
|
-
max: 4e3,
|
|
4781
|
-
step: 50,
|
|
4782
|
-
value: thresholdK,
|
|
4783
|
-
disabled: !rebuildOn,
|
|
4784
|
-
title: "重建阈值(K token,默认 400)",
|
|
4785
|
-
onChange: (e) => setThreshold(Number(e.target.value))
|
|
4786
|
-
})
|
|
4787
|
-
}) })]
|
|
4844
|
+
}) })
|
|
4788
4845
|
}),
|
|
4789
4846
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Group, {
|
|
4790
4847
|
title: "外部能力",
|
|
@@ -4792,7 +4849,9 @@ Instruction-following style:
|
|
|
4792
4849
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
|
|
4793
4850
|
title: "Skiff 调试",
|
|
4794
4851
|
desc: "Skiff 认知子集问答页(端口 3099,实验性,127.0.0.1)",
|
|
4795
|
-
|
|
4852
|
+
expandable: true,
|
|
4853
|
+
open: openSkiff,
|
|
4854
|
+
onToggle: setOpenSkiff,
|
|
4796
4855
|
control: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4797
4856
|
className: "ss-switchRow",
|
|
4798
4857
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Toggle, {
|
|
@@ -4808,12 +4867,18 @@ Instruction-following style:
|
|
|
4808
4867
|
title: "Skiff 调试端口(默认 3099)",
|
|
4809
4868
|
onChange: (e) => setSkiffPort(Number(e.target.value))
|
|
4810
4869
|
})]
|
|
4870
|
+
}),
|
|
4871
|
+
detail: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4872
|
+
className: "ss-detailIntro",
|
|
4873
|
+
children: "Skiff 认知子集角色调试服务(端口 3099):\n· 概念:Skiff = 完整宁静号 trajectory 的任意子集(认知子集角色)\n· 服务:角色问答页(调试用),仅监听 127.0.0.1(本地)\n· 使用:配置 CCC 的 skiff.roles 角色后,可经此页以角色身份问答\n· 实验性:人工启停,默认关闭;对外问答请用「Skiff 问答页」"
|
|
4811
4874
|
})
|
|
4812
4875
|
}) }),
|
|
4813
4876
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
|
|
4814
4877
|
title: "ACP JSON-RPC",
|
|
4815
4878
|
desc: "程序化调用 Skiff 角色(端口 3100,实验性,127.0.0.1)",
|
|
4816
|
-
|
|
4879
|
+
expandable: true,
|
|
4880
|
+
open: openAcp,
|
|
4881
|
+
onToggle: setOpenAcp,
|
|
4817
4882
|
control: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4818
4883
|
className: "ss-switchRow",
|
|
4819
4884
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Toggle, {
|
|
@@ -4829,60 +4894,199 @@ Instruction-following style:
|
|
|
4829
4894
|
title: "ACP + Skiff 问答共用端口(默认 3100)",
|
|
4830
4895
|
onChange: (e) => setAcpPort(Number(e.target.value))
|
|
4831
4896
|
})]
|
|
4897
|
+
}),
|
|
4898
|
+
detail: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4899
|
+
className: "ss-detailIntro",
|
|
4900
|
+
children: "ACP(Agent Client Protocol)HTTP JSON-RPC 端点(端口 3100):\n· 作用:程序化调用 Skiff 角色(指定 CCC + 角色 + 会话)\n· 形态:HTTP JSON-RPC 服务,仅监听 127.0.0.1(本地)\n· 场景:IM 桥(如微信桥)、脚本、自动化接线\n· 实验性:人工启停,默认关闭;与「Skiff 问答页」共用端口"
|
|
4832
4901
|
})
|
|
4833
4902
|
}) }),
|
|
4834
4903
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
|
|
4835
4904
|
title: "Skiff 问答页",
|
|
4836
4905
|
desc: "按认知容器暴露问答页(端口 3100,需 key)",
|
|
4837
|
-
|
|
4906
|
+
expandable: true,
|
|
4907
|
+
open: openPublicAsk,
|
|
4908
|
+
onToggle: setOpenPublicAsk,
|
|
4838
4909
|
control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Toggle, {
|
|
4839
4910
|
checked: publicAskOn,
|
|
4840
4911
|
onChange: (on) => toggle("publicAskEnabled", on)
|
|
4912
|
+
}),
|
|
4913
|
+
detail: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4914
|
+
className: "ss-detailStack",
|
|
4915
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4916
|
+
className: "ss-detailIntro",
|
|
4917
|
+
children: "Skiff 问答页(对外问答,端口 3100,key 认证):\n· 作用:让外部用户在浏览器中与指定 CCC 的 Skiff 角色对话\n· 认证:访问 key(首次开启自动生成)\n· 授权:开放容器白名单(未选 = 全部开放)\n· 外部接入:需经部署方自选方案暴露(隧道/反代/端口映射)\n· 安全:key 可轮换(旧 key 立即失效)"
|
|
4918
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PublicAskEditor, { publicAskOn })]
|
|
4841
4919
|
})
|
|
4842
4920
|
}) }),
|
|
4843
4921
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
|
|
4844
4922
|
title: "Autopilot Trajectory",
|
|
4845
4923
|
desc: "自动巡航轨迹(全局开关,默认关——只在指定电脑开启)",
|
|
4846
|
-
|
|
4924
|
+
expandable: true,
|
|
4925
|
+
open: openAutopilot,
|
|
4926
|
+
onToggle: setOpenAutopilot,
|
|
4847
4927
|
control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Toggle, {
|
|
4848
4928
|
checked: autopilotOn,
|
|
4849
4929
|
onChange: (on) => toggle("autopilotEnabled", on)
|
|
4930
|
+
}),
|
|
4931
|
+
detail: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4932
|
+
className: "ss-detailStack",
|
|
4933
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4934
|
+
className: "ss-detailIntro",
|
|
4935
|
+
children: "Autopilot Trajectory 全局总开关(v1.27.9):\n· 作用:控制本机(本 dsh 实例)是否运行自动巡航轨迹\n· 默认关:未开启即使 CCC 配置 enabled=true 也不启动定时器\n· 定位:多台电脑装 dsp 时,只在指定电脑开启(其余默认关)\n· 双重门控:全局开关 AND CCC 级 enabled 都满足才运行\n· CCC 级配置(interval/session/偏见脚本/焦点)不受影响"
|
|
4936
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AutopilotTrajectoryStatusBlock, { autopilotOn })]
|
|
4850
4937
|
})
|
|
4851
4938
|
}) })
|
|
4852
4939
|
]
|
|
4853
4940
|
}),
|
|
4854
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Collapse, {
|
|
4855
|
-
title: "Skiff 问答页配置",
|
|
4856
|
-
desc: "开放容器白名单 · 访问 key 与地址",
|
|
4857
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PublicAskEditor, { publicAskOn })
|
|
4858
|
-
}),
|
|
4859
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Collapse, {
|
|
4860
|
-
title: "外部访问",
|
|
4861
|
-
desc: "网关监听(端口 3081)· 登录账号 · 工作区白名单(plugin 全局)",
|
|
4862
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountsEditor, { gatewayOn })
|
|
4863
|
-
}),
|
|
4864
4941
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Collapse, {
|
|
4865
4942
|
title: "彩蛋模式",
|
|
4866
4943
|
desc: "persona 输出风格(默认关闭)",
|
|
4867
4944
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PersonaEditor, {})
|
|
4868
4945
|
}),
|
|
4869
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Collapse, {
|
|
4870
|
-
title: "Autopilot Trajectory",
|
|
4871
|
-
desc: autopilotOn ? "全局已开启" : "全局关闭(外部能力组开启)",
|
|
4872
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AutopilotTrajectoryStatusBlock, {})
|
|
4873
|
-
}),
|
|
4874
4946
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Collapse, {
|
|
4875
4947
|
title: "微信桥",
|
|
4876
|
-
desc: "扫码绑定微信账号 · 路由到 skiff
|
|
4948
|
+
desc: "扫码绑定微信账号 · 路由到 skiff 角色(CCC 级配置)",
|
|
4877
4949
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WeixinBridgeEditor, {})
|
|
4950
|
+
}),
|
|
4951
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Collapse, {
|
|
4952
|
+
title: "会话清理",
|
|
4953
|
+
desc: "删除指定天数前无活动的 DSH 会话(手动,物理删不可恢复)",
|
|
4954
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionCleanupBlock, {})
|
|
4955
|
+
})
|
|
4956
|
+
]
|
|
4957
|
+
});
|
|
4958
|
+
}
|
|
4959
|
+
/** 「会话清理」块(v1.29 需求③,S142 用户拍板:lastActive + 手动按钮 + 直接物理删):
|
|
4960
|
+
* 天数输入 → GET 预览(dryRun 列表)→ 确认 → POST 执行。live 会话由服务端保护跳过。 */
|
|
4961
|
+
function SessionCleanupBlock() {
|
|
4962
|
+
const [days, setDays] = (0, react.useState)(30);
|
|
4963
|
+
const [preview, setPreview] = (0, react.useState)(null);
|
|
4964
|
+
const [done, setDone] = (0, react.useState)(null);
|
|
4965
|
+
const [busy, setBusy] = (0, react.useState)(false);
|
|
4966
|
+
const [confirming, setConfirming] = (0, react.useState)(false);
|
|
4967
|
+
const [error, setError] = (0, react.useState)(null);
|
|
4968
|
+
const previewNow = async () => {
|
|
4969
|
+
setBusy(true);
|
|
4970
|
+
setError(null);
|
|
4971
|
+
setDone(null);
|
|
4972
|
+
try {
|
|
4973
|
+
const res = await fetch(`/serenity/session-cleanup?olderThanDays=${days}`, { headers: {
|
|
4974
|
+
accept: "application/json",
|
|
4975
|
+
"x-serenity-ui": "1"
|
|
4976
|
+
} });
|
|
4977
|
+
if (!res.ok) {
|
|
4978
|
+
const body = await res.json().catch(() => null);
|
|
4979
|
+
setError(body?.error ?? `HTTP ${res.status}`);
|
|
4980
|
+
return;
|
|
4981
|
+
}
|
|
4982
|
+
setPreview(await res.json());
|
|
4983
|
+
setConfirming(false);
|
|
4984
|
+
} catch (err) {
|
|
4985
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
4986
|
+
} finally {
|
|
4987
|
+
setBusy(false);
|
|
4988
|
+
}
|
|
4989
|
+
};
|
|
4990
|
+
const execute = async () => {
|
|
4991
|
+
if (!confirming) {
|
|
4992
|
+
setConfirming(true);
|
|
4993
|
+
return;
|
|
4994
|
+
}
|
|
4995
|
+
setBusy(true);
|
|
4996
|
+
setError(null);
|
|
4997
|
+
try {
|
|
4998
|
+
const res = await fetch(`/serenity/session-cleanup?olderThanDays=${days}`, {
|
|
4999
|
+
method: "POST",
|
|
5000
|
+
headers: {
|
|
5001
|
+
accept: "application/json",
|
|
5002
|
+
"x-serenity-ui": "1"
|
|
5003
|
+
}
|
|
5004
|
+
});
|
|
5005
|
+
if (!res.ok) {
|
|
5006
|
+
const body = await res.json().catch(() => null);
|
|
5007
|
+
setError(body?.error ?? `HTTP ${res.status}`);
|
|
5008
|
+
return;
|
|
5009
|
+
}
|
|
5010
|
+
setDone(await res.json());
|
|
5011
|
+
setPreview(null);
|
|
5012
|
+
setConfirming(false);
|
|
5013
|
+
} catch (err) {
|
|
5014
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
5015
|
+
} finally {
|
|
5016
|
+
setBusy(false);
|
|
5017
|
+
}
|
|
5018
|
+
};
|
|
5019
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5020
|
+
className: "ss-detailStack",
|
|
5021
|
+
children: [
|
|
5022
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
|
|
5023
|
+
title: "删除前无活动天数",
|
|
5024
|
+
desc: "删除最后活动早于该天数的 DSH 会话(默认 30)",
|
|
5025
|
+
help: "会话清理阈值(v1.29,S142 用户拍板 lastActive 基准):\n· 含义:删除「最后活动早于 N 天前」的 DSH 平台会话(对话历史)\n· lastActive = 会话日志文件最后写入时间(日志只追加,mtime 可靠)\n· live 保护:正在运行的会话绝不删除(服务端强制跳过)\n· 物理删不可恢复——先「预览」确认列表再执行",
|
|
5026
|
+
control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
5027
|
+
className: "ss-portInput",
|
|
5028
|
+
type: "number",
|
|
5029
|
+
min: 1,
|
|
5030
|
+
max: 3650,
|
|
5031
|
+
step: 1,
|
|
5032
|
+
value: days,
|
|
5033
|
+
title: "删除前无活动天数(默认 30)",
|
|
5034
|
+
onChange: (e) => {
|
|
5035
|
+
setDays(Math.min(3650, Math.max(1, Math.round(Number(e.target.value) || 30))));
|
|
5036
|
+
setPreview(null);
|
|
5037
|
+
setDone(null);
|
|
5038
|
+
setConfirming(false);
|
|
5039
|
+
}
|
|
5040
|
+
})
|
|
5041
|
+
}),
|
|
5042
|
+
error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
5043
|
+
className: "ss-error",
|
|
5044
|
+
children: error
|
|
5045
|
+
}),
|
|
5046
|
+
preview && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5047
|
+
className: "ss-detailIntro",
|
|
5048
|
+
children: preview.count === 0 ? `无早于 ${preview.olderThanDays} 天前无活动的会话可清理(root: ${preview.root})` : `将删除 ${preview.count} 个会话(root: ${preview.root}):\n` + preview.candidates.map((c) => ` · ${c.id}(${c.project},最后活动 ${new Date(c.lastActive).toLocaleDateString()})`).join("\n")
|
|
5049
|
+
}),
|
|
5050
|
+
done && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5051
|
+
className: "ss-detailIntro",
|
|
5052
|
+
children: `已删除 ${done.deleted.length} 个会话${done.errors.length > 0 ? `;${done.errors.length} 个失败(${done.errors.map((e) => `${e.id}: ${e.reason}`).join("; ")})` : ""}`
|
|
5053
|
+
}),
|
|
5054
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5055
|
+
className: "ss-switchRow",
|
|
5056
|
+
children: [
|
|
5057
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
5058
|
+
type: "button",
|
|
5059
|
+
className: "ss-wakeBtn",
|
|
5060
|
+
disabled: busy,
|
|
5061
|
+
onClick: () => void previewNow(),
|
|
5062
|
+
children: busy ? "处理中…" : preview ? "刷新预览" : "预览将删会话"
|
|
5063
|
+
}),
|
|
5064
|
+
preview && preview.count > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
5065
|
+
type: "button",
|
|
5066
|
+
className: "ss-removeBtn",
|
|
5067
|
+
disabled: busy,
|
|
5068
|
+
onClick: () => void execute(),
|
|
5069
|
+
children: confirming ? "确认物理删除(不可恢复)" : "执行删除"
|
|
5070
|
+
}),
|
|
5071
|
+
done && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
5072
|
+
type: "button",
|
|
5073
|
+
className: "ss-wakeBtn",
|
|
5074
|
+
onClick: () => {
|
|
5075
|
+
setPreview(null);
|
|
5076
|
+
setDone(null);
|
|
5077
|
+
},
|
|
5078
|
+
children: "完成"
|
|
5079
|
+
})
|
|
5080
|
+
]
|
|
4878
5081
|
})
|
|
4879
5082
|
]
|
|
4880
5083
|
});
|
|
4881
5084
|
}
|
|
4882
5085
|
/** 「Autopilot Trajectory」只读状态区块(v1.26.14;v1.27.4 多 CCC:显式 CCC 选择器——
|
|
4883
5086
|
* GET/POST 带 ?ccc=/body.ccc——用户"两个 CCC 都设定了,但手工唤起只能唤起一个"修复):
|
|
4884
|
-
* 展示所选 CCC 的状态(配置摘要 + 目标会话 + 窗口/可唤起判定 + 审计);配置改走 CCC 配置文件
|
|
4885
|
-
|
|
5087
|
+
* 展示所选 CCC 的状态(配置摘要 + 目标会话 + 窗口/可唤起判定 + 审计);配置改走 CCC 配置文件
|
|
5088
|
+
* v1.29:autopilotOn prop(需求②——原折叠块并入开关行 detail,全局门控状态由外部行显示) */
|
|
5089
|
+
function AutopilotTrajectoryStatusBlock(props) {
|
|
4886
5090
|
const [cccs, setCccs] = (0, react.useState)([]);
|
|
4887
5091
|
const [selectedRoot, setSelectedRoot] = (0, react.useState)("");
|
|
4888
5092
|
const [status, setStatus] = (0, react.useState)(null);
|
|
@@ -4967,7 +5171,8 @@ Instruction-following style:
|
|
|
4967
5171
|
}) })
|
|
4968
5172
|
});
|
|
4969
5173
|
const target = status.target;
|
|
4970
|
-
const
|
|
5174
|
+
const { autopilotOn } = props;
|
|
5175
|
+
const stateText = !props.autopilotOn ? "全局开关关闭(在「外部能力」组开启后才运行)" : !status.configured ? "未配置(机制未开始)" : !status.enabled ? "已配置,未启用(enabled=false,零资源占用)" : "已启用 — 时钟唤起等待中";
|
|
4971
5176
|
const targetText = target ? `${target.dirName}${target.autoFlag ? "(--auto ✓)" : "(无 --auto 标志)"} · 空闲 ${target.idleHours.toFixed(1)}h / 阈值 ${status.intervalHours}h` : status.session ? `会话 ${status.session} 未命中(AGENT_SESSIONS 无匹配)` : "未配置目标会话(不唤起)";
|
|
4972
5177
|
const wakeReady = status.enabled && !!target && target.autoFlag;
|
|
4973
5178
|
const lastWake = status.recentWakes[0];
|
package/lib/index.js
CHANGED
|
@@ -1428,7 +1428,7 @@ handyman(杂工)工具可用模型白名单(provider/model 列表);未
|
|
|
1428
1428
|
{ "handyman": { "models": ["minimax-cn-coding-plan/MiniMax-M3"], "defaultModel": "minimax-cn-coding-plan/MiniMax-M3", "maxRounds": 100, "maxParallel": 10 } }
|
|
1429
1429
|
|
|
1430
1430
|
── 2. sessionKeeper.threshold ──
|
|
1431
|
-
|
|
1431
|
+
trajectory-assistant(TRAJECTORY-ASSISTANT · CHECKPOINT)提醒机制的积分阈值(非 headless 主 agent)。
|
|
1432
1432
|
按工具调用加权 + 耗时计分;达到阈值注入提醒,要求模型回复 ACK 码。
|
|
1433
1433
|
|
|
1434
1434
|
Config:
|
|
@@ -3824,6 +3824,49 @@ function registerBootstrap(ctx) {
|
|
|
3824
3824
|
}, { prepend: true });
|
|
3825
3825
|
}
|
|
3826
3826
|
//#endregion
|
|
3827
|
+
//#region src/trajectory-assistant.ts
|
|
3828
|
+
/**
|
|
3829
|
+
* trajectory-assistant.ts — 关卡化注入的统一命名与风格门面(v0.3,S142)
|
|
3830
|
+
*
|
|
3831
|
+
* 概念(用户拍板 2026-09-05):dsp 全部"过程中动态提示注入"统一命名为
|
|
3832
|
+
* trajectory-assistant(轨迹助航员)。关卡设计思想塑造**结构与时机**
|
|
3833
|
+
* (何时/何地注入),**不用于提示词用词**(D8 词法原则)——纯游戏黑话
|
|
3834
|
+
* (BOSS/XP/level-up)禁止出现在提示词文本;CHECKPOINT/LIMIT/TUTORIAL 等
|
|
3835
|
+
* 跨领域自然通用词允许。
|
|
3836
|
+
*
|
|
3837
|
+
* 本模块 = token 常量 + level-event 词汇表的**单一真相源**(避免前缀散落
|
|
3838
|
+
* 各文件字符串字面量)+ 风格门面(plain 默认 / metaphor 星舰变体)。
|
|
3839
|
+
* 仅当 style=metaphor 时前缀包装措辞变化;可行动正文不变 → 零行为漂移。
|
|
3840
|
+
*
|
|
3841
|
+
* 设计简写(L0 环境 / L1 教程 / L2 目标 / L3 检查点 / L4 极限 / L5 守卫 /
|
|
3842
|
+
* L6 结算)仅在本模块注释与内部文档出现,永不浮现在提示词文本。
|
|
3843
|
+
*
|
|
3844
|
+
* 结算(settlement)挂点:D6 用户拍板——若 CCC 有标准 SESSION 复盘仪式,
|
|
3845
|
+
* 结算视图归 trajectory-assistant。当前 close/archive 无复盘摘要 → 机制
|
|
3846
|
+
* 延后,仅留 onSettlement 导出 seam(OP-1,无调用者)。
|
|
3847
|
+
*/
|
|
3848
|
+
/** 可见提示词前缀用词(跨领域自然词,D8:无游戏黑话) */
|
|
3849
|
+
const EVENT_LABEL = {
|
|
3850
|
+
/** 计分同步提醒(原 TRAJECTORY-STEWARD) */
|
|
3851
|
+
checkpoint: "CHECKPOINT",
|
|
3852
|
+
/** 上下文极限重建提醒(原 TRAJECTORY;LIMIT 替代被否的 BOSS——自然词) */
|
|
3853
|
+
limit: "LIMIT",
|
|
3854
|
+
/** 极限强制升级(原 TRAJECTORY-ESCALATED) */
|
|
3855
|
+
limitMandatory: "LIMIT · MANDATORY",
|
|
3856
|
+
/** 重建锚点头部(原 TRAJECTORY-REBUILD) */
|
|
3857
|
+
rebuild: "REBUILD",
|
|
3858
|
+
/** 敏感输出边界守卫(原 SERENITY OUTPUT GUARD) */
|
|
3859
|
+
guard: "BOUNDARY GUARD"
|
|
3860
|
+
};
|
|
3861
|
+
/** 家族标识(所有动态注入统一前缀) */
|
|
3862
|
+
const ASSISTANT_PREFIX = "TRAJECTORY-ASSISTANT";
|
|
3863
|
+
/** 完整 token:`[TRAJECTORY-ASSISTANT · <LABEL>]` */
|
|
3864
|
+
function eventToken(event) {
|
|
3865
|
+
return `[${ASSISTANT_PREFIX} · ${EVENT_LABEL[event]}]`;
|
|
3866
|
+
}
|
|
3867
|
+
/** ACK 确认码前缀(recorded/skipped 语义不变,仅家族名更新) */
|
|
3868
|
+
const ACK_PREFIX = `${ASSISTANT_PREFIX}-recorded`;
|
|
3869
|
+
//#endregion
|
|
3827
3870
|
//#region src/rebuild.ts
|
|
3828
3871
|
const PLUGIN_SOURCE$4 = {
|
|
3829
3872
|
kind: "plugin",
|
|
@@ -3850,7 +3893,7 @@ function buildRebuildAnchor(root, sessionName, activeMdPath, anchorMessages = DE
|
|
|
3850
3893
|
const sessionDir = basename(dirname(activeMdPath));
|
|
3851
3894
|
const sessionLine = sessionDir !== "AGENT_SESSIONS" ? `- Serenity session: ${sessionName !== "" ? `${sessionName} (${sessionDir})` : sessionDir}` : null;
|
|
3852
3895
|
return [
|
|
3853
|
-
"
|
|
3896
|
+
`${eventToken("rebuild")} The conversation has been cleared and rebuilt (Ship of Theseus: the carrier is replaced, the trajectory continues).`,
|
|
3854
3897
|
"",
|
|
3855
3898
|
...anchorMessages.flatMap((text) => [stripAckSuffix(text), ""]),
|
|
3856
3899
|
sessionName !== "" ? `Continue the work of ${sessionName}.` : "Continue the current work.",
|
|
@@ -4075,7 +4118,7 @@ function registerRebuildTurnHook(ctx) {
|
|
|
4075
4118
|
agent.steer(createUserMessage({
|
|
4076
4119
|
content: [{
|
|
4077
4120
|
type: "text",
|
|
4078
|
-
text: "
|
|
4121
|
+
text: `${eventToken("rebuild")} The conversation has been cleared and rebuilt. Follow the anchor instructions above now: read the persistent trajectory (SESSION.md) and continue the work automatically from the last checkpoint.`
|
|
4079
4122
|
}],
|
|
4080
4123
|
source: PLUGIN_SOURCE$4
|
|
4081
4124
|
}));
|
|
@@ -4137,7 +4180,7 @@ function renderText$3(value) {
|
|
|
4137
4180
|
function createRebuildTool(ctx) {
|
|
4138
4181
|
return defineTool({
|
|
4139
4182
|
name: "session_rebuild",
|
|
4140
|
-
description: "Trajectory-tracker overflow rebuild (Ship of Theseus): this session is the rebuildable carrier of a trajectory — the current conversation is discarded and rebuilt in place at the end of this turn with the anchor \"continue the work of {SESSION name}\" (first-anchor protocol body included), then auto-continues. SESSION.md (the trajectory's persistent body) stays in place; identity continues from it. Use when you receive a
|
|
4183
|
+
description: "Trajectory-tracker overflow rebuild (Ship of Theseus): this session is the rebuildable carrier of a trajectory — the current conversation is discarded and rebuilt in place at the end of this turn with the anchor \"continue the work of {SESSION name}\" (first-anchor protocol body included), then auto-continues. SESSION.md (the trajectory's persistent body) stays in place; identity continues from it. Use when you receive a " + eventToken("limit") + " reminder (context above threshold), at a natural pause point. After triggering, resume from SESSION.md when this turn ends.",
|
|
4141
4184
|
parameters: {
|
|
4142
4185
|
note: {
|
|
4143
4186
|
type: "string",
|
|
@@ -4600,7 +4643,7 @@ function buildWakeMessage(opts) {
|
|
|
4600
4643
|
lines.push(`[轨迹焦点] ${opts.topPrompt}`);
|
|
4601
4644
|
lines.push("");
|
|
4602
4645
|
}
|
|
4603
|
-
lines.push(`[Autopilot Trajectory 唤起] — 距上次轨迹活动已满 ${intervalLabel},自动继续。`, "", `身份锚定:继续 ${opts.sessionName} 的 trajectory(SESSION.md: ${opts.mdPath})。`, "先验偏见:");
|
|
4646
|
+
lines.push(`[Autopilot Trajectory · 唤起] — 距上次轨迹活动已满 ${intervalLabel},自动继续。`, "", `身份锚定:继续 ${opts.sessionName} 的 trajectory(SESSION.md: ${opts.mdPath})。`, "先验偏见:");
|
|
4604
4647
|
if (opts.motivation) lines.push(` · 自生动机:${opts.motivation}`);
|
|
4605
4648
|
if (opts.biasContent) lines.push(` · 偏见内容:${opts.biasContent}`);
|
|
4606
4649
|
if (!opts.motivation && !opts.biasContent) lines.push(" · (无——本轮纯自主探索)");
|
|
@@ -5128,7 +5171,7 @@ var KeeperTracker = class {
|
|
|
5128
5171
|
}
|
|
5129
5172
|
};
|
|
5130
5173
|
function reminderText(code, score) {
|
|
5131
|
-
return
|
|
5174
|
+
return `${eventToken("checkpoint")} Score threshold reached (${score}). Please acknowledge with [${ACK_PREFIX}-${code}] once progress is synced to the working session (acc-session show). No need to interrupt your work — just acknowledge inline and keep going.`;
|
|
5132
5175
|
}
|
|
5133
5176
|
/**
|
|
5134
5177
|
* F2 rebuild 提示(v1.21;v1.22.1 对齐"轨迹跟踪器"概念;v1.23.0 英化 + 载体关系;
|
|
@@ -5147,8 +5190,8 @@ function reminderText(code, score) {
|
|
|
5147
5190
|
* thresholdK = 配置阈值(千 token);文案 `Context usage at NNNK (threshold NNNK)`。
|
|
5148
5191
|
*/
|
|
5149
5192
|
function rebuildReminderText(tokensK, thresholdK, escalated = false) {
|
|
5150
|
-
if (escalated) return
|
|
5151
|
-
return
|
|
5193
|
+
if (escalated) return `${eventToken("limitMandatory")} Context usage at ${Math.round(tokensK)}K (threshold ${Math.round(thresholdK)}K) — you have been reminded repeatedly and have NOT called session_rebuild. This is now mandatory: STOP at the current task step, preserve valuable cognition into the CCC skills (or write a new-skill proposal into SESSION.md), then call the session_rebuild tool immediately, passing --summary "<content summary ≤20 chars>" (required; the dsh session title is renamed to S###-YYYY-MM-DD-<summary> after rebuild). The conversation will be cleared and rebuilt in place; SESSION.md is the persistent trajectory and stays in place — identity continues from it. Do not continue working without rebuilding; this reminder persists until you call session_rebuild.`;
|
|
5194
|
+
return `${eventToken("limit")} Context usage at ${Math.round(tokensK)}K (threshold ${Math.round(thresholdK)}K). This session is the rebuildable carrier of the trajectory: SESSION.md is the persistent body, this conversation is only a temporary work copy. Before rebuilding: if this conversation produced valuable cognition, revise the relevant existing skill of this CCC (structure it with eap); if a new skill is warranted, write a short proposal into SESSION.md for the user to review — do not create it yourself. ACT NOW: at the next natural pause (end of the current task step), call the session_rebuild tool — passing --summary "<content summary ≤20 chars>" describing the next work phase (required; the dsh session title is renamed to S###-YYYY-MM-DD-<summary> after rebuild) — to clear and rebuild this conversation: the current copy is discarded, identity continues from SESSION.md. If you are in the middle of an unbreakable step, continue it, then rebuild at its end. Do not ignore this; rebuild is the expected action, not an option.`;
|
|
5152
5195
|
}
|
|
5153
5196
|
/** 读取会话 contextPressure 投影(sessionProjections 可选服务;未装配返回 null) */
|
|
5154
5197
|
function readContextPressure(ctx, session) {
|
|
@@ -5905,22 +5948,25 @@ function eapBlock() {
|
|
|
5905
5948
|
].join("\n");
|
|
5906
5949
|
}
|
|
5907
5950
|
/**
|
|
5908
|
-
* Metaphor 强化块(v1.19.6,S142
|
|
5951
|
+
* Metaphor 强化块(v1.19.6,S142;v1.29 星舰意象升级,S142 用户拍板):
|
|
5952
|
+
* 宁静号宇宙隐喻域(星舰/深空/航程/船员)。海船→星舰意象:one starship, one voyage;
|
|
5953
|
+
* deep space / launch / docking clamp;Departure Inspection(原 Harbor Inspection)。
|
|
5909
5954
|
* 隐喻是记忆钩子——形象唤起约束,前述块保持规则精确。每条隐喻 = 一个不可违背的
|
|
5910
5955
|
* 物理事实 + 行为判据(verdict)。全英文(与 CCE/Constraints 一致);独立块可
|
|
5911
5956
|
* 回退;无 osp 对应(dsp 扩展,不进对齐断言参照)。
|
|
5957
|
+
* 结构约束(docs/metaphor-domain.md M-1~M-4):三层骨架不变 + 每条映射约束不变。
|
|
5912
5958
|
*/
|
|
5913
5959
|
function metaphorBlock() {
|
|
5914
5960
|
return [
|
|
5915
5961
|
"",
|
|
5916
5962
|
"=== Serenity Metaphor ===",
|
|
5917
|
-
"The Serenity Universe — one
|
|
5963
|
+
"The Serenity Universe — one starship, one voyage. Metaphors are memory hooks:",
|
|
5918
5964
|
"they make constraints vivid, while the rules above stay precise. Each",
|
|
5919
5965
|
"metaphor is an unbreakable physical fact; violating one is a behavioral",
|
|
5920
5966
|
"violation. The universe is structured in three layers — the Ship (the",
|
|
5921
5967
|
"container itself), the Voyage (the cognitive lifecycle), the Crew",
|
|
5922
5968
|
"(multi-agent collaboration); every metaphor maps to one protocol",
|
|
5923
|
-
"constraint.
|
|
5969
|
+
"constraint. Deep space has no mistakes — only stars you have not yet mapped.",
|
|
5924
5970
|
"",
|
|
5925
5971
|
"THE SHIP — the container itself",
|
|
5926
5972
|
"",
|
|
@@ -5930,8 +5976,8 @@ function metaphorBlock() {
|
|
|
5930
5976
|
" container = overload.",
|
|
5931
5977
|
"",
|
|
5932
5978
|
"2. Deck Order → Entropy (H_op). Clutter on deck raises the cost of",
|
|
5933
|
-
" finding things. H_op ≤ H_critical = the ship stays
|
|
5934
|
-
" Verdict: disorganized output =
|
|
5979
|
+
" finding things. H_op ≤ H_critical = the ship stays flight-worthy.",
|
|
5980
|
+
" Verdict: disorganized output = debris in the hold.",
|
|
5935
5981
|
"",
|
|
5936
5982
|
"3. Engineering Drawings → EAP. Every part dimensioned (E↑), the",
|
|
5937
5983
|
" drawings rebuild the whole machine (R↓), the drawings are reusable",
|
|
@@ -5947,14 +5993,14 @@ function metaphorBlock() {
|
|
|
5947
5993
|
" is on the manifest (mech-registry); there is exactly one manifest.",
|
|
5948
5994
|
" An MSM self-describes (--help/--schema) — the manifest is the only",
|
|
5949
5995
|
" key. Verdict: duplicating a tool's usage in documents = two",
|
|
5950
|
-
" contradictory charts.",
|
|
5996
|
+
" contradictory star charts.",
|
|
5951
5997
|
"",
|
|
5952
5998
|
"THE VOYAGE — the cognitive lifecycle",
|
|
5953
5999
|
"",
|
|
5954
|
-
"6.
|
|
5955
|
-
"
|
|
5956
|
-
" ballast (constraints) before setting
|
|
5957
|
-
"
|
|
6000
|
+
"6. Departure Inspection → First Anchor. The departure inspection = pre-",
|
|
6001
|
+
" launch checklist: confirm identity (ACC manifesto), logbook (SESSION),",
|
|
6002
|
+
" ballast (constraints) before setting course. Verdict: skipping the",
|
|
6003
|
+
" inspection and launching directly = flying uninspected.",
|
|
5958
6004
|
"",
|
|
5959
6005
|
"7. The Logbook → Session Tracking. SESSION.md is the trajectory's logbook —",
|
|
5960
6006
|
" the persistent body of the voyage; sessions are rebuildable carriers of",
|
|
@@ -6090,12 +6136,12 @@ function sessionBlock(root, scope = DEFAULT_SESSION_SCOPE) {
|
|
|
6090
6136
|
"This preserves the session context across todo updates.",
|
|
6091
6137
|
"Do NOT remove or reorder this item — keep it at position 0.",
|
|
6092
6138
|
"",
|
|
6093
|
-
"TRAJECTORY-
|
|
6139
|
+
"TRAJECTORY-ASSISTANT: a background tracker scores your tool use (write/edit=3,",
|
|
6094
6140
|
"task=10, read/grep/glob/msm=1, +1 per minute) and reminds you with a",
|
|
6095
|
-
"[TRAJECTORY-
|
|
6141
|
+
"[TRAJECTORY-ASSISTANT · CHECKPOINT] message when the threshold is reached. On every such",
|
|
6096
6142
|
"reminder you MUST reply with the exact ACK code:",
|
|
6097
|
-
" [TRAJECTORY-
|
|
6098
|
-
" [TRAJECTORY-
|
|
6143
|
+
" [TRAJECTORY-ASSISTANT-recorded-{code}] — if you recorded progress to SESSION.md",
|
|
6144
|
+
" [TRAJECTORY-ASSISTANT-skipped-{code}] — if nothing to record this round",
|
|
6099
6145
|
"Do not ignore the reminder; do not stop ongoing work. Codes are single-use;",
|
|
6100
6146
|
"never reuse a prior code.",
|
|
6101
6147
|
""
|
|
@@ -7025,6 +7071,58 @@ function registerStatusApi(ctx, opts = {}) {
|
|
|
7025
7071
|
}
|
|
7026
7072
|
}
|
|
7027
7073
|
});
|
|
7074
|
+
ctx.webServer.register({
|
|
7075
|
+
kind: "exact",
|
|
7076
|
+
path: "/serenity/session-cleanup",
|
|
7077
|
+
handler: async (req, res) => {
|
|
7078
|
+
try {
|
|
7079
|
+
const url = new URL(req.url ?? "/", "http://127.0.0.1");
|
|
7080
|
+
const daysParam = Number(url.searchParams.get("olderThanDays") ?? "30");
|
|
7081
|
+
const days = Number.isFinite(daysParam) && daysParam >= 1 ? daysParam : 30;
|
|
7082
|
+
const sessions = ctx.get("sessions");
|
|
7083
|
+
const liveIds = /* @__PURE__ */ new Set();
|
|
7084
|
+
if (sessions?.list) for (const s of sessions.list()) {
|
|
7085
|
+
const id = s.id ?? s.header?.id;
|
|
7086
|
+
if (id) liveIds.add(id);
|
|
7087
|
+
}
|
|
7088
|
+
const { sessionsRootDir, collectEligibleSessions, performCleanup, cutoffDaysAgo } = await import("./session-cleanup-PahSNvjI.js");
|
|
7089
|
+
const root = sessionsRootDir();
|
|
7090
|
+
if (req.method === "GET") {
|
|
7091
|
+
const { candidates } = performCleanup(root, cutoffDaysAgo(days), liveIds, { dryRun: true });
|
|
7092
|
+
sendJson$1(res, 200, {
|
|
7093
|
+
root,
|
|
7094
|
+
olderThanDays: days,
|
|
7095
|
+
dryRun: true,
|
|
7096
|
+
count: candidates.length,
|
|
7097
|
+
candidates: candidates.map((c) => ({
|
|
7098
|
+
id: c.id,
|
|
7099
|
+
project: c.project,
|
|
7100
|
+
lastActive: new Date(c.lastActiveMs).toISOString()
|
|
7101
|
+
}))
|
|
7102
|
+
});
|
|
7103
|
+
return;
|
|
7104
|
+
}
|
|
7105
|
+
if (req.method !== "POST") {
|
|
7106
|
+
sendJson$1(res, 405, { error: "method not allowed" });
|
|
7107
|
+
return;
|
|
7108
|
+
}
|
|
7109
|
+
if (req.headers["x-serenity-ui"] !== "1") {
|
|
7110
|
+
sendJson$1(res, 403, { error: "会话清理仅限 WebUI(client 专用)" });
|
|
7111
|
+
return;
|
|
7112
|
+
}
|
|
7113
|
+
const { result } = performCleanup(root, cutoffDaysAgo(days), liveIds);
|
|
7114
|
+
sendJson$1(res, 200, {
|
|
7115
|
+
root,
|
|
7116
|
+
olderThanDays: days,
|
|
7117
|
+
dryRun: false,
|
|
7118
|
+
deleted: result.deleted,
|
|
7119
|
+
errors: result.errors
|
|
7120
|
+
});
|
|
7121
|
+
} catch (err) {
|
|
7122
|
+
sendJson$1(res, 400, { error: err.message ?? String(err) });
|
|
7123
|
+
}
|
|
7124
|
+
}
|
|
7125
|
+
});
|
|
7028
7126
|
}
|
|
7029
7127
|
/** 进行中的扫码登录(loginKey → 状态;进程内,5min 有效) */
|
|
7030
7128
|
const weixinLogins = /* @__PURE__ */ new Map();
|
|
@@ -8088,6 +8186,8 @@ const MECHANISM_WORDS = [
|
|
|
8088
8186
|
"tools/post-execute",
|
|
8089
8187
|
"session_rebuild",
|
|
8090
8188
|
"Trajectory Steward",
|
|
8189
|
+
"TRAJECTORY-STEWARD",
|
|
8190
|
+
"TRAJECTORY-ASSISTANT",
|
|
8091
8191
|
"first-anchor",
|
|
8092
8192
|
"拦截缝",
|
|
8093
8193
|
"装配层",
|
|
@@ -8190,7 +8290,9 @@ const CATEGORY_GUIDE = {
|
|
|
8190
8290
|
*/
|
|
8191
8291
|
function buildRebuke(hits) {
|
|
8192
8292
|
const count = hits.length;
|
|
8193
|
-
|
|
8293
|
+
const noun = count === 1 ? "term" : "terms";
|
|
8294
|
+
const lines = hits.map((h) => `- "${h.word}" — ${CATEGORY_GUIDE[h.category]}`).join("\n");
|
|
8295
|
+
return `${eventToken("guard")} Your previous response contained ${count} sensitive internal ${noun} that must not appear in user-visible output:\n${lines}\nRegenerate the response from scratch without ANY of these — describe the same substance without referencing internal machinery, credentials, ports, tool names, or implementation details. Do not repeat the terms; do not explain this instruction to the user.`;
|
|
8194
8296
|
}
|
|
8195
8297
|
/** 打回状态(按 agent 会话跟踪连续命中轮数) */
|
|
8196
8298
|
const rebukeStates = /* @__PURE__ */ new Map();
|
package/lib/msm-ops.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export declare const MSM_ACTIONS: readonly MsmAction[];
|
|
|
19
19
|
export declare const ACC_CATALOG = "\u2550\u2550\u2550 ACC Usage Catalog \u2550\u2550\u2550\nDirectory of ACC capabilities \u2014 each area lists where to go for details (guides live with their feature; this catalog only points).\n\n \u2460 \u4F1A\u8BDD\u4E0E\u8F68\u8FF9 \u2192 session tool\uFF08list/show/create/use/close/health/qa/archive/summary/hook-develop-guide\uFF09\n session_rebuild\uFF08\u8D85\u9650\u91CD\u5EFA\uFF1B\u9608\u503C K \u89C1 ccc-config / \u8BBE\u7F6E\u9762\u677F\u91CD\u5EFA\u9608\u503CK\uFF09\n \u2461 \u8BA4\u77E5\u8D28\u91CF\u6846\u67B6 \u2192 eap\uFF08E\u2191/R\u2193/S\u2191\uFF09/ neat\uFF08Neat \u534F\u8BAE\uFF09/ cce\uFF08\u8BA4\u77E5\u8FDE\u7EED\u6027\u5DE5\u7A0B\uFF09\u2014\u2014\u6E10\u8FDB\u62AB\u9732\uFF0C\u65E0\u53C2\u5373\u5168\u6587\n \u2462 \u5DE5\u5177\u4E0E\u6267\u884C \u2192 cc_fs\uFF08\u6587\u4EF6\u7CFB\u7EDF 15 \u5B50\u547D\u4EE4\uFF09/ cc_git\uFF08git\uFF09/ acc_kit\uFF08health \u542B\u6CE8\u518C\u8868\u68C0\u67E5/time/wait\uFF09\n acc_msm\uFF08MSM \u6846\u67B6\uFF1A\u672C\u5DE5\u5177 list/exec/register/deregister/check/guide/ccc-config/catalog\uFF09\n handyman\uFF08\u6742\u5DE5 agent \u7F16\u6392\u2014\u2014guide \u5B50\u547D\u4EE4\uFF1Aacc_msm exec handyman guide\uFF09\n \u2463 \u89D2\u8272\u4E0E\u5BF9\u5916\u9762 \u2192 skiff_admin\uFF08Skiff \u8BA4\u77E5\u5B50\u96C6\u89D2\u8272\uFF1Aguide/validate/apply/list\u2014\u2014acc_msm exec skiff_admin guide\uFF09\n ACP\uFF08\u7A0B\u5E8F\u5316 JSON-RPC 3100\uFF09/ Skiff \u95EE\u7B54\u9875\uFF08\u516C\u7F51 ask\uFF09\u2014\u2014\u9762\u677F\u300C\u5916\u90E8\u80FD\u529B\u300D\u7EC4\n \u2464 \u81EA\u4E3B\u4E0E\u63A5\u5165 \u2192 autopilot-trajectory\uFF08Autopilot \u4E00\u7AD9\u5F0F\uFF1Aall/init/random/diag/doc/check/status/guide\uFF09\n weixin \u5FAE\u4FE1\u6865\uFF08\u914D\u7F6E/\u626B\u7801/\u8DEF\u7531/\u6D88\u606F hook\u2014\u2014CCC \u4FA7 weixin-doctor MSM\uFF1Aacc_msm exec weixin-doctor guide\uFF09\n \u2465 CCC \u914D\u7F6E\u603B\u89C8 \u2192 acc_msm ccc-config\uFF088 \u6BB5\uFF1Ahandyman/sessionKeeper/localstore/hooks/safeMode/skiff/autopilotTrajectory/weixin\uFF09\n \u2466 \u6CE8\u518C\u8868\u4E0E\u5B89\u5168 \u2192 mech-registry.json \u7531 acc_msm register/deregister \u7BA1\u7406\uFF08\u5199\u4FDD\u62A4\u2014\u2014\u4E0D\u53EF\u76F4\u63A5\u7F16\u8F91\uFF09\n acc_kit health \u8F93\u51FA registry \u5B8C\u6574\u6027\u68C0\u67E5\uFF1B\u635F\u574F\u6062\u590D\u6307\u5F15\u89C1 health registry.issues\n\n\u6BCF\u533A\uFF1A\u4E00\u53E5\u8BDD\u5B9A\u4F4D + \u8BE6\u7EC6\u5165\u53E3\uFF08\u5DE5\u5177\u540D / guide \u5B50\u547D\u4EE4\uFF09\u3002\u8BE6\u60C5\u6C38\u8FDC\u4EE5\u5BF9\u5E94\u5DE5\u5177\u7684 guide/ccc-config \u4E3A\u5355\u4E00\u771F\u76F8\u6E90\u3002\n";
|
|
20
20
|
export declare const MSM_GUIDE = "MSM Development Manual (Mech & Semi-Mech framework)\n\n## What it is\nMSM = the executable-unit layer. Mech is pure TS with zero LLM reasoning; Semi-Mech is a TS framework + LLM decision points.\nMSM is ACC's deterministic executable-unit layer \u2014 all shell/exec operations go through MSM and cannot be bypassed.\n\n## Registering a new MSM (acc_msm register)\n1. Write the script under <skill>/scripts/ (runnable via tsx; must include a main() CLI guard with an import.meta.url check)\n2. acc_msm register <name> --skill <s> --path <script path relative to root> --category <mech|semi-mech> --description <desc>\n3. Auto-writes mech-registry.json (preserving the original format) + git commit (commits only the registry file)\n4. Validation: path must be inside root, script must exist, name must be globally unique\n\n## flag schema (v1)\nflags is a new-style object array for parameter validation and path-escape guarding:\n [{\"name\":\"output\",\"type\":\"string\",\"description\":\"output path\"},\n {\"name\":\"target\",\"type\":\"path\",\"description\":\"operation target (type:path enables in-root validation + symlink defense)\"},\n {\"name\":\"force\",\"type\":\"boolean\",\"description\":\"force mode\",\"default\":false}]\n- {name, type} format \u2014 new style, type:\"path\" enables the path-escape guard\n- {flag, description} format \u2014 old style, CLI flag description string\n- On registration, flags are passed via acc_msm register --flags '<json>' (the tool currently parses the name style)\n\n## Script conventions\n- Top-of-file documentation: purpose / usage / exit codes\n- Exit codes: 0 success / 1 user / 2 system / 3 operator (per ACC protocol classification)\n- main() CLI guard (DC-M2): the script must start with\n if (import.meta.url === `file://${process.argv[1]}`) { main() }\n or an equivalent isMain / require.main === check \u2014 so vitest imports never trigger top-level code\n- A paired .test.ts or .spec.ts (DC-M1, vitest)\n- Business subprocess environment: SERENITY_ROOT / SERENITY_CCC / SERENITY_VERSION injected\n\n## Interaction & confirmation conventions (no blocking confirmation)\n- MSMs run in **user-less subprocesses** (spawn/execFile, 600s timeout) \u2014 **never** use\n readline / prompt / process.stdin etc. to block waiting for user input (it would hang until killed by the timeout)\n- When a second confirmation is needed: **directly return the confirmation request** (list the operation to perform and its impact + how to retry with the confirmation flag),\n returning a non-zero exit code (or an explicit hint)\n- After the agent confirms, **re-invoke the MSM with the confirmation flag** (e.g. --confirm / --yes / --force) to retry\n- Standard mode (two-phase):\n 1. First call: destructive/confirmation-requiring operation detected and no confirmation flag present \u2192 output the confirmation request (list operation/impact/rollback),\n exit non-zero (e.g. 1 user), **perform no changes**\n 2. After the agent evaluates, re-invoke: with the confirmation flag \u2192 execute and output the result\n- Applies to: delete/overwrite/push/batch operations and other irreversible or wide-impact operations\n- Anti-example (forbidden): readline waiting for user input, process.stdin.on('data') blocking waits\n (MSMs have no stdin interaction channel \u2014 they hang until the 600s timeout)\n\n## Quality checks (acc_msm check, DC-M1~M4)\nDC-M1 has .test.ts/.spec.ts; DC-M2 has a main() guard (function main( / isMain / require.main === / import.meta.url);\nDC-M3 bidirectional: scripts unregistered + registry references missing scripts; DC-M4 path-type flags marked type:\"path\"\n\n## Self-description (protocol flags, first argument only)\nacc_msm exec <name> --list \u2014 list all MSMs\nacc_msm exec <name> --schema <n> \u2014 view a specific MSM's parameter schema\nacc_msm exec <name> --format=json \u2014 JSON output mode (remaining args passed through losslessly)\n";
|
|
21
21
|
/** CCC 配置参考(对齐 osp ccc-config action) */
|
|
22
|
-
export declare const CCC_CONFIG_REFERENCE = "\u2550\u2550\u2550 CCC Configuration Reference \u2550\u2550\u2550\n\nCCC-level features are configured in .opencode/serenity.json.\nBelow are all available configuration sections.\n\n\u2500\u2500 1. handyman.models \u2500\u2500\nhandyman\uFF08\u6742\u5DE5\uFF09\u5DE5\u5177\u53EF\u7528\u6A21\u578B\u767D\u540D\u5355\uFF08provider/model \u5217\u8868\uFF09\uFF1B\u672A\u914D\u7F6E\u65F6 handyman \u62A5\u9519\u8981\u6C42\u914D\u7F6E\u3002\n\u7F3A\u7701\u6A21\u578B = models[0]\uFF08\u53EF\u7528 handyman.defaultModel \u6307\u5B9A\uFF0C\u5FC5\u987B \u2208 models\uFF09\u3002\n\n Config:\n { \"handyman\": { \"models\": [\"provider/model-name\"] } }\n\n Example:\n { \"handyman\": { \"models\": [\"minimax-cn-coding-plan/MiniMax-M3\"], \"defaultModel\": \"minimax-cn-coding-plan/MiniMax-M3\", \"maxRounds\": 100, \"maxParallel\": 10 } }\n\n\u2500\u2500 2. sessionKeeper.threshold \u2500\u2500\
|
|
22
|
+
export declare const CCC_CONFIG_REFERENCE = "\u2550\u2550\u2550 CCC Configuration Reference \u2550\u2550\u2550\n\nCCC-level features are configured in .opencode/serenity.json.\nBelow are all available configuration sections.\n\n\u2500\u2500 1. handyman.models \u2500\u2500\nhandyman\uFF08\u6742\u5DE5\uFF09\u5DE5\u5177\u53EF\u7528\u6A21\u578B\u767D\u540D\u5355\uFF08provider/model \u5217\u8868\uFF09\uFF1B\u672A\u914D\u7F6E\u65F6 handyman \u62A5\u9519\u8981\u6C42\u914D\u7F6E\u3002\n\u7F3A\u7701\u6A21\u578B = models[0]\uFF08\u53EF\u7528 handyman.defaultModel \u6307\u5B9A\uFF0C\u5FC5\u987B \u2208 models\uFF09\u3002\n\n Config:\n { \"handyman\": { \"models\": [\"provider/model-name\"] } }\n\n Example:\n { \"handyman\": { \"models\": [\"minimax-cn-coding-plan/MiniMax-M3\"], \"defaultModel\": \"minimax-cn-coding-plan/MiniMax-M3\", \"maxRounds\": 100, \"maxParallel\": 10 } }\n\n\u2500\u2500 2. sessionKeeper.threshold \u2500\u2500\ntrajectory-assistant\uFF08TRAJECTORY-ASSISTANT \u00B7 CHECKPOINT\uFF09\u63D0\u9192\u673A\u5236\u7684\u79EF\u5206\u9608\u503C\uFF08\u975E headless \u4E3B agent\uFF09\u3002\n\u6309\u5DE5\u5177\u8C03\u7528\u52A0\u6743 + \u8017\u65F6\u8BA1\u5206\uFF1B\u8FBE\u5230\u9608\u503C\u6CE8\u5165\u63D0\u9192\uFF0C\u8981\u6C42\u6A21\u578B\u56DE\u590D ACK \u7801\u3002\n\n Config:\n { \"sessionKeeper\": { \"threshold\": 150 } }\n\n \u8BA1\u5206\uFF1Awrite/edit = 3\uFF0Ctask = 10\uFF0Cread/grep/glob/msm \u7B49 = 1\uFF0C\u65F6\u95F4 = 1/\u5206\u949F\n \u9ED8\u8BA4\uFF1A150\n\n\u2500\u2500 3. localstore.gitTrack \u2500\u2500\nlocalstore.json \u7684 git \u7B56\u7565\uFF1Aallow \u53EF\u63D0\u4EA4 / deny \u7981\u63D0\u4EA4\uFF08\u9ED8\u8BA4 deny\uFF09\u3002\ndeny \u65F6\u5199\u5165\u81EA\u52A8\u786E\u4FDD .gitignore \u542B\u8BE5\u6587\u4EF6\uFF08\u7269\u7406\u4FDD\u8BC1\uFF09\uFF0Ccc_git commit \u4F1A\u68C0\u67E5\u62D2\u7EDD\u3002\n\n Config:\n { \"localstore\": { \"gitTrack\": \"allow\" } }\n\n\u2500\u2500 4. hooks.autoRestoreSession \u2500\u2500\n\u4F1A\u8BDD\u81EA\u52A8\u6062\u590D\uFF08\u9ED8\u8BA4 true\uFF1B\u53D7 events \u95E8\u63A7\u2014\u2014\u4EC5\u6839\u4F1A\u8BDD + \u5DF2\u6709\u5BF9\u8BDD\u5386\u53F2\u624D\u6062\u590D\uFF09\u3002\n\n Config:\n { \"hooks\": { \"autoRestoreSession\": false } }\n\n\u2500\u2500 5. safeMode / blacklist \u2500\u2500\nsafe-mode \u7531 WebUI \u5F00\u5173\u63A7\u5236\uFF08\u5199 .serenity-safe-on \u6807\u8BB0\uFF09\uFF1B\u9ED1\u540D\u5355\u8DEF\u5F84\u53D7 guards seam \u62E6\u622A\u3002\n\n Config:\n { \"safeMode\": { \"blacklist\": [\".secrets/\"] } }\n\n\u2500\u2500 6. skiff.roles\uFF08F4 \u8BA4\u77E5\u5B50\u96C6\u89D2\u8272\uFF09\u2500\u2500\nSkiff \u89D2\u8272 = \u5168\u77E5\u5168\u80FD trajectory \u7684\u4EFB\u610F\u5B50\u96C6\uFF08CCC \u5B9A\u4E49\uFF09\u3002\u6BCF\u89D2\u8272\u72EC\u7ACB\u6A21\u578B + \u53CC\u767D\u540D\u5355\n\uFF08MSM \u767D\u540D\u5355 msms[] \u4E0E\u975E MSM \u5DE5\u5177\u767D\u540D\u5355 tools[]\uFF0C\u767D\u540D\u5355\u5916\u5168\u9690\u85CF\uFF1Bskill \u52A0\u8F7D\u6052\u53EF\u7528\uFF09\u3002\ntrajectory \u7EAA\u5F8B\u5B50\u96C6\uFF08session/keeper/rebuild \u53C2\u4E0E\u9879\uFF09\u9ED8\u8BA4\u5168\u5173 = \u5B8C\u5168\u72EC\u7ACB\u3002\nsystemPrompt \u5185\u8054 \u6216 systemPromptFile\uFF08.md \u5F15\u7528\uFF0C\u63A8\u8350\uFF09\u2014\u2014\u89D2\u8272\u4F1A\u8BDD\u7684\u5B8C\u6574\u4EBA\u683C/\u8FB9\u754C\u63D0\u793A\u8BCD\u3002\nvalidate \u6821\u9A8C / apply \u751F\u6548 / list \u67E5\u770B\uFF1Aacc_msm exec skiff_admin <guide|validate|apply|list>\u3002\n\n Config:\n { \"skiff\": { \"roles\": {\n \"qa\": {\n \"model\": \"provider/model\",\n \"msms\": [\"web-search\", \"vlm-describe\"],\n \"tools\": [\"read\", \"grep\", \"glob\"],\n \"systemPromptFile\": \".opencode/skiff/qa.md\"\n } } } }\n\n\u2500\u2500 7. autopilotTrajectory\uFF08\u81EA\u52A8\u5DE1\u822A\u8F68\u8FF9\uFF09\u2500\u2500\nCCC \u5B9A\u4E49\u7684\u4E00\u6761\u81EA\u4E3B trajectory\u2014\u2014\u65F6\u949F\u5230\u70B9\u81EA\u52A8\u5524\u8D77\uFF08\u524D\u53F0\u6CE8\u5165\uFF0C\u7528\u6237\u53EF\u89C1\u53EF\u4ECB\u5165\uFF09\u3002\n\u672A\u914D\u7F6E\u6216 enabled=false \u2192 \u5B8C\u5168\u4E0D\u542F\u52A8\uFF08\u96F6\u8D44\u6E90\u5360\u7528\uFF09\u3002\u591A CCC \u72EC\u7ACB\uFF1A\u6BCF CCC \u81EA\u5DF1\u7684\u914D\u7F6E\u3002\n\u5524\u8D77\u6D88\u606F\u56DB\u6BB5\u5F0F\uFF1A\u8F68\u8FF9\u7126\u70B9 topPrompt\uFF08\u6700\u5148\u6CE8\u5165\uFF0C\u7A33\u5B9A\u951A\uFF09\u2192 \u8EAB\u4EFD\u951A\u5B9A \u2192 \u5148\u9A8C\u504F\u89C1\n\uFF08CCC \u6839\u811A\u672C biasProvider \u8F93\u51FA\uFF09\u2192 \u4EFB\u52A1\u3002\u76EE\u6807\u4F1A\u8BDD session \u5FC5\u586B\uFF08\u76EE\u5F55\u987B\u5E26 --auto \u540E\u7F00\uFF09\u3002\n\u8BCA\u65AD/\u72B6\u6001/\u7ACB\u5373\u5524\u8D77\uFF1Aacc_msm exec autopilot-trajectory <all|check|status|diag>\u3002\n\n Config:\n { \"autopilotTrajectory\": {\n \"enabled\": true,\n \"intervalHours\": 2,\n \"session\": \"S151\",\n \"biasProvider\": \"autopilot-bias.ts\",\n \"topPrompt\": \"\u672C\u8F68\u8FF9\u6838\u5FC3\u76EE\u6807/\u7EAA\u5F8B/\u8D28\u91CF\u8981\u6C42\uFF08CCC \u81EA\u586B\uFF0C\u9632\u6F02\u79FB\uFF09\",\n \"avoidWakeHours\": { \"start\": 8, \"end\": 18 }\n } }\n\n\u2500\u2500 8. weixin\uFF08\u5FAE\u4FE1\u6865 F4c-3\uFF0C\u542B\u6D88\u606F\u8BB0\u5F55 hook\uFF09\u2500\u2500\nCCC \u7EA7\u5FAE\u4FE1\u4E2A\u4EBA\u53F7\u63A5\u5165\uFF08iLink \u534F\u8BAE\uFF09\uFF1Adsh \u4E00\u8FDB\u7A0B\u591A CCC\uFF0C\u6BCF CCC \u72EC\u7ACB\u5BF9\u63A5\u5FAE\u4FE1\u6865\u3002\n\u8D26\u53F7/\u8DEF\u7531/\u5F00\u5173\u5728\u6B64\u6587\u4EF6\uFF1B**bot_token \u51ED\u636E\u5728 CCC localstore credential scope**\n\uFF08\u626B\u7801\u7ED1\u5B9A\u540E\u81EA\u52A8\u5199\u5165\uFF0C\u6C38\u4E0D\u8FDB git \u660E\u6587\u9762\uFF09\u3002\n\u8DEF\u7531 user \u2192 role\uFF1Aexact \u4F18\u5148\uFF0C* \u901A\u914D\u515C\u5E95\uFF1Brole \u5FC5\u987B \u2208 \u8BE5 CCC skiff.roles\u3002\n\u9762\u677F\uFF08WebUI \u8BBE\u7F6E \u2192 \u5FAE\u4FE1\u6865\uFF09\u53EF\u626B\u7801\u7ED1\u5B9A/\u79FB\u9664\u8D26\u53F7/\u7F16\u8F91\u8DEF\u7531\uFF1Bacc_msm exec weixin-doctor\n<status|diag|verify> \u6392\u67E5\u3002\u51ED\u636E\u4E3B\u52A8\u67E5\u770B\uFF1Alocalstore get WEIXIN_<ACCOUNT>_TOKEN\u3002\n\n Config:\n { \"weixin\": {\n \"enabled\": true,\n \"hook\": \"scripts/weixin-message-hook.ts\",\n \"accounts\": [{ \"accountId\": \"wechat-1\", \"name\": \"\u5BB6\u5EAD\u52A9\u624B\", \"enabled\": true }],\n \"routes\": [{ \"user\": \"*\", \"role\": \"zhaocai\" }]\n } }\n\n \u25B8 weixin.hook\uFF08\u6D88\u606F\u8BB0\u5F55 hook\uFF0Cv1.27.13\uFF09\uFF1A\n \u5FAE\u4FE1\u6865\u6BCF\u6536/\u53D1\u4E00\u6761\u6D88\u606F\u89E6\u53D1\u4E00\u6B21 CCC \u81EA\u5199\u811A\u672C\uFF0C\u7531 CCC \u81EA\u884C\u6301\u4E45\u5316\u4FDD\u5B58\uFF08\u5B58\u54EA/\u5B58\u6210\u4EC0\u4E48\n /\u662F\u5426\u5165\u5E93\u5168\u5F52 CCC\u2014\u2014ACC \u4E0D\u7ED1\u5B9A\u5B58\u50A8\uFF09\u3002\u672A\u914D\u7F6E hook \u2192 \u96F6\u53D8\u5316\uFF08\u4E0D\u89E6\u53D1\uFF09\u3002\n\n \u89E6\u53D1\uFF08\u53CC\u5411\uFF09\uFF1A\n incoming = \u7528\u6237 \u2192 bot\uFF1A\u8DEF\u7531\u547D\u4E2D\u540E\u3001\u5A92\u4F53\u843D\u76D8\u540E\u89E6\u53D1\uFF08\u6587\u672C\u542B\u8BED\u97F3\u8F6C\u5199\uFF1B\u5A92\u4F53\u5E26\u843D\u76D8 relPath\uFF09\n outgoing = bot \u2192 \u7528\u6237\uFF1A\u56DE\u590D\u53D1\u9001\u6210\u529F\u540E\u89E6\u53D1\uFF08reply = \u7528\u6237\u5B9E\u9645\u6536\u5230\u7684\u7EAF\u6587\u672C\uFF0C\u5DF2\u5265\u79BB think\uFF09\n\n \u811A\u672C\u7EA6\u5B9A\uFF08\u4E8B\u4EF6 JSON \u5355\u884C\u7ECF stdin \u4F20\u5165\uFF1Bbun \u4F18\u5148 node \u515C\u5E95\uFF09\uFF1A\n #!/usr/bin/env bun \u6216 node script.js \u2014\u2014 \u8BFB process.stdin \u6574\u6BB5 JSON.parse\n const ev = JSON.parse(await new Response(process.stdin).text())\n ev.event === 'incoming' | 'outgoing'\n\n \u4E8B\u4EF6 schema\uFF08**\u4E0D\u542B\u4EFB\u4F55\u4F1A\u8BDD\u51ED\u636E**\u2014\u2014context_token/bot_token/token/aes_key \u5747\u4E0D\u51FA\u73B0\uFF09\uFF1A\n { \"event\": \"incoming\", \"ts\": 1788359941488, \"cccRoot\": \"/path/ccc\",\n \"accountId\": \"wechat-1\", \"userId\": \"u1@im.wechat\",\n \"sessionId\": \"skiff-weixin-xxx\", \"role\": \"zhaocai\",\n \"message\": { \"text\": \"\u4F60\u597D\", \"media\": [{ \"kind\": \"image\", \"relPath\": \"_tmp/weixin-inbound/<hash>/img_x.jpg\" }] } }\n { \"event\": \"outgoing\", \"ts\": ..., \"cccRoot\": ..., \"accountId\": ...,\n \"userId\": ..., \"sessionId\": ..., \"role\": ...,\n \"reply\": \"\u5DF2\u8BB0\u5F55\uFF08\u7EAF\u6587\u672C\uFF09\" }\n\n \u793A\u4F8B\u811A\u672C\uFF08\u8FFD\u52A0\u5230\u6309\u65E5\u6587\u4EF6\u2014\u2014\u6301\u4E45\u5316\u5F52 CCC \u81EA\u9009\uFF1A\u6587\u4EF6/DB/\u8FDC\u7AEF\u5747\u53EF\uFF09\uFF1A\n const fs = require('node:fs'); const p = '/path/ccc/AGENT_SESSIONS/_weixin-log.jsonl';\n fs.appendFileSync(p, JSON.stringify(ev) + '\\n');\n\n \u6267\u884C\u8BED\u4E49\uFF08\u65C1\u8DEF\u5BB9\u5FCD\uFF09\uFF1A\u5F02\u6B65 fire-and-forget + 15s \u8D85\u65F6 kill + \u5931\u8D25\u4EC5\u65E5\u5FD7\u2014\u2014\n \u5FAE\u4FE1\u6865\u6D88\u606F\u5904\u7406/\u56DE\u590D\u4E0D\u53D7 hook \u5F71\u54CD\uFF1B\u811A\u672C\u987B\u5728 CCC \u6839\u5185\uFF08\u8DEF\u5F84\u9003\u9038\u62D2\u7EDD\uFF09\u3002\n \u5A92\u4F53 relPath \u6307\u5411 _tmp/weixin-inbound/\uFF08\u4E34\u65F6\u76EE\u5F55\uFF09\u2014\u2014\u9700\u6301\u4E45\u4FDD\u5B58\u5A92\u4F53\u6587\u4EF6\u8BF7\u81EA\u884C copy\u3002\n";
|
|
23
23
|
export interface MsmFlag {
|
|
24
24
|
name: string;
|
|
25
25
|
type?: string;
|
package/lib/seams/keeper.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* 计分(对齐 opencode-serenity-plugin session-keeper):
|
|
8
8
|
* write/edit=3, task=10, read/grep/glob/msm=1, 经过时间 +1 分/分钟
|
|
9
9
|
* 阈值:.opencode/serenity.json sessionKeeper.threshold(规范位置,.dsh 回退;缺省 150)
|
|
10
|
-
* 提醒要求模型回应 [
|
|
10
|
+
* 提醒要求模型回应 [TRAJECTORY-ASSISTANT-recorded-{code}] 确认(DCP 模式)。
|
|
11
11
|
*/
|
|
12
12
|
import type { Context } from 'cordis';
|
|
13
13
|
export declare function scoreTool(toolName: string): number;
|
|
@@ -61,10 +61,13 @@ export declare function personaBlock(mode: string, overrideText: string): string
|
|
|
61
61
|
*/
|
|
62
62
|
export declare function eapBlock(): string;
|
|
63
63
|
/**
|
|
64
|
-
* Metaphor 强化块(v1.19.6,S142
|
|
64
|
+
* Metaphor 强化块(v1.19.6,S142;v1.29 星舰意象升级,S142 用户拍板):
|
|
65
|
+
* 宁静号宇宙隐喻域(星舰/深空/航程/船员)。海船→星舰意象:one starship, one voyage;
|
|
66
|
+
* deep space / launch / docking clamp;Departure Inspection(原 Harbor Inspection)。
|
|
65
67
|
* 隐喻是记忆钩子——形象唤起约束,前述块保持规则精确。每条隐喻 = 一个不可违背的
|
|
66
68
|
* 物理事实 + 行为判据(verdict)。全英文(与 CCE/Constraints 一致);独立块可
|
|
67
69
|
* 回退;无 osp 对应(dsp 扩展,不进对齐断言参照)。
|
|
70
|
+
* 结构约束(docs/metaphor-domain.md M-1~M-4):三层骨架不变 + 每条映射约束不变。
|
|
68
71
|
*/
|
|
69
72
|
export declare function metaphorBlock(): string;
|
|
70
73
|
/**
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { existsSync, readdirSync, rmSync, statSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
//#region src/session-cleanup.ts
|
|
4
|
+
/**
|
|
5
|
+
* session-cleanup.ts — DSH 平台旧会话自动清理(v1.29,S142 需求③)
|
|
6
|
+
*
|
|
7
|
+
* 背景(实证):DSH 会话物理存储 = `$DSH_HOME/sessions/`(缺省 ~/.dsh/sessions;
|
|
8
|
+
* base bundle cordis.patch.yml root: dshHomePath('sessions'))。磁盘布局:
|
|
9
|
+
* <root>/--<project-slug>--/<encoded-session-id>/session.jsonl(.zstd)
|
|
10
|
+
* DSH **无删除会话 API**(PersistenceCoordinator 仅 create/append/load/inspect/borrow,
|
|
11
|
+
* 无 delete/purge;workspace archiveSession 只加归档集不删文件)——物理删除只能直接
|
|
12
|
+
* 删文件。删除后一致性(利好):sessionPersistence.list() = readdir 扫描磁盘现存 →
|
|
13
|
+
* 物理删后 list 不再返回;WorkspaceRegistry 下次启动重建 header index 自动消失。
|
|
14
|
+
*
|
|
15
|
+
* 方案(S142 用户拍板):lastActive 基准 + 手动触发 + 不过滤不归档直接物理删;
|
|
16
|
+
* 安全底线 = live 会话保护跳过(删正在运行的会话 = 灾难)。
|
|
17
|
+
*
|
|
18
|
+
* 本模块纯逻辑(零 ctx 依赖):传入 sessionsRoot + liveIds,可单测。
|
|
19
|
+
*/
|
|
20
|
+
/** DSH 会话 root:env DSH_HOME → ~/.dsh(config-ops globalConfigPath 同款推导) */
|
|
21
|
+
function sessionsRootDir() {
|
|
22
|
+
const dshHome = process.env.DSH_HOME ?? join(process.env.HOME ?? "", ".dsh");
|
|
23
|
+
return join(dshHome, "sessions");
|
|
24
|
+
}
|
|
25
|
+
/** 一天的毫秒数 */
|
|
26
|
+
const DAY_MS = 864e5;
|
|
27
|
+
/**
|
|
28
|
+
* 扫描 sessions root,列出可清理候选:
|
|
29
|
+
* - 递归 `<root>/<project>/<session-id>/session.jsonl(.zstd)`(任意深度下找 *session* 文件)
|
|
30
|
+
* - 过滤 live(liveIds 集合)——安全底线
|
|
31
|
+
* - 过滤 lastActive >= cutoffMs(最后活动未达阈值 → 保留)
|
|
32
|
+
* root 不存在/为空 → 返回 [](非错误)。
|
|
33
|
+
*/
|
|
34
|
+
function collectEligibleSessions(root, cutoffMs, liveIds = /* @__PURE__ */ new Set()) {
|
|
35
|
+
if (!existsSync(root)) return [];
|
|
36
|
+
const out = [];
|
|
37
|
+
for (const project of readdirSync(root, { withFileTypes: true })) {
|
|
38
|
+
if (!project.isDirectory()) continue;
|
|
39
|
+
const projectPath = join(root, project.name);
|
|
40
|
+
for (const entry of readdirSync(projectPath, { withFileTypes: true })) {
|
|
41
|
+
if (!entry.isDirectory()) continue;
|
|
42
|
+
const log = findSessionLog(join(projectPath, entry.name));
|
|
43
|
+
if (log === null) continue;
|
|
44
|
+
if (liveIds.has(entry.name)) continue;
|
|
45
|
+
let mtime;
|
|
46
|
+
try {
|
|
47
|
+
mtime = statSync(log).mtimeMs;
|
|
48
|
+
} catch {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (mtime >= cutoffMs) continue;
|
|
52
|
+
out.push({
|
|
53
|
+
id: entry.name,
|
|
54
|
+
project: project.name,
|
|
55
|
+
logPath: log,
|
|
56
|
+
lastActiveMs: mtime
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
/** 在会话目录下找 session 日志文件(.jsonl / .jsonl.zstd);无 → null */
|
|
63
|
+
function findSessionLog(sessionDirPath) {
|
|
64
|
+
for (const name of ["session.jsonl", "session.jsonl.zstd"]) {
|
|
65
|
+
const p = join(sessionDirPath, name);
|
|
66
|
+
if (existsSync(p)) return p;
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* 执行清理(用户拍板:直接物理删,不过滤不归档;dryRun 预览不删)。
|
|
72
|
+
* 删除 = rmSync 整个会话目录(recursive + force)。失败逐个记 errors 不中断。
|
|
73
|
+
*/
|
|
74
|
+
function performCleanup(root, cutoffMs, liveIds = /* @__PURE__ */ new Set(), opts = {}) {
|
|
75
|
+
const candidates = collectEligibleSessions(root, cutoffMs, liveIds);
|
|
76
|
+
if (opts.dryRun) return {
|
|
77
|
+
candidates,
|
|
78
|
+
result: null
|
|
79
|
+
};
|
|
80
|
+
const result = {
|
|
81
|
+
deleted: [],
|
|
82
|
+
errors: []
|
|
83
|
+
};
|
|
84
|
+
for (const c of candidates) {
|
|
85
|
+
const dir = dirOf(c.logPath);
|
|
86
|
+
try {
|
|
87
|
+
rmSync(dir, {
|
|
88
|
+
recursive: true,
|
|
89
|
+
force: true
|
|
90
|
+
});
|
|
91
|
+
result.deleted.push(c.id);
|
|
92
|
+
} catch (e) {
|
|
93
|
+
result.errors.push({
|
|
94
|
+
id: c.id,
|
|
95
|
+
reason: e.message
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
candidates,
|
|
101
|
+
result
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/** 从日志路径取会话目录(父目录) */
|
|
105
|
+
function dirOf(logPath) {
|
|
106
|
+
return logPath.slice(0, logPath.lastIndexOf("/")) || logPath;
|
|
107
|
+
}
|
|
108
|
+
/** 便捷:默认 N 天前为 cutoff(供 API/调用方) */
|
|
109
|
+
function cutoffDaysAgo(days, nowMs = Date.now()) {
|
|
110
|
+
return nowMs - days * DAY_MS;
|
|
111
|
+
}
|
|
112
|
+
//#endregion
|
|
113
|
+
export { cutoffDaysAgo, performCleanup, sessionsRootDir };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* session-cleanup.ts — DSH 平台旧会话自动清理(v1.29,S142 需求③)
|
|
3
|
+
*
|
|
4
|
+
* 背景(实证):DSH 会话物理存储 = `$DSH_HOME/sessions/`(缺省 ~/.dsh/sessions;
|
|
5
|
+
* base bundle cordis.patch.yml root: dshHomePath('sessions'))。磁盘布局:
|
|
6
|
+
* <root>/--<project-slug>--/<encoded-session-id>/session.jsonl(.zstd)
|
|
7
|
+
* DSH **无删除会话 API**(PersistenceCoordinator 仅 create/append/load/inspect/borrow,
|
|
8
|
+
* 无 delete/purge;workspace archiveSession 只加归档集不删文件)——物理删除只能直接
|
|
9
|
+
* 删文件。删除后一致性(利好):sessionPersistence.list() = readdir 扫描磁盘现存 →
|
|
10
|
+
* 物理删后 list 不再返回;WorkspaceRegistry 下次启动重建 header index 自动消失。
|
|
11
|
+
*
|
|
12
|
+
* 方案(S142 用户拍板):lastActive 基准 + 手动触发 + 不过滤不归档直接物理删;
|
|
13
|
+
* 安全底线 = live 会话保护跳过(删正在运行的会话 = 灾难)。
|
|
14
|
+
*
|
|
15
|
+
* 本模块纯逻辑(零 ctx 依赖):传入 sessionsRoot + liveIds,可单测。
|
|
16
|
+
*/
|
|
17
|
+
/** DSH 会话 root:env DSH_HOME → ~/.dsh(config-ops globalConfigPath 同款推导) */
|
|
18
|
+
export declare function sessionsRootDir(): string;
|
|
19
|
+
/** 一个候选会话(删除前预览信息) */
|
|
20
|
+
export interface CandidateSession {
|
|
21
|
+
/** 会话 id(目录名) */
|
|
22
|
+
id: string;
|
|
23
|
+
/** 项目目录(父目录名,如 --home-yh-home-home-serenity--) */
|
|
24
|
+
project: string;
|
|
25
|
+
/** 会话日志文件绝对路径 */
|
|
26
|
+
logPath: string;
|
|
27
|
+
/** 最后活动(mtime 退化——日志只追加,mtime ≈ 最后写) */
|
|
28
|
+
lastActiveMs: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 扫描 sessions root,列出可清理候选:
|
|
32
|
+
* - 递归 `<root>/<project>/<session-id>/session.jsonl(.zstd)`(任意深度下找 *session* 文件)
|
|
33
|
+
* - 过滤 live(liveIds 集合)——安全底线
|
|
34
|
+
* - 过滤 lastActive >= cutoffMs(最后活动未达阈值 → 保留)
|
|
35
|
+
* root 不存在/为空 → 返回 [](非错误)。
|
|
36
|
+
*/
|
|
37
|
+
export declare function collectEligibleSessions(root: string, cutoffMs: number, liveIds?: ReadonlySet<string>): CandidateSession[];
|
|
38
|
+
/** 在会话目录下找 session 日志文件(.jsonl / .jsonl.zstd);无 → null */
|
|
39
|
+
export declare function findSessionLog(sessionDirPath: string): string | null;
|
|
40
|
+
/** 删除执行结果 */
|
|
41
|
+
export interface CleanupResult {
|
|
42
|
+
deleted: string[];
|
|
43
|
+
/** 尝试删除但失败的会话目录(权限/竞态) */
|
|
44
|
+
errors: Array<{
|
|
45
|
+
id: string;
|
|
46
|
+
reason: string;
|
|
47
|
+
}>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 执行清理(用户拍板:直接物理删,不过滤不归档;dryRun 预览不删)。
|
|
51
|
+
* 删除 = rmSync 整个会话目录(recursive + force)。失败逐个记 errors 不中断。
|
|
52
|
+
*/
|
|
53
|
+
export declare function performCleanup(root: string, cutoffMs: number, liveIds?: ReadonlySet<string>, opts?: {
|
|
54
|
+
dryRun?: boolean;
|
|
55
|
+
}): {
|
|
56
|
+
candidates: CandidateSession[];
|
|
57
|
+
result: CleanupResult | null;
|
|
58
|
+
};
|
|
59
|
+
/** 便捷:默认 N 天前为 cutoff(供 API/调用方) */
|
|
60
|
+
export declare function cutoffDaysAgo(days: number, nowMs?: number): number;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* trajectory-assistant.ts — 关卡化注入的统一命名与风格门面(v0.3,S142)
|
|
3
|
+
*
|
|
4
|
+
* 概念(用户拍板 2026-09-05):dsp 全部"过程中动态提示注入"统一命名为
|
|
5
|
+
* trajectory-assistant(轨迹助航员)。关卡设计思想塑造**结构与时机**
|
|
6
|
+
* (何时/何地注入),**不用于提示词用词**(D8 词法原则)——纯游戏黑话
|
|
7
|
+
* (BOSS/XP/level-up)禁止出现在提示词文本;CHECKPOINT/LIMIT/TUTORIAL 等
|
|
8
|
+
* 跨领域自然通用词允许。
|
|
9
|
+
*
|
|
10
|
+
* 本模块 = token 常量 + level-event 词汇表的**单一真相源**(避免前缀散落
|
|
11
|
+
* 各文件字符串字面量)+ 风格门面(plain 默认 / metaphor 星舰变体)。
|
|
12
|
+
* 仅当 style=metaphor 时前缀包装措辞变化;可行动正文不变 → 零行为漂移。
|
|
13
|
+
*
|
|
14
|
+
* 设计简写(L0 环境 / L1 教程 / L2 目标 / L3 检查点 / L4 极限 / L5 守卫 /
|
|
15
|
+
* L6 结算)仅在本模块注释与内部文档出现,永不浮现在提示词文本。
|
|
16
|
+
*
|
|
17
|
+
* 结算(settlement)挂点:D6 用户拍板——若 CCC 有标准 SESSION 复盘仪式,
|
|
18
|
+
* 结算视图归 trajectory-assistant。当前 close/archive 无复盘摘要 → 机制
|
|
19
|
+
* 延后,仅留 onSettlement 导出 seam(OP-1,无调用者)。
|
|
20
|
+
*/
|
|
21
|
+
/** 可见提示词前缀用词(跨领域自然词,D8:无游戏黑话) */
|
|
22
|
+
export declare const EVENT_LABEL: {
|
|
23
|
+
/** 计分同步提醒(原 TRAJECTORY-STEWARD) */
|
|
24
|
+
readonly checkpoint: "CHECKPOINT";
|
|
25
|
+
/** 上下文极限重建提醒(原 TRAJECTORY;LIMIT 替代被否的 BOSS——自然词) */
|
|
26
|
+
readonly limit: "LIMIT";
|
|
27
|
+
/** 极限强制升级(原 TRAJECTORY-ESCALATED) */
|
|
28
|
+
readonly limitMandatory: "LIMIT · MANDATORY";
|
|
29
|
+
/** 重建锚点头部(原 TRAJECTORY-REBUILD) */
|
|
30
|
+
readonly rebuild: "REBUILD";
|
|
31
|
+
/** 敏感输出边界守卫(原 SERENITY OUTPUT GUARD) */
|
|
32
|
+
readonly guard: "BOUNDARY GUARD";
|
|
33
|
+
};
|
|
34
|
+
/** 家族标识(所有动态注入统一前缀) */
|
|
35
|
+
export declare const ASSISTANT_PREFIX = "TRAJECTORY-ASSISTANT";
|
|
36
|
+
/** 完整 token:`[TRAJECTORY-ASSISTANT · <LABEL>]` */
|
|
37
|
+
export declare function eventToken(event: keyof typeof EVENT_LABEL): string;
|
|
38
|
+
/** ACK 确认码前缀(recorded/skipped 语义不变,仅家族名更新) */
|
|
39
|
+
export declare const ACK_PREFIX = "TRAJECTORY-ASSISTANT-recorded";
|
|
40
|
+
export declare const ACK_SKIP_PREFIX = "TRAJECTORY-ASSISTANT-skipped";
|
|
41
|
+
/** 风格档位:plain(默认,精确文本)/ metaphor(借星舰词——产品隐喻非游戏词) */
|
|
42
|
+
export type TrajectoryStyle = 'plain' | 'metaphor';
|
|
43
|
+
/**
|
|
44
|
+
* 按风格生成前缀 token。plain = eventToken()(原样);metaphor 仅当有
|
|
45
|
+
* 星舰化变体时替换用词(当前等价保留——星舰词库隐喻域的既有措辞即
|
|
46
|
+
* "context limit/deck check" 类,不强制替换;扩展点留给未来实验)。
|
|
47
|
+
*/
|
|
48
|
+
export declare function styledToken(event: keyof typeof EVENT_LABEL, style?: TrajectoryStyle): string;
|
|
49
|
+
/**
|
|
50
|
+
* 结算 seam(OP-1/D6):未来标准 SESSION 复盘仪式接入点。当前无调用者,
|
|
51
|
+
* 仅导出契约:onSettlement(cb) 在"工作完成且被用户认可"时触发——该信号
|
|
52
|
+
* 尚无可靠自动检测(D2 用户拍板记录为未解问题),实现留待仪式落地。
|
|
53
|
+
*/
|
|
54
|
+
export declare function onSettlement(_cb: (sessionId: string) => void): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shgroup/dsh-serenity-hooks",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.29.0",
|
|
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": {
|