@shgroup/dsh-serenity-hooks 1.79.4 → 1.79.5
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/index.js +110 -103
- package/lib/{message-source-DK2CnXlh.js → message-source-DiP3Uve3.js} +35 -8
- package/lib/{session-BYC1uWi0.js → session-tdlJDS9i.js} +1 -1
- package/lib/trajectory/bind-file.d.ts +7 -1
- package/lib/trajectory/bound.d.ts +26 -2
- 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.79.
|
|
3
|
+
"version": "1.79.5",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"description": "宁静号 ACC harness(Native Cordis 插件):给 DSH 装一个「AI 工作区」——14 个工具(container_fs/cognitive_trajectory/dashboard/container_git/msm/praxis/ontology/serenity-skill-creator/cheap-worker/localstore/container_admin;另三个 im-bridge/acc-diag/diagram 按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫)+ 认知轨迹日志与原地重建 + 网页登录入口/IM 桥/认知轨迹唤醒注册表。轨迹声明 = 轨迹目录下的 trajectory.json(约束面 + 旧标识 uid + CRO 机器绑定 cro.host;旧名 trajectory-constraint.json / skiff.json 仍在读取族里);轨迹提示词 = 轨迹目录下的 PROMPT.md(一条轨迹「是谁、按什么章程工作」,所有轨迹通用,追加在容器层与质量层之后,不替换它们)。适配 DSH 0.1.7-rc.1 / 0.2.0-rc.1 / 0.2.1-rc.1(三档,deepseek-ai/deepseek-harness)。",
|
|
6
6
|
"engines": {
|
package/lib/index.js
CHANGED
|
@@ -3,8 +3,8 @@ import { c as hostInjected, d as hostSessions, f as hostSettings, h as hostWebSe
|
|
|
3
3
|
import { _ as resolveInside, a as findSerenityRoot$1, c as matchBlacklist, d as readCccName$1, f as readCheapWorkerConfig, h as readSafeModeHiddenTools, i as findGitRoot, l as pathInside, m as readExclusiveTools, n as SAFE_MODE_MARKER, o as isSafeModeOn, r as classifyPath, s as loadSerenityConfig, t as DEFAULT_SERENITY_CONFIG_PATHS, u as readBlacklist } from "./ccc-CyYJL4F2.js";
|
|
4
4
|
import { A as sessionEvents, B as isoLocal, C as listSessions, E as parseTrajectoryCode, F as trajectoryDescOf, H as localHuman, I as useSession, L as TRAJECTORY_FILENAME, M as setActiveSessionInfo, N as showSession, O as readTrajectoryUid, P as summarize, R as TRAJECTORY_LEGACY_FILENAMES, S as listActiveTrajectories, T as parseSessionContextFromEvents, U as localIdStamp, V as localFileStamp, _ as createSession, a as readTrajectoryConstraintAt, b as getActiveSessionInfo, c as trajectoryConstraintForSession, f as COGNITIVE_TRAJECTORY_ACTIONS, g as clearActiveSessionInfo, h as archiveSession, j as sessionsRoot, k as resolveSessionByTitle, m as UID_FILENAME, n as isTrajectoryConstrained, o as readTrajectoryConstraintByCode, r as listTrajectoryConstraints, s as replacesDefaultIdentity, t as TRAJECTORY_CONSTRAINT_FILENAME, v as extractSessionMdPathFromText, w as namingTitleFor, y as findSession, z as readTrajectoryFile } from "./profile-5TQ_C1xi.js";
|
|
5
5
|
import { n as checkLocalstoreGitCompliance, o as readStore, s as runLocalStore, t as LOCALSTORE_SCOPES } from "./service-DDmHSglV.js";
|
|
6
|
-
import { _ as ACC_VERSION, a as listBoundSessionIds, d as constraintCognitiveTrajectory, f as constraintSystemPromptSource, g as resolveConstraintSystemPrompt, h as profileToolWhitelist, i as carrierState, l as TRAJECTORY_CONSTRAINT_HINT, n as PLUGIN_SOURCE, o as readLastBound, r as appendBound, s as resolveSessionCognitiveTrajectoryLabel, t as ACC_MESSAGE_KIND, v as findPackageRoot } from "./message-source-
|
|
7
|
-
import { A as buildResourceIndex, C as verifyPassword, D as recordToolUsage, E as verifyTotpCode, F as hasTrajectoryPrompt, M as isSafeSkillName, N as truncateContent, O as REFERENCE_DIR, P as TRAJECTORY_PROMPT_FILENAME, S as toWire, T as MECHANISM_PORTS, _ as registerEntrySkillSectionGlobal, a as trajectoryConstraintFor, b as projectKnownWorkspaces, c as trajectoryWorkspaceMdPath, d as CHEAP_WORKER_GUIDE, f as providerAvailabilityError, g as registerEntrySkillSection, h as registerCognitiveTrajectorySkillSection, i as getTrajectoryAgent, j as buildResourceNameSuffix, k as SKILL_ONTOLOGY_FILE, l as unregisterTrajectorySession, m as splitModel, n as createTrajectoryAgent, o as trajectoryConstraintMsmGate, p as requireWhitelistedModel, r as ensureWorkspacePromptSection, s as trajectoryConstraintParticipates, t as askTrajectory, u as workspaceCognitiveTrajectoryLine, v as applyWirePatch, w as FACE_PORTS, x as readAdvancedSettings, y as migrateLegacyLocalstore } from "./session-
|
|
6
|
+
import { _ as ACC_VERSION, a as listBoundSessionIds, d as constraintCognitiveTrajectory, f as constraintSystemPromptSource, g as resolveConstraintSystemPrompt, h as profileToolWhitelist, i as carrierState, l as TRAJECTORY_CONSTRAINT_HINT, n as PLUGIN_SOURCE, o as readLastBound, r as appendBound, s as resolveSessionCognitiveTrajectoryLabel, t as ACC_MESSAGE_KIND, v as findPackageRoot } from "./message-source-DiP3Uve3.js";
|
|
7
|
+
import { A as buildResourceIndex, C as verifyPassword, D as recordToolUsage, E as verifyTotpCode, F as hasTrajectoryPrompt, M as isSafeSkillName, N as truncateContent, O as REFERENCE_DIR, P as TRAJECTORY_PROMPT_FILENAME, S as toWire, T as MECHANISM_PORTS, _ as registerEntrySkillSectionGlobal, a as trajectoryConstraintFor, b as projectKnownWorkspaces, c as trajectoryWorkspaceMdPath, d as CHEAP_WORKER_GUIDE, f as providerAvailabilityError, g as registerEntrySkillSection, h as registerCognitiveTrajectorySkillSection, i as getTrajectoryAgent, j as buildResourceNameSuffix, k as SKILL_ONTOLOGY_FILE, l as unregisterTrajectorySession, m as splitModel, n as createTrajectoryAgent, o as trajectoryConstraintMsmGate, p as requireWhitelistedModel, r as ensureWorkspacePromptSection, s as trajectoryConstraintParticipates, t as askTrajectory, u as workspaceCognitiveTrajectoryLine, v as applyWirePatch, w as FACE_PORTS, x as readAdvancedSettings, y as migrateLegacyLocalstore } from "./session-tdlJDS9i.js";
|
|
8
8
|
import { n as hasSessionLogById, r as sessionsRootDir } from "./cleanup-C-92qnDs.js";
|
|
9
9
|
import { n as readSimpleSettings, r as registerSettingsSection } from "./settings-B-vn8j4g.js";
|
|
10
10
|
import { REGISTERED_TOOLS } from "./invariant.js";
|
|
@@ -7114,102 +7114,6 @@ function createCheapWorkerTool(ctx) {
|
|
|
7114
7114
|
});
|
|
7115
7115
|
}
|
|
7116
7116
|
//#endregion
|
|
7117
|
-
//#region src/trajectory/alive.ts
|
|
7118
|
-
/**
|
|
7119
|
-
* trajectory/alive.ts — **"这个 dsh 会话还活着吗"的唯一判据**(owner 2026-10-20 裁决)
|
|
7120
|
-
*
|
|
7121
|
-
* ## owner 的原话(本模块的全部设计依据)
|
|
7122
|
-
*
|
|
7123
|
-
* > 「死应该包含归档判断;只有 ① 或者 ②且不在归档集 才算活」
|
|
7124
|
-
* > 「use 只要被调用了,可以无条件覆盖绑定到当前会话(这说明当前会话肯定活着啊)」
|
|
7125
|
-
*
|
|
7126
|
-
* ## 为什么必须收成一个判据(在此之前有三个互不一致的判据)
|
|
7127
|
-
*
|
|
7128
|
-
* | # | 判据 | 旧实现位置 | 单独使用时的漏洞 |
|
|
7129
|
-
* |---|---|---|---|
|
|
7130
|
-
* | ① | 进程内 loaded agent | `hostAgents(ctx).get(id)` | 冷会话全判死 |
|
|
7131
|
-
* | ② | 磁盘上有会话日志 | `hasSessionLogById()` | **归档后日志逐字节不动** ⇒ 归档会话判活 |
|
|
7132
|
-
* | ③ | 宿主归档集 | `workspaceRegistry.archivedSessionIds` | 旧 dsp **零引用**(整个仓库 0 处) |
|
|
7133
|
-
*
|
|
7134
|
-
* 宿主的归档语义是**只往集合里加一个 id、不动日志**(`dsh-workspace` 的
|
|
7135
|
-
* `archiveSession` 注释:「Archiving never touches workspace accounting」)。
|
|
7136
|
-
* ⇒ 只问 ② 的实现在归档上**必然判错**,而那个错误没有任何机械信号。
|
|
7137
|
-
*
|
|
7138
|
-
* ## 判据(owner 给定,逐字实现)
|
|
7139
|
-
*
|
|
7140
|
-
* ```text
|
|
7141
|
-
* 活 ⟺ ① (进程内 loaded ⇒ 一定在)
|
|
7142
|
-
* ∨ (② ∧ 不在归档集) (日志在、且没人把它归档掉)
|
|
7143
|
-
* ```
|
|
7144
|
-
*
|
|
7145
|
-
* 🔴 **一处对原话的收紧(必须说出来,不许默默改)**:owner 的 ① 未附加"不在归档集",
|
|
7146
|
-
* 而本模块把**归档判定排在最前** —— 即 `归档 ∧ live ⇒ 判死`。理由:归档是**人对这条会话
|
|
7147
|
-
* 的处置声明**(宿主会把它从所有分组面隐藏),若仍被当成载体,唤醒调度器会去驱动一条
|
|
7148
|
-
* **使用者以为已经收起来**的会话。⚠️ 与字面规则的差异仅此一格;`use` 不受影响
|
|
7149
|
-
* (见下方 §use 逃生门),因此真需要复活一条已归档会话时**仍然有受支持的路**。
|
|
7150
|
-
*
|
|
7151
|
-
* ## 🔴 `use` 的逃生门(owner 第二条,写在调用点)
|
|
7152
|
-
*
|
|
7153
|
-
* **`use` 不查存活**:它被调用这件事本身证明**当前会话活着**(本模块的被测对象是
|
|
7154
|
-
* "别人写的那个 id",而 `use` 手里拿的是**自己**)。⇒ `use` 走无条件覆盖
|
|
7155
|
-
* (`claimBinding` 的 `takeover`),因此**判据再严也不会把一条轨迹锁死**。
|
|
7156
|
-
* 这条逃生门是判据可以取严的前提,两者必须一起存在。
|
|
7157
|
-
*
|
|
7158
|
-
* ## 依赖纪律
|
|
7159
|
-
*
|
|
7160
|
-
* 纯判据 `isSessionAlive` 零依赖、可单测;宿主面只在 `hostAliveProbe` 里,
|
|
7161
|
-
* 且**不抛错**(服务缺失 ⇒ 该维度作废,而不是让 ACC 工具整块失败)。
|
|
7162
|
-
*/
|
|
7163
|
-
/** 宿主侧的归档集读取(不可用 ⇒ 空集 = 该维度作废,**不是**把所有会话判死) */
|
|
7164
|
-
function archivedIdsOf(ctx) {
|
|
7165
|
-
try {
|
|
7166
|
-
const ids = hostService(ctx, "workspaceRegistry")?.archivedSessionIds;
|
|
7167
|
-
return new Set(Array.isArray(ids) ? ids : []);
|
|
7168
|
-
} catch {
|
|
7169
|
-
return /* @__PURE__ */ new Set();
|
|
7170
|
-
}
|
|
7171
|
-
}
|
|
7172
|
-
/**
|
|
7173
|
-
* **宿主面的判活探针**(`(sessionId) => boolean`)——所有需要"这条会话还活着吗"的
|
|
7174
|
-
* 生产代码都应当用这一个,不要自己拼 `agents.get` + `hasSessionLogById`。
|
|
7175
|
-
*
|
|
7176
|
-
* 语义 = {@link isSessionAlive},其中:
|
|
7177
|
-
* · `liveIds` 因为宿主只给 `get(id)` 而**按 id 逐次问**(不是集合);
|
|
7178
|
-
* · `archivedIds` 在**首次调用时**取一次快照并在闭包内复用(每 tick 一个探针,
|
|
7179
|
-
* 归档集在一个 tick 内不变)—— 避免为每条轨迹重复读存储域。
|
|
7180
|
-
*
|
|
7181
|
-
* ⚠️ **快照的代价**:同一探针内若有人中途归档了某会话,本探针直到下次新建才看见。
|
|
7182
|
-
* 调度器是每 tick 新建一个探针(见 `wake/scheduler.ts`),故实际窗口 ≤1 tick。
|
|
7183
|
-
*
|
|
7184
|
-
* @param ctx 插件上下文(取 `agents` 与 `workspaceRegistry`)
|
|
7185
|
-
* @returns 探针;**永不抛**
|
|
7186
|
-
*/
|
|
7187
|
-
function hostAliveProbe(ctx) {
|
|
7188
|
-
let archived;
|
|
7189
|
-
const archivedOnce = () => archived ??= archivedIdsOf(ctx);
|
|
7190
|
-
return (sessionId) => {
|
|
7191
|
-
if (typeof sessionId !== "string" || sessionId === "") return false;
|
|
7192
|
-
if (archivedOnce().has(sessionId)) return false;
|
|
7193
|
-
try {
|
|
7194
|
-
if (hostAgents(ctx)?.get?.(sessionId)) return true;
|
|
7195
|
-
} catch {}
|
|
7196
|
-
try {
|
|
7197
|
-
return hasSessionLogById(sessionsRootDir(), sessionId);
|
|
7198
|
-
} catch {
|
|
7199
|
-
return true;
|
|
7200
|
-
}
|
|
7201
|
-
};
|
|
7202
|
-
}
|
|
7203
|
-
/**
|
|
7204
|
-
* 判据只有**两个**出口,别再开第三个:
|
|
7205
|
-
* · {@link isSessionAlive} —— 纯判据(给定事实),单测的靶子;
|
|
7206
|
-
* · {@link hostAliveProbe} —— 生产入口(自己去宿主与磁盘取事实)。
|
|
7207
|
-
*
|
|
7208
|
-
* ⚠️ 曾有一个 `aliveFactsFor`(把探针摊平成 `SessionAliveFacts`),**全仓零调用点**,
|
|
7209
|
-
* 已删除 —— 留一个"看起来有用、实际无人调用"的导出,会让下一个人以为存在第二条判活路径
|
|
7210
|
-
* (本仓同族教训:`cheapWorkerPresetInheritance` 全仓零调用点 ⇒ 接线断了却看不出来)。
|
|
7211
|
-
*/
|
|
7212
|
-
//#endregion
|
|
7213
7117
|
//#region src/wake/registry.ts
|
|
7214
7118
|
/**
|
|
7215
7119
|
* wake/registry.ts — 认知轨迹唤醒注册表(D58,S142 2026-09-13)
|
|
@@ -7670,6 +7574,102 @@ function deliverCarrierOpening(agent, text) {
|
|
|
7670
7574
|
}
|
|
7671
7575
|
}
|
|
7672
7576
|
//#endregion
|
|
7577
|
+
//#region src/trajectory/alive.ts
|
|
7578
|
+
/**
|
|
7579
|
+
* trajectory/alive.ts — **"这个 dsh 会话还活着吗"的唯一判据**(owner 2026-10-20 裁决)
|
|
7580
|
+
*
|
|
7581
|
+
* ## owner 的原话(本模块的全部设计依据)
|
|
7582
|
+
*
|
|
7583
|
+
* > 「死应该包含归档判断;只有 ① 或者 ②且不在归档集 才算活」
|
|
7584
|
+
* > 「use 只要被调用了,可以无条件覆盖绑定到当前会话(这说明当前会话肯定活着啊)」
|
|
7585
|
+
*
|
|
7586
|
+
* ## 为什么必须收成一个判据(在此之前有三个互不一致的判据)
|
|
7587
|
+
*
|
|
7588
|
+
* | # | 判据 | 旧实现位置 | 单独使用时的漏洞 |
|
|
7589
|
+
* |---|---|---|---|
|
|
7590
|
+
* | ① | 进程内 loaded agent | `hostAgents(ctx).get(id)` | 冷会话全判死 |
|
|
7591
|
+
* | ② | 磁盘上有会话日志 | `hasSessionLogById()` | **归档后日志逐字节不动** ⇒ 归档会话判活 |
|
|
7592
|
+
* | ③ | 宿主归档集 | `workspaceRegistry.archivedSessionIds` | 旧 dsp **零引用**(整个仓库 0 处) |
|
|
7593
|
+
*
|
|
7594
|
+
* 宿主的归档语义是**只往集合里加一个 id、不动日志**(`dsh-workspace` 的
|
|
7595
|
+
* `archiveSession` 注释:「Archiving never touches workspace accounting」)。
|
|
7596
|
+
* ⇒ 只问 ② 的实现在归档上**必然判错**,而那个错误没有任何机械信号。
|
|
7597
|
+
*
|
|
7598
|
+
* ## 判据(owner 给定,逐字实现)
|
|
7599
|
+
*
|
|
7600
|
+
* ```text
|
|
7601
|
+
* 活 ⟺ ① (进程内 loaded ⇒ 一定在)
|
|
7602
|
+
* ∨ (② ∧ 不在归档集) (日志在、且没人把它归档掉)
|
|
7603
|
+
* ```
|
|
7604
|
+
*
|
|
7605
|
+
* 🔴 **一处对原话的收紧(必须说出来,不许默默改)**:owner 的 ① 未附加"不在归档集",
|
|
7606
|
+
* 而本模块把**归档判定排在最前** —— 即 `归档 ∧ live ⇒ 判死`。理由:归档是**人对这条会话
|
|
7607
|
+
* 的处置声明**(宿主会把它从所有分组面隐藏),若仍被当成载体,唤醒调度器会去驱动一条
|
|
7608
|
+
* **使用者以为已经收起来**的会话。⚠️ 与字面规则的差异仅此一格;`use` 不受影响
|
|
7609
|
+
* (见下方 §use 逃生门),因此真需要复活一条已归档会话时**仍然有受支持的路**。
|
|
7610
|
+
*
|
|
7611
|
+
* ## 🔴 `use` 的逃生门(owner 第二条,写在调用点)
|
|
7612
|
+
*
|
|
7613
|
+
* **`use` 不查存活**:它被调用这件事本身证明**当前会话活着**(本模块的被测对象是
|
|
7614
|
+
* "别人写的那个 id",而 `use` 手里拿的是**自己**)。⇒ `use` 走无条件覆盖
|
|
7615
|
+
* (`claimBinding` 的 `takeover`),因此**判据再严也不会把一条轨迹锁死**。
|
|
7616
|
+
* 这条逃生门是判据可以取严的前提,两者必须一起存在。
|
|
7617
|
+
*
|
|
7618
|
+
* ## 依赖纪律
|
|
7619
|
+
*
|
|
7620
|
+
* 纯判据 `isSessionAlive` 零依赖、可单测;宿主面只在 `hostAliveProbe` 里,
|
|
7621
|
+
* 且**不抛错**(服务缺失 ⇒ 该维度作废,而不是让 ACC 工具整块失败)。
|
|
7622
|
+
*/
|
|
7623
|
+
/** 宿主侧的归档集读取(不可用 ⇒ 空集 = 该维度作废,**不是**把所有会话判死) */
|
|
7624
|
+
function archivedIdsOf(ctx) {
|
|
7625
|
+
try {
|
|
7626
|
+
const ids = hostService(ctx, "workspaceRegistry")?.archivedSessionIds;
|
|
7627
|
+
return new Set(Array.isArray(ids) ? ids : []);
|
|
7628
|
+
} catch {
|
|
7629
|
+
return /* @__PURE__ */ new Set();
|
|
7630
|
+
}
|
|
7631
|
+
}
|
|
7632
|
+
/**
|
|
7633
|
+
* **宿主面的判活探针**(`(sessionId) => boolean`)——所有需要"这条会话还活着吗"的
|
|
7634
|
+
* 生产代码都应当用这一个,不要自己拼 `agents.get` + `hasSessionLogById`。
|
|
7635
|
+
*
|
|
7636
|
+
* 语义 = {@link isSessionAlive},其中:
|
|
7637
|
+
* · `liveIds` 因为宿主只给 `get(id)` 而**按 id 逐次问**(不是集合);
|
|
7638
|
+
* · `archivedIds` 在**首次调用时**取一次快照并在闭包内复用(每 tick 一个探针,
|
|
7639
|
+
* 归档集在一个 tick 内不变)—— 避免为每条轨迹重复读存储域。
|
|
7640
|
+
*
|
|
7641
|
+
* ⚠️ **快照的代价**:同一探针内若有人中途归档了某会话,本探针直到下次新建才看见。
|
|
7642
|
+
* 调度器是每 tick 新建一个探针(见 `wake/scheduler.ts`),故实际窗口 ≤1 tick。
|
|
7643
|
+
*
|
|
7644
|
+
* @param ctx 插件上下文(取 `agents` 与 `workspaceRegistry`)
|
|
7645
|
+
* @returns 探针;**永不抛**
|
|
7646
|
+
*/
|
|
7647
|
+
function hostAliveProbe(ctx) {
|
|
7648
|
+
let archived;
|
|
7649
|
+
const archivedOnce = () => archived ??= archivedIdsOf(ctx);
|
|
7650
|
+
return (sessionId) => {
|
|
7651
|
+
if (typeof sessionId !== "string" || sessionId === "") return false;
|
|
7652
|
+
if (archivedOnce().has(sessionId)) return false;
|
|
7653
|
+
try {
|
|
7654
|
+
if (hostAgents(ctx)?.get?.(sessionId)) return true;
|
|
7655
|
+
} catch {}
|
|
7656
|
+
try {
|
|
7657
|
+
return hasSessionLogById(sessionsRootDir(), sessionId);
|
|
7658
|
+
} catch {
|
|
7659
|
+
return true;
|
|
7660
|
+
}
|
|
7661
|
+
};
|
|
7662
|
+
}
|
|
7663
|
+
/**
|
|
7664
|
+
* 判据只有**两个**出口,别再开第三个:
|
|
7665
|
+
* · {@link isSessionAlive} —— 纯判据(给定事实),单测的靶子;
|
|
7666
|
+
* · {@link hostAliveProbe} —— 生产入口(自己去宿主与磁盘取事实)。
|
|
7667
|
+
*
|
|
7668
|
+
* ⚠️ 曾有一个 `aliveFactsFor`(把探针摊平成 `SessionAliveFacts`),**全仓零调用点**,
|
|
7669
|
+
* 已删除 —— 留一个"看起来有用、实际无人调用"的导出,会让下一个人以为存在第二条判活路径
|
|
7670
|
+
* (本仓同族教训:`cheapWorkerPresetInheritance` 全仓零调用点 ⇒ 接线断了却看不出来)。
|
|
7671
|
+
*/
|
|
7672
|
+
//#endregion
|
|
7673
7673
|
//#region src/cro/core.ts
|
|
7674
7674
|
/**
|
|
7675
7675
|
* cro/core.ts — CRO(Continuous Re-Occurrence · 持续再发生)机制层(S142 §7.8,2026-09-19)
|
|
@@ -9462,7 +9462,8 @@ async function createAndBindTarget(ctx, root, dirName) {
|
|
|
9462
9462
|
});
|
|
9463
9463
|
const openingNote = deliverCarrierOpening(agent, buildCarrierOpening(parseTrajectoryCode(dirName) ?? dirName, trajectoryDescOf(dirName))) ? ", opening-as-user" : ", ⚠️ 开场白未投递";
|
|
9464
9464
|
const wsNote = workspaceId !== void 0 ? "" : await attachToWorkspace(ctx, root, sessionId);
|
|
9465
|
-
const
|
|
9465
|
+
const viaNote = workspaceId !== void 0 ? ", via-workspaceId(=用户同一形态)" : ", via-cwd+attach";
|
|
9466
|
+
const how = `auto-create(${sessionId}${bound.ok ? ", bound" : `, ⚠️ 绑定写入失败(${bound.code})`}${viaNote}${openingNote}${wsNote})`;
|
|
9466
9467
|
return {
|
|
9467
9468
|
agent,
|
|
9468
9469
|
how
|
|
@@ -10475,7 +10476,7 @@ function createCognitiveTrajectoryTool(ctx) {
|
|
|
10475
10476
|
dirName: info.dirName,
|
|
10476
10477
|
mdPath: info.mdPath,
|
|
10477
10478
|
sessionId: info.sessionId,
|
|
10478
|
-
|
|
10479
|
+
takeover: true
|
|
10479
10480
|
});
|
|
10480
10481
|
const advisory = advisoryHint(targetEntry.dirName, join(targetEntry.path, "SESSION.md"));
|
|
10481
10482
|
const out = {
|
|
@@ -10484,10 +10485,16 @@ function createCognitiveTrajectoryTool(ctx) {
|
|
|
10484
10485
|
context: active.context
|
|
10485
10486
|
};
|
|
10486
10487
|
if (advisory) out.advisory = advisory;
|
|
10487
|
-
if (bound
|
|
10488
|
-
|
|
10488
|
+
if (bound !== null && bound.ok) {
|
|
10489
|
+
out.binding = "written";
|
|
10490
|
+
if (bound.replaced !== void 0) {
|
|
10491
|
+
out.bindingReplaced = bound.replaced;
|
|
10492
|
+
out.bindingHint = `已顶掉原载体 ${bound.replaced}(owner 裁决:use 无条件覆盖到当前会话)。若那条会话还活着,它此刻**不再**承载「${info?.dirName ?? targetEntry.dirName}」——这是单槽位的必然结果,不是错误;需要它继续承载就再对它 \`use\` 一次。`;
|
|
10493
|
+
}
|
|
10494
|
+
} else if (bound !== null) {
|
|
10489
10495
|
out.binding = "not-written";
|
|
10490
|
-
out.
|
|
10496
|
+
out.bindingCode = bound.code;
|
|
10497
|
+
out.bindingHint = `绑定未写入(${bound.code}):${bound.detail} ⇒ 按契约「绑定声明是唯一真相」,「${info?.dirName ?? targetEntry.dirName}」此刻仍是**未绑定**。 会话标题变了**不能**当作绑定成功的证据(改名走的是另一条通路)。`;
|
|
10491
10498
|
}
|
|
10492
10499
|
return out;
|
|
10493
10500
|
}
|
|
@@ -521,7 +521,12 @@ function findTrajectoryHolding(sessionsRoot, sessionId) {
|
|
|
521
521
|
* @param decl 要写入的声明
|
|
522
522
|
* @param opts.takeover 允许顶掉本条轨迹现有的另一个载体
|
|
523
523
|
* @param opts.alive 探针:**旧载体**是否还活着(缺省 ⇒ 一律当活 = 旧语义)
|
|
524
|
-
* @returns `{ ok: true }` 或 `{ ok: false, code, detail }`(**不抛**,由调用方决定如何呈现)
|
|
524
|
+
* @returns `{ ok: true, replaced?, released? }` 或 `{ ok: false, code, detail }`(**不抛**,由调用方决定如何呈现)
|
|
525
|
+
*
|
|
526
|
+
* 🔴 **2026-10-20 追加 `replaced`(由一条 skiff 轨迹的实测逼出)**:`released` 只覆盖
|
|
527
|
+
* 「这个会话此前安家在**另一条**轨迹」那一格(跨轨迹清理);而**同一轨迹换载体**时被顶掉的那个
|
|
528
|
+
* 会话 id 此前**没有任何出口** ⇒ 调用方无法在回执里说出"你顶掉了谁"。
|
|
529
|
+
* 静默换代正是"一条轨迹感觉有两个载体"的成因 ⇒ 顶掉谁必须能被读出来。
|
|
525
530
|
*/
|
|
526
531
|
function claimBinding(sessionsRoot, dirName, decl, opts = {}) {
|
|
527
532
|
const holder = findTrajectoryHolding(sessionsRoot, decl.sessionId);
|
|
@@ -547,9 +552,11 @@ function claimBinding(sessionsRoot, dirName, decl, opts = {}) {
|
|
|
547
552
|
code: "WRITE_FAILED",
|
|
548
553
|
detail: `写 ${BIND_FILENAME} 失败:${join(sessionsRoot, dirName)}`
|
|
549
554
|
};
|
|
550
|
-
|
|
555
|
+
const replaced = cur !== null && cur.sessionId !== decl.sessionId ? cur.sessionId : void 0;
|
|
556
|
+
return {
|
|
551
557
|
ok: true,
|
|
552
|
-
|
|
558
|
+
...replaced === void 0 ? {} : { replaced },
|
|
559
|
+
...released === void 0 ? {} : { released }
|
|
553
560
|
};
|
|
554
561
|
}
|
|
555
562
|
//#endregion
|
|
@@ -718,14 +725,26 @@ function listBoundSessionIds(root, dirName, alive) {
|
|
|
718
725
|
* 旧签名 `appendBound(session, action, rec)` 保持不变:`session` 提供 `header.id` / `header.cwd`,
|
|
719
726
|
* `rec.dirName` 指明写哪条轨迹的交代。
|
|
720
727
|
*
|
|
721
|
-
* @returns 写入成功 ⇒ true
|
|
728
|
+
* @returns 写入成功 ⇒ `{ ok: true, replaced?, released? }`(**每条轨迹只有一个文件,没有"追加"语义,只有"覆盖"**);
|
|
729
|
+
* 失败 ⇒ `{ ok: false, code, detail }`,**`code` 指名是哪一条守卫拒的**
|
|
730
|
+
*
|
|
731
|
+
* 🔴 **为什么从 `boolean` 改成分级结果(2026-10-20,一条 skiff 轨迹实测逼出)**:
|
|
732
|
+
* 本函数有**两条完全不同的失败路径** —— ① header 守卫(id / root 取不到)② `claimBinding` 拒绝
|
|
733
|
+
* (`SESSION_TAKEN` / `TRAJECTORY_OCCUPIED` / `WRITE_FAILED`)。日志侧早已分开(D186),
|
|
734
|
+
* **但回执侧只有一句 header 文案** ⇒ 调用方被指向错误的方向(那位实测者第一轮就照文案去找 header,
|
|
735
|
+
* 真因是槽位被占)。⇒ 结果必须**带码**,让回执能说出是哪一半。
|
|
722
736
|
*/
|
|
723
737
|
function appendBound(session, action, rec) {
|
|
724
738
|
const id = sessionHeader(session)?.id;
|
|
725
739
|
const root = rootOf(session);
|
|
726
740
|
if (typeof id !== "string" || id === "" || root === null) {
|
|
727
|
-
|
|
728
|
-
|
|
741
|
+
const detail = `会话对象取不到可用的 header(id=${typeof id === "string" && id !== "" ? id : "(空/非字符串)"},root=${root ?? "null(header.cwd 缺失或上溯不到 .serenity)"}) ⇒ 轨迹「${rec.dirName}」的 current.dsh_session_bind **未被改写**。 排查:该会话的 header.cwd 是否指向某个含 .serenity 的目录; 无 cwd 的会话(如某些程序性创建的载体)**不会**写绑定。`;
|
|
742
|
+
console.warn(`[serenity-hooks] ✗ 绑定未写入(SESSION_HEADER_UNRESOLVED):${detail}`);
|
|
743
|
+
return {
|
|
744
|
+
ok: false,
|
|
745
|
+
code: "SESSION_HEADER_UNRESOLVED",
|
|
746
|
+
detail
|
|
747
|
+
};
|
|
729
748
|
}
|
|
730
749
|
const result = claimBinding(sessionsRoot(root), rec.dirName, {
|
|
731
750
|
sessionId: id,
|
|
@@ -739,9 +758,17 @@ function appendBound(session, action, rec) {
|
|
|
739
758
|
});
|
|
740
759
|
if (!result.ok) {
|
|
741
760
|
console.warn(`[serenity-hooks] ✗ 绑定未写入(${result.code}):${result.detail}`);
|
|
742
|
-
return
|
|
761
|
+
return {
|
|
762
|
+
ok: false,
|
|
763
|
+
code: result.code,
|
|
764
|
+
detail: result.detail
|
|
765
|
+
};
|
|
743
766
|
}
|
|
744
|
-
return
|
|
767
|
+
return {
|
|
768
|
+
ok: true,
|
|
769
|
+
...result.replaced === void 0 ? {} : { replaced: result.replaced },
|
|
770
|
+
...result.released === void 0 ? {} : { released: result.released }
|
|
771
|
+
};
|
|
745
772
|
}
|
|
746
773
|
/**
|
|
747
774
|
* 这条轨迹**是否曾经有过载体**(判"要不要允许自建")。
|
|
@@ -2,7 +2,7 @@ import { n as agentCwdFor, r as cccRootForCwd, s as hostAgents } from "./ccc-roo
|
|
|
2
2
|
import { g as readUtf8, o as isSafeModeOn, p as readCognitiveTrajectorySkills, u as readBlacklist } from "./ccc-CyYJL4F2.js";
|
|
3
3
|
import { B as isoLocal, D as readActiveSessionMd, a as readTrajectoryConstraintAt, c as trajectoryConstraintForSession, d as unregisterTrajectorySession$1, j as sessionsRoot, l as registerTrajectorySession$1, p as DEFAULT_SESSION_SCOPE, u as trajectoryDirNameForSession } from "./profile-5TQ_C1xi.js";
|
|
4
4
|
import { a as readGitTrack, i as localstorePath } from "./service-DDmHSglV.js";
|
|
5
|
-
import { _ as ACC_VERSION, d as constraintCognitiveTrajectory, m as profileMsmWhitelist, n as PLUGIN_SOURCE, o as readLastBound, p as createProfilePromptReader, u as buildTrajectoryBasePrompt } from "./message-source-
|
|
5
|
+
import { _ as ACC_VERSION, d as constraintCognitiveTrajectory, m as profileMsmWhitelist, n as PLUGIN_SOURCE, o as readLastBound, p as createProfilePromptReader, u as buildTrajectoryBasePrompt } from "./message-source-DiP3Uve3.js";
|
|
6
6
|
import { basename, dirname, join, resolve } from "node:path";
|
|
7
7
|
import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, writeFileSync } from "node:fs";
|
|
8
8
|
import { createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
@@ -241,13 +241,19 @@ export declare function findTrajectoryHolding(sessionsRoot: string, sessionId: s
|
|
|
241
241
|
* @param decl 要写入的声明
|
|
242
242
|
* @param opts.takeover 允许顶掉本条轨迹现有的另一个载体
|
|
243
243
|
* @param opts.alive 探针:**旧载体**是否还活着(缺省 ⇒ 一律当活 = 旧语义)
|
|
244
|
-
* @returns `{ ok: true }` 或 `{ ok: false, code, detail }`(**不抛**,由调用方决定如何呈现)
|
|
244
|
+
* @returns `{ ok: true, replaced?, released? }` 或 `{ ok: false, code, detail }`(**不抛**,由调用方决定如何呈现)
|
|
245
|
+
*
|
|
246
|
+
* 🔴 **2026-10-20 追加 `replaced`(由一条 skiff 轨迹的实测逼出)**:`released` 只覆盖
|
|
247
|
+
* 「这个会话此前安家在**另一条**轨迹」那一格(跨轨迹清理);而**同一轨迹换载体**时被顶掉的那个
|
|
248
|
+
* 会话 id 此前**没有任何出口** ⇒ 调用方无法在回执里说出"你顶掉了谁"。
|
|
249
|
+
* 静默换代正是"一条轨迹感觉有两个载体"的成因 ⇒ 顶掉谁必须能被读出来。
|
|
245
250
|
*/
|
|
246
251
|
export declare function claimBinding(sessionsRoot: string, dirName: string, decl: BindDeclaration, opts?: {
|
|
247
252
|
takeover?: boolean;
|
|
248
253
|
alive?: (sessionId: string) => boolean;
|
|
249
254
|
}): {
|
|
250
255
|
ok: true;
|
|
256
|
+
replaced?: string;
|
|
251
257
|
released?: string;
|
|
252
258
|
} | {
|
|
253
259
|
ok: false;
|
|
@@ -120,13 +120,37 @@ export declare function supersedeOtherBindings(_root: string, _dirName: string,
|
|
|
120
120
|
* 保留本函数只为不打断既有调用点,恒返回空数组。
|
|
121
121
|
*/
|
|
122
122
|
export declare function pruneMissingBindings(_root: string, _isMissing: (sessionId: string) => boolean): string[];
|
|
123
|
+
/**
|
|
124
|
+
* 绑定写入的结果(分级,**不是 boolean**)。
|
|
125
|
+
*
|
|
126
|
+
* 分级的意义 = **调用方能说出是哪一半失败**(见 `appendBound` 头注)。
|
|
127
|
+
*/
|
|
128
|
+
export type BindWriteCode = 'SESSION_HEADER_UNRESOLVED' | 'SESSION_TAKEN' | 'TRAJECTORY_OCCUPIED' | 'WRITE_FAILED';
|
|
129
|
+
export type BindWriteResult = {
|
|
130
|
+
ok: true;
|
|
131
|
+
/** 同一轨迹上被顶掉的旧载体 id(`use` 无条件覆盖时要写进回执 —— 静默换代是不允许的) */
|
|
132
|
+
replaced?: string;
|
|
133
|
+
/** 被清掉的**另一条**轨迹的残留声明(`claimBinding` 的安全网) */
|
|
134
|
+
released?: string;
|
|
135
|
+
} | {
|
|
136
|
+
ok: false;
|
|
137
|
+
code: BindWriteCode;
|
|
138
|
+
detail: string;
|
|
139
|
+
};
|
|
123
140
|
/**
|
|
124
141
|
* 把一条轨迹的当前载体写成 `sessionId`(**唯一写入口**,内部走 `claimBinding` 的两条不变量)。
|
|
125
142
|
*
|
|
126
143
|
* 旧签名 `appendBound(session, action, rec)` 保持不变:`session` 提供 `header.id` / `header.cwd`,
|
|
127
144
|
* `rec.dirName` 指明写哪条轨迹的交代。
|
|
128
145
|
*
|
|
129
|
-
* @returns 写入成功 ⇒ true
|
|
146
|
+
* @returns 写入成功 ⇒ `{ ok: true, replaced?, released? }`(**每条轨迹只有一个文件,没有"追加"语义,只有"覆盖"**);
|
|
147
|
+
* 失败 ⇒ `{ ok: false, code, detail }`,**`code` 指名是哪一条守卫拒的**
|
|
148
|
+
*
|
|
149
|
+
* 🔴 **为什么从 `boolean` 改成分级结果(2026-10-20,一条 skiff 轨迹实测逼出)**:
|
|
150
|
+
* 本函数有**两条完全不同的失败路径** —— ① header 守卫(id / root 取不到)② `claimBinding` 拒绝
|
|
151
|
+
* (`SESSION_TAKEN` / `TRAJECTORY_OCCUPIED` / `WRITE_FAILED`)。日志侧早已分开(D186),
|
|
152
|
+
* **但回执侧只有一句 header 文案** ⇒ 调用方被指向错误的方向(那位实测者第一轮就照文案去找 header,
|
|
153
|
+
* 真因是槽位被占)。⇒ 结果必须**带码**,让回执能说出是哪一半。
|
|
130
154
|
*/
|
|
131
155
|
export declare function appendBound(session: unknown, action: SessionBoundAction, rec: {
|
|
132
156
|
dirName: string;
|
|
@@ -144,7 +168,7 @@ export declare function appendBound(session: unknown, action: SessionBoundAction
|
|
|
144
168
|
* 生产调用点应当传 {@link hostAliveProbe}(`trajectory/alive.ts`)。
|
|
145
169
|
*/
|
|
146
170
|
alive?: (sessionId: string) => boolean;
|
|
147
|
-
}):
|
|
171
|
+
}): BindWriteResult;
|
|
148
172
|
/**
|
|
149
173
|
* 这条轨迹**是否曾经有过载体**(判"要不要允许自建")。
|
|
150
174
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shgroup/dsh-serenity-hooks",
|
|
3
|
-
"version": "1.79.
|
|
3
|
+
"version": "1.79.5",
|
|
4
4
|
"description": "宁静号 ACC harness(Native Cordis 插件)——给 DeepSeek Harness 装一个「AI 工作区」:14 个工具(container_fs/cognitive_trajectory/dashboard/container_git/msm/praxis/ontology/serenity-skill-creator/cheap-worker/localstore/container_admin;另三个 im-bridge/acc-diag/diagram 按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫/对外输出守卫)+ 认知轨迹日志与原地重建 + 网页登录入口/IM 桥/认知轨迹唤醒注册表。轨迹声明 = 轨迹目录下的 trajectory.json(约束面 + 旧标识 uid + CRO 机器绑定 cro.host;旧名 trajectory-constraint.json / skiff.json 仍在读取族里);轨迹提示词 = 轨迹目录下的 PROMPT.md(一条轨迹「是谁、按什么章程工作」,所有轨迹通用,追加在容器层与质量层之后,不替换它们)。适配 DSH 0.1.7-rc.1 / 0.2.0-rc.1 / 0.2.1-rc.1(三档)。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|