@shgroup/dsh-serenity-hooks 1.87.4 → 1.87.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "dsh-serenity-hooks",
3
- "version": "1.87.4",
3
+ "version": "1.87.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": {
@@ -227,7 +227,7 @@ async function listCccs(ctx, opts = {}) {
227
227
  if (typeof defaultRoot === "string" && defaultRoot !== "" && !c.roots.includes(defaultRoot)) c.roots.unshift(defaultRoot);
228
228
  let rolesOf = null;
229
229
  if (opts.withRoles === true) {
230
- const { listTrajectoryConstraints } = await import("./profile-CQWuuopQ.js").then((n) => n.a);
230
+ const { listTrajectoryConstraints } = await import("./profile-DGt_e-Nx.js").then((n) => n.a);
231
231
  rolesOf = (root) => {
232
232
  try {
233
233
  return listTrajectoryConstraints(root).map((p) => p.code);
package/lib/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import { i as __toESM, n as __exportAll } from "./rolldown-runtime-B4iAMlE-.js";
2
- import { c as hostInjected, d as hostSessions, f as hostSettings, h as hostWebServer, i as cccRootForExec, l as hostLlm, m as hostWeb, n as agentCwdFor, o as listCccs, p as hostSubagents, r as cccRootForCwd, s as hostAgents, t as NO_CCC_FROM_AGENT_CWD, u as hostService } from "./ccc-roots-CR1IWLDJ.js";
2
+ import { c as hostInjected, d as hostSessions, f as hostSettings, h as hostWebServer, i as cccRootForExec, l as hostLlm, m as hostWeb, n as agentCwdFor, o as listCccs, p as hostSubagents, r as cccRootForCwd, s as hostAgents, t as NO_CCC_FROM_AGENT_CWD, u as hostService } from "./ccc-roots-CvgsUnFW.js";
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
- import { A as resolveSessionByTitle, B as readTrajectoryFile, C as listActiveTrajectories, D as parseTrajectoryCode, E as parseSessionContextFromEvents, F as summarize, H as localFileStamp, I as trajectoryDescOf, L as useSession, M as sessionsRoot, N as setActiveSessionInfo, P as showSession, R as TRAJECTORY_FILENAME, T as namingTitleFor, U as localHuman, V as isoLocal, W as localIdStamp, _ as clearActiveSessionInfo, b as findSession, c as replacesDefaultIdentity, g as archiveSession, h as UID_FILENAME, i as listTrajectoryConstraints, j as sessionEvents, k as readTrajectoryUid, l as trajectoryConstraintForSession, n as findDirNameByCode, o as readTrajectoryConstraintAt, p as COGNITIVE_TRAJECTORY_ACTIONS, r as isTrajectoryConstrained, s as readTrajectoryConstraintByCode, t as TRAJECTORY_CONSTRAINT_FILENAME, v as createSession, w as listSessions, x as getActiveSessionInfo, y as extractSessionMdPathFromText, z as TRAJECTORY_LEGACY_FILENAMES } from "./profile-CQWuuopQ.js";
4
+ import { A as resolveSessionByTitle, B as readTrajectoryFile, C as listActiveTrajectories, D as parseTrajectoryCode, E as parseSessionContextFromEvents, F as summarize, H as localFileStamp, I as trajectoryDescOf, L as useSession, M as sessionsRoot, N as setActiveSessionInfo, P as showSession, R as TRAJECTORY_FILENAME, T as namingTitleFor, U as localHuman, V as isoLocal, W as localIdStamp, _ as clearActiveSessionInfo, b as findSession, c as replacesDefaultIdentity, g as archiveSession, h as UID_FILENAME, i as listTrajectoryConstraints, j as sessionEvents, k as readTrajectoryUid, l as trajectoryConstraintForSession, n as findDirNameByCode, o as readTrajectoryConstraintAt, p as COGNITIVE_TRAJECTORY_ACTIONS, r as isTrajectoryConstrained, s as readTrajectoryConstraintByCode, t as TRAJECTORY_CONSTRAINT_FILENAME, v as createSession, w as listSessions, x as getActiveSessionInfo, y as extractSessionMdPathFromText, z as TRAJECTORY_LEGACY_FILENAMES } from "./profile-DGt_e-Nx.js";
5
5
  import { n as checkLocalstoreGitCompliance, o as readStore, s as runLocalStore, t as LOCALSTORE_SCOPES } from "./service-DDmHSglV.js";
6
- import { _ as resolveConstraintSystemPrompt, a as listBoundSessionIds, d as constraintCognitiveTrajectory, f as constraintSystemPromptSource, g as profileWriteWhitelist, 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 ACC_VERSION, y as findPackageRoot } from "./message-source-HLXLQuvR.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-CksIqzii.js";
6
+ import { _ as resolveConstraintSystemPrompt, a as listBoundSessionIds, d as constraintCognitiveTrajectory, f as constraintSystemPromptSource, g as profileWriteWhitelist, 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 ACC_VERSION, y as findPackageRoot } from "./message-source-Cq4PsuES.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-Ca5UYzF3.js";
8
8
  import { i as sessionsRootDir, n as findSessionLog, r as hasSessionLogById } from "./cleanup-DxX78__Z.js";
9
- import { n as readSimpleSettings, r as registerSettingsSection } from "./settings-D14eA2MR.js";
9
+ import { n as readSimpleSettings, r as registerSettingsSection } from "./settings-BI3NRHgC.js";
10
10
  import { a as readFeishuCredential, c as readWeixinSettings, d as weixinInboundDir, f as weixinSessionIdForTrajectory, i as matchWeixinRoute, n as extractWeixinText, o as readImSettings, r as hasVoiceItem, s as readWeixinCredential, t as extractWeixinMedia, u as sanitizeFileName$1 } from "./route-3OzOAjec.js";
11
11
  import { REGISTERED_TOOLS } from "./invariant.js";
12
12
  import { c as sendTextMessage, i as getUpdates, l as sendTyping, n as downloadMedia, o as markdownToPlainText, r as getConfig, s as sendFileMessage, t as TypingStatus, u as sniffImageExt } from "./ilink-CsZ-f64q.js";
@@ -10505,6 +10505,133 @@ function scanInterruptedSessions(projectDir, options = {}) {
10505
10505
  function projectDirNameForCwd(cwd) {
10506
10506
  return `--${cwd.replace(/\/+$/, "").split("/").filter(Boolean).join("-")}--`;
10507
10507
  }
10508
+ /**
10509
+ * 续跑正文(**简单、稳定、不含版本号**)。
10510
+ *
10511
+ * 判据(为什么这么短):本动作的用途是**把被打断的会话推回工作状态**,
10512
+ * 不是替它重述任务 —— 被打断那一轮的上下文就在它自己的日志里。
10513
+ * ⇒ 正文只做三件事:① 说明发生了什么;② 提示**先核对副作用**;③ 让它接着做。
10514
+ *
10515
+ * 🔴 **为什么要写"先核对副作用"**:中断时可能有「有 call 无 result」的工具调用,
10516
+ * 它们的副作用**未知**(可能已写文件 / 已发消息)。若模型把那一轮整段重放,
10517
+ * 会**重复执行**。这句话是给模型的护栏,不是客套。
10518
+ */
10519
+ function buildContinueText(sessionId, turn, pendingTools) {
10520
+ const lines = [];
10521
+ lines.push("[中断续跑] 上一条进程在本轮完成前退出,该轮已被中止。现在继续。");
10522
+ lines.push("");
10523
+ lines.push(`会话: ${sessionId}${turn === null ? "" : ` / 被中断的轮次: turn ${turn}`}`);
10524
+ if (pendingTools.length > 0) {
10525
+ lines.push("");
10526
+ lines.push(`⚠️ 中断时这些工具「有调用、无结果」(副作用未知,**可能已经执行**): ${pendingTools.join(", ")}`);
10527
+ lines.push(" ⇒ 先核对它们是否已生效(文件是否已写、消息是否已发),再决定要不要重做。");
10528
+ lines.push(" ⛔ 不要把被中断的那一轮整段重放。");
10529
+ }
10530
+ lines.push("");
10531
+ lines.push("请接着完成该轮未完成的工作;完成后把进展写入本轨迹的 SESSION.md。");
10532
+ return lines.join("\n");
10533
+ }
10534
+ /**
10535
+ * 把一个 agent 唤醒(注入一条续跑消息)。
10536
+ *
10537
+ * 两条路径(与 `wake/scheduler.ts` 的 `sendToCognitiveTrajectory` 同源判据):
10538
+ * - **live**:`agents.get(id)` 拿得到 ⇒ 目标在跑(或被加载)⇒ `steer` 当场注入当前轮;
10539
+ * `steer` 不可用则退回 `followup`(宁可排队,不可静默丢)。
10540
+ * - **cold-resume**:`sessionController.resolveAgent(id)` 冷载入后同样注入。
10541
+ *
10542
+ * ⚠️ 冷会话载入**会真起一个 agent**(消耗真实算力)⇒ 调用方必须自己决定要不要,
10543
+ * 本函数不做数量限制(那是策略,归调用者)。
10544
+ */
10545
+ function createResumeOne(deps) {
10546
+ return async (hit) => {
10547
+ const { sessionId } = hit;
10548
+ const text = buildContinueText(sessionId, hit.turn, hit.pendingTools);
10549
+ let agent;
10550
+ let how;
10551
+ const live = deps.agents?.get?.(sessionId);
10552
+ if (live) {
10553
+ agent = live;
10554
+ how = "live";
10555
+ } else {
10556
+ const sc = deps.sessionController;
10557
+ const resolve = sc?.resolveAgent;
10558
+ if (typeof resolve !== "function" || sc === void 0) return {
10559
+ sessionId,
10560
+ ok: false,
10561
+ error: "宿主 sessionController 不可用(重启启动窗口?)—— 稍后重试"
10562
+ };
10563
+ try {
10564
+ const out = await resolve.call(sc, sessionId);
10565
+ if (!out?.agent) return {
10566
+ sessionId,
10567
+ ok: false,
10568
+ error: `冷载入未返回 agent: ${String(out?.error ?? "未知原因")}`
10569
+ };
10570
+ agent = out.agent;
10571
+ how = "cold-resume";
10572
+ } catch (err) {
10573
+ return {
10574
+ sessionId,
10575
+ ok: false,
10576
+ error: `冷载入失败: ${err instanceof Error ? err.message : String(err)}`
10577
+ };
10578
+ }
10579
+ }
10580
+ const a = agent;
10581
+ try {
10582
+ if (typeof a.steer === "function" && a.status === "running") {
10583
+ a.steer(deps.makeMessage(text));
10584
+ return {
10585
+ sessionId,
10586
+ ok: true,
10587
+ how: `${how}+steer`
10588
+ };
10589
+ }
10590
+ if (typeof a.followup === "function") {
10591
+ a.followup(deps.makeMessage(text));
10592
+ return {
10593
+ sessionId,
10594
+ ok: true,
10595
+ how: `${how}+followup`
10596
+ };
10597
+ }
10598
+ if (typeof a.steer === "function") {
10599
+ a.steer(deps.makeMessage(text));
10600
+ return {
10601
+ sessionId,
10602
+ ok: true,
10603
+ how: `${how}+steer`
10604
+ };
10605
+ }
10606
+ return {
10607
+ sessionId,
10608
+ ok: false,
10609
+ how,
10610
+ error: "agent 既无 steer 也无 followup(宿主契约漂移)"
10611
+ };
10612
+ } catch (err) {
10613
+ if (typeof a.followup === "function") try {
10614
+ a.followup(deps.makeMessage(text));
10615
+ return {
10616
+ sessionId,
10617
+ ok: true,
10618
+ how: `${how}+followup(steer 失败后退回)`
10619
+ };
10620
+ } catch (err2) {
10621
+ return {
10622
+ sessionId,
10623
+ ok: false,
10624
+ error: `steer 与 followup 均失败: ${String(err2?.message ?? err2)}`
10625
+ };
10626
+ }
10627
+ return {
10628
+ sessionId,
10629
+ ok: false,
10630
+ error: `注入失败: ${err instanceof Error ? err.message : String(err)}`
10631
+ };
10632
+ }
10633
+ };
10634
+ }
10508
10635
  //#endregion
10509
10636
  //#region src/tools/cognitive-trajectory.ts
10510
10637
  /**
@@ -10597,6 +10724,51 @@ function renderInterruptedScan(input) {
10597
10724
  }
10598
10725
  return lines.join("\n");
10599
10726
  }
10727
+ /**
10728
+ * 渲染 `continue-all-interrupted` 的结果(人读)。
10729
+ *
10730
+ * 三种形态必须能一眼分清:**dryRun(只预告)** / **有命中且全成功** / **有失败**。
10731
+ * ⚠️ 明确写出"已注入 ≠ 已跑完" —— 与 `send-now` 的回执口径一致(D-族:回执只到注入)。
10732
+ */
10733
+ function renderContinueResult(input) {
10734
+ const { projectDir, lookbackHours, scan, outcomes, dryRun } = input;
10735
+ const lines = [];
10736
+ const head = dryRun ? "续跑预告(dryRun,未注入任何消息)" : "中断续跑结果";
10737
+ lines.push(`═══ ${head}(回看 ${lookbackHours}h)═══`);
10738
+ lines.push(` 扫描域: ${projectDir}`);
10739
+ lines.push(` 检查 ${scan.scanned} 个 · 命中 ${scan.sessions.length} · 跳过 ${scan.skipped} · 耗时 ${scan.elapsedMs}ms`);
10740
+ if (scan.sessions.length === 0) {
10741
+ lines.push("");
10742
+ lines.push("✓ 没有会话以 interrupted 结尾 —— 无需续跑。");
10743
+ return lines.join("\n");
10744
+ }
10745
+ lines.push("");
10746
+ if (dryRun) {
10747
+ lines.push("将对这些会话注入续跑消息:");
10748
+ for (const s of scan.sessions) {
10749
+ const at = s.lastEventAt !== null ? new Date(s.lastEventAt).toISOString() : "(时间未知)";
10750
+ lines.push(` · ${s.sessionId} turn=${s.turn ?? "?"} 末事件 ${at}`);
10751
+ if (s.pendingTools.length > 0) lines.push(` 副作用未知: ${s.pendingTools.join(", ")}`);
10752
+ }
10753
+ lines.push("");
10754
+ lines.push("要真的执行,去掉 dryRun 再调用一次。");
10755
+ return lines.join("\n");
10756
+ }
10757
+ const okCount = (outcomes ?? []).filter((o) => o.ok).length;
10758
+ const failCount = (outcomes ?? []).length - okCount;
10759
+ lines.push(`结果:已注入 ${okCount} / 失败 ${failCount}`);
10760
+ lines.push("");
10761
+ for (const o of outcomes ?? []) lines.push(o.ok ? ` ✓ ${o.sessionId} (${o.how ?? "已注入"})` : ` ✗ ${o.sessionId} ${o.error ?? "未知原因"}`);
10762
+ lines.push("");
10763
+ lines.push("⚠️ 回执只到「消息已注入」——**不表示**目标已经跑完或已答复。");
10764
+ lines.push(" 要确认它真的动了,去看该会话的日志 / 它自己的 SESSION.md。");
10765
+ if (scan.errors.length > 0) {
10766
+ lines.push("");
10767
+ lines.push("扫描期读取失败(诊断):");
10768
+ for (const e of scan.errors.slice(0, 10)) lines.push(` · ${e.sessionId}: ${e.message}`);
10769
+ }
10770
+ return lines.join("\n");
10771
+ }
10600
10772
  /** 当前 dsh 会话 id(use/close 按会话隔离的 scope) */
10601
10773
  function agentScope$1(exec) {
10602
10774
  return exec.agent?.session?.id ?? "default";
@@ -10757,7 +10929,8 @@ function createCognitiveTrajectoryTool(ctx) {
10757
10929
  "send-later (one future instant + one message; fire-and-forget, and it does NOT auto-create a target).",
10758
10930
  "REFERENCE: cro-guide (no parameters: prints the CRO programming guide, including a ready-to-use sample snapshot) /",
10759
10931
  "resident (READ-ONLY: the roster of trajectories that declared themselves RESIDENT — \"I am here, this is what I am good at, come bother me\". It lists each code with its own `serves` sentence, plus any code that wrote `resident` without `serves` (half a declaration is worse than none: people ask, then find they asked the wrong one). ⚠️ Residency is NOT a resource state — it does not mean \"never sleeps\" or \"never destroyed\"; a trajectory permanently exists either way. It governs BEING FOUND, not being kept alive, and it never touches the scheduler).",
10760
- "INSPECTION: interrupted (READ-ONLY: dsh sessions whose LAST turn ended with reason \"interrupted\" — the process died mid-turn. Accepts an optional lookbackHours (default 8). Deciding whether/when to resume is YOUR job — this action only answers \"which sessions are in that state right now\")."
10932
+ "INSPECTION: interrupted (READ-ONLY: dsh sessions whose LAST turn ended with reason \"interrupted\" — the process died mid-turn. Accepts an optional lookbackHours (default 8). Deciding whether/when to resume is YOUR job — this action only answers \"which sessions are in that state right now\") /",
10933
+ "continue-all-interrupted (ACTION: same detection as above, but it then INJECTS a short continue message into every hit, waking them. Serial delivery. Supports dryRun to preview without injecting. ⚠️ This really starts agents and spends real compute — use dryRun first if unsure. The receipt means \"injected\", NOT \"the target finished or replied\")."
10761
10934
  ].join(" ")
10762
10935
  },
10763
10936
  name: {
@@ -10798,7 +10971,7 @@ function createCognitiveTrajectoryTool(ctx) {
10798
10971
  },
10799
10972
  dryRun: {
10800
10973
  type: "boolean",
10801
- description: "create: preview mode (no actual changes)"
10974
+ description: "create: preview mode (no actual changes). continue-all-interrupted: preview which sessions WOULD be resumed, injecting nothing."
10802
10975
  },
10803
10976
  target: {
10804
10977
  type: "string",
@@ -10814,7 +10987,7 @@ function createCognitiveTrajectoryTool(ctx) {
10814
10987
  },
10815
10988
  lookbackHours: {
10816
10989
  type: "number",
10817
- description: "interrupted: how far back to look, in hours (default 8). Sessions whose current-generation log was last written earlier than this are not examined at all."
10990
+ description: "interrupted / continue-all-interrupted: how far back to look, in hours (default 8). Sessions whose current-generation log was last written earlier than this are not examined at all."
10818
10991
  }
10819
10992
  },
10820
10993
  output: {
@@ -11037,6 +11210,65 @@ function createCognitiveTrajectoryTool(ctx) {
11037
11210
  })
11038
11211
  });
11039
11212
  }
11213
+ case "continue-all-interrupted": {
11214
+ /**
11215
+ * 扫 + 逐条注入续跑消息(owner 2026-10-22 追加令:
11216
+ * 「我希望实现的是 continue-all-interrupted 方法,调用后自动找到 8h 内所有 dsh 会话
11217
+ * 注入简单的 continue 进行唤醒,这样 CCC 就不用动脑子了」)。
11218
+ *
11219
+ * 🔴 **与 `interrupted` 分立而不合并**:前者是**观察**(只读、零副作用),
11220
+ * 后者是**动作**(会真起 agent、真烧算力)。想看一眼清单却误触发全量续跑
11221
+ * 是不可接受的 ⇒ 两个动作各自可调用。
11222
+ *
11223
+ * 🔴 **边界仍是"不判周期"**:何时调用归调用方(CCC 的定时轨迹)。
11224
+ * 本动作只保证"**调用一次就把该做的做完**"。
11225
+ */
11226
+ const lookbackHours = typeof args.lookbackHours === "number" && args.lookbackHours > 0 ? args.lookbackHours : DEFAULT_LOOKBACK_MS / 36e5;
11227
+ const dryRun = args.dryRun === true;
11228
+ const sessionsRootPath = sessionsRootDir();
11229
+ const cwdRead = exec.agent?.session?.header?.cwd ?? root;
11230
+ const projectDir = join(sessionsRootPath, projectDirNameForCwd(cwdRead));
11231
+ const scan = scanInterruptedSessions(projectDir, {
11232
+ lookbackMs: lookbackHours * 36e5,
11233
+ liveIds: collectLiveSessionIds()
11234
+ });
11235
+ if (dryRun) return renderContinueResult({
11236
+ projectDir,
11237
+ lookbackHours,
11238
+ scan,
11239
+ outcomes: null,
11240
+ dryRun: true
11241
+ });
11242
+ const hostCtx = exec;
11243
+ const resumeOne = createResumeOne({
11244
+ agents: hostAgents(hostCtx),
11245
+ sessionController: hostService(hostCtx, "sessionController"),
11246
+ makeMessage: (text) => createUserMessage({
11247
+ content: [{
11248
+ type: "text",
11249
+ text
11250
+ }],
11251
+ source: PLUGIN_SOURCE
11252
+ })
11253
+ });
11254
+ const outcomes = [];
11255
+ for (const hit of scan.sessions) try {
11256
+ outcomes.push(await resumeOne(hit));
11257
+ } catch (err) {
11258
+ outcomes.push({
11259
+ sessionId: hit.sessionId,
11260
+ ok: false,
11261
+ error: err instanceof Error ? err.message : String(err)
11262
+ });
11263
+ }
11264
+ return renderContinueResult({
11265
+ projectDir,
11266
+ lookbackHours,
11267
+ scan,
11268
+ outcomes,
11269
+ dryRun: false
11270
+ });
11271
+ }
11040
11272
  default: throw new Error(`Unknown action: ${args.action}`);
11041
11273
  }
11042
11274
  }
@@ -14796,7 +15028,7 @@ function registerStatusApi(ctx, opts = {}) {
14796
15028
  });
14797
15029
  }
14798
15030
  const { saveWeixinRoutes } = await import("./route-3OzOAjec.js").then((n) => n.l);
14799
- const { findDirNameByCode } = await import("./profile-CQWuuopQ.js").then((n) => n.a);
15031
+ const { findDirNameByCode } = await import("./profile-DGt_e-Nx.js").then((n) => n.a);
14800
15032
  for (const r of routes) if (findDirNameByCode(root, r.trajectory) === null) {
14801
15033
  sendJson$2(res, 400, { error: `unknown trajectory: ${r.trajectory} (no such trajectory code in ${root})` });
14802
15034
  return;
@@ -19839,7 +20071,7 @@ const MEDIA_MAX_BYTES = 20971520;
19839
20071
  */
19840
20072
  async function resolveCccRootByAlias(ctx, alias) {
19841
20073
  try {
19842
- const { listCccs } = await import("./ccc-roots-CR1IWLDJ.js").then((n) => n.a);
20074
+ const { listCccs } = await import("./ccc-roots-CvgsUnFW.js").then((n) => n.a);
19843
20075
  const entries = await listCccs(ctx);
19844
20076
  const byName = entries.find((e) => e.name === alias);
19845
20077
  if (byName) return byName.root;
@@ -19907,7 +20139,7 @@ async function resolveInboundTarget(ctx, input) {
19907
20139
  });
19908
20140
  return null;
19909
20141
  }
19910
- const { findDirNameByCode } = await import("./profile-CQWuuopQ.js").then((n) => n.a);
20142
+ const { findDirNameByCode } = await import("./profile-DGt_e-Nx.js").then((n) => n.a);
19911
20143
  if (findDirNameByCode(root, target.role) === null) {
19912
20144
  const detail = `目标 CCC "${target.ccc}" 内没有编码为 "${target.role}" 的认知轨迹`;
19913
20145
  console.error(`[serenity-hooks] ✗ human-channel: ${detail}(account=${input.account} user=${input.user})—— 该消息**未投递**,请改订阅表里的目标编码`);
@@ -20861,7 +21093,7 @@ function syncHumanChannel(ctx) {
20861
21093
  (async () => {
20862
21094
  try {
20863
21095
  stopMachineLoops();
20864
- const { listCccs } = await import("./ccc-roots-CR1IWLDJ.js").then((n) => n.a);
21096
+ const { listCccs } = await import("./ccc-roots-CvgsUnFW.js").then((n) => n.a);
20865
21097
  for (const entry of await listCccs(ctx)) syncCccBridge(ctx, entry.root);
20866
21098
  } catch {}
20867
21099
  })();
@@ -21154,7 +21386,7 @@ function matchCcc(input, candidates) {
21154
21386
  }
21155
21387
  /** 组装候选列表(`ccc-roots.listCccs` 投影 + `.serenity` 名;动态 import 保持本模块静态依赖轻量) */
21156
21388
  async function collectCandidates(ctx) {
21157
- const { listCccs } = await import("./ccc-roots-CR1IWLDJ.js").then((n) => n.a);
21389
+ const { listCccs } = await import("./ccc-roots-CvgsUnFW.js").then((n) => n.a);
21158
21390
  const entries = await listCccs(ctx, { defaultRoot: process.cwd() });
21159
21391
  const seen = /* @__PURE__ */ new Set();
21160
21392
  const out = [];
@@ -1,6 +1,6 @@
1
- import { r as cccRootForCwd } from "./ccc-roots-CR1IWLDJ.js";
1
+ import { r as cccRootForCwd } from "./ccc-roots-CvgsUnFW.js";
2
2
  import { _ as resolveInside, g as readUtf8 } from "./ccc-CyYJL4F2.js";
3
- import { D as parseTrajectoryCode, M as sessionsRoot, S as getLastActiveSessionInfo, j as sessionEvents, x as getActiveSessionInfo } from "./profile-CQWuuopQ.js";
3
+ import { D as parseTrajectoryCode, M as sessionsRoot, S as getLastActiveSessionInfo, j as sessionEvents, x as getActiveSessionInfo } from "./profile-DGt_e-Nx.js";
4
4
  import { dirname, join } from "node:path";
5
5
  import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, writeFileSync } from "node:fs";
6
6
  import { fileURLToPath } from "node:url";
@@ -245,7 +245,8 @@ const COGNITIVE_TRAJECTORY_ACTIONS = [
245
245
  "send-later",
246
246
  "cro-guide",
247
247
  "resident",
248
- "interrupted"
248
+ "interrupted",
249
+ "continue-all-interrupted"
249
250
  ];
250
251
  /**
251
252
  * 读取 Session 事件序列(v1.28.1 适配 0.1.2-rc.1 补齐):rc.1 起官方 Session 类
@@ -1,8 +1,8 @@
1
- import { n as agentCwdFor, r as cccRootForCwd, s as hostAgents } from "./ccc-roots-CR1IWLDJ.js";
1
+ import { n as agentCwdFor, r as cccRootForCwd, s as hostAgents } from "./ccc-roots-CvgsUnFW.js";
2
2
  import { g as readUtf8, o as isSafeModeOn, p as readCognitiveTrajectorySkills, u as readBlacklist } from "./ccc-CyYJL4F2.js";
3
- import { M as sessionsRoot, O as readActiveSessionMd, V as isoLocal, d as trajectoryDirNameForSession, f as unregisterTrajectorySession$1, l as trajectoryConstraintForSession, m as DEFAULT_SESSION_SCOPE, o as readTrajectoryConstraintAt, u as registerTrajectorySession$1 } from "./profile-CQWuuopQ.js";
3
+ import { M as sessionsRoot, O as readActiveSessionMd, V as isoLocal, d as trajectoryDirNameForSession, f as unregisterTrajectorySession$1, l as trajectoryConstraintForSession, m as DEFAULT_SESSION_SCOPE, o as readTrajectoryConstraintAt, u as registerTrajectorySession$1 } from "./profile-DGt_e-Nx.js";
4
4
  import { a as readGitTrack, i as localstorePath } from "./service-DDmHSglV.js";
5
- import { d as constraintCognitiveTrajectory, m as profileMsmWhitelist, n as PLUGIN_SOURCE, o as readLastBound, p as createProfilePromptReader, u as buildTrajectoryBasePrompt, v as ACC_VERSION } from "./message-source-HLXLQuvR.js";
5
+ import { d as constraintCognitiveTrajectory, m as profileMsmWhitelist, n as PLUGIN_SOURCE, o as readLastBound, p as createProfilePromptReader, u as buildTrajectoryBasePrompt, v as ACC_VERSION } from "./message-source-Cq4PsuES.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";
@@ -1,4 +1,4 @@
1
- import { f as hostSettings } from "./ccc-roots-CR1IWLDJ.js";
1
+ import { f as hostSettings } from "./ccc-roots-CvgsUnFW.js";
2
2
  //#region src/surface/settings.ts
3
3
  /**
4
4
  * 设置面板命名空间 = **profile 条目 id**(v0.1.7 起;与旧 `settings.yaml` 段名逐字相同)。
@@ -69,8 +69,15 @@
69
69
  * **不判周期、不自动续跑、不改任何会话日志**(是否续、续谁、几点续 = CCC 的事)。
70
70
  * ⚠️ 判据的锋利处:**只认"以 interrupted 结尾"**,不认"曾经中断过"—— 长会话历史上
71
71
  * 可中断几十次(实测单会话 33 次),按"曾经"判会把早已恢复的会话全部当成待续。
72
+ * 2026-10-22(owner 追加令「我希望实现的是 continue-all-interrupted 方法,调用后自动找到
73
+ * 8h 内所有 dsh 会话注入简单的 continue 进行唤醒,这样 CCC 就不用动脑子了」):
74
+ * 新增 **`continue-all-interrupted`** = `interrupted` 的**动作版**(扫 → 逐条注入续跑消息)。
75
+ * 判据(R↓,两者为何并存而不合并):`interrupted` 是**观察**(只读,零副作用),
76
+ * `continue-all-interrupted` 是**动作**(会真起 agent、真消耗算力)。
77
+ * ⇒ 观察与动作**必须分开可调用** —— 想看一眼清单却误触发全量续跑,是不可接受的副作用。
78
+ * ⚠️ 边界不变:ACC 仍**不判周期**(何时调用归调用方),只是把"调用一次要做完什么"补齐。
72
79
  */
73
- type CognitiveTrajectoryAction = 'list' | 'show' | 'create' | 'use' | 'rebuild' | 'archive' | 'uid' | 'send-now' | 'send-later' | 'cro-guide' | 'resident' | 'interrupted';
80
+ type CognitiveTrajectoryAction = 'list' | 'show' | 'create' | 'use' | 'rebuild' | 'archive' | 'uid' | 'send-now' | 'send-later' | 'cro-guide' | 'resident' | 'interrupted' | 'continue-all-interrupted';
74
81
  export declare const COGNITIVE_TRAJECTORY_ACTIONS: readonly CognitiveTrajectoryAction[];
75
82
  /**
76
83
  * 读取 Session 事件序列(v1.28.1 适配 0.1.2-rc.1 补齐):rc.1 起官方 Session 类
@@ -119,4 +119,53 @@ export declare function scanInterruptedSessions(projectDir: string, options?: {
119
119
  * 回退到"扫整个 sessions root"或直接报未找到。
120
120
  */
121
121
  export declare function projectDirNameForCwd(cwd: string): string;
122
+ /** 单条续跑结果 */
123
+ export interface ResumeOutcome {
124
+ sessionId: string;
125
+ /** 是否已把消息投进该会话 */
126
+ ok: boolean;
127
+ /** 投递路径:live = 已在跑(直接注入)|cold-resume = 冷载入后注入 */
128
+ how?: string;
129
+ /** 失败原因 */
130
+ error?: string;
131
+ }
132
+ /**
133
+ * 续跑正文(**简单、稳定、不含版本号**)。
134
+ *
135
+ * 判据(为什么这么短):本动作的用途是**把被打断的会话推回工作状态**,
136
+ * 不是替它重述任务 —— 被打断那一轮的上下文就在它自己的日志里。
137
+ * ⇒ 正文只做三件事:① 说明发生了什么;② 提示**先核对副作用**;③ 让它接着做。
138
+ *
139
+ * 🔴 **为什么要写"先核对副作用"**:中断时可能有「有 call 无 result」的工具调用,
140
+ * 它们的副作用**未知**(可能已写文件 / 已发消息)。若模型把那一轮整段重放,
141
+ * 会**重复执行**。这句话是给模型的护栏,不是客套。
142
+ */
143
+ export declare function buildContinueText(sessionId: string, turn: number | null, pendingTools: string[]): string;
144
+ /**
145
+ * 把一个 agent 唤醒(注入一条续跑消息)。
146
+ *
147
+ * 两条路径(与 `wake/scheduler.ts` 的 `sendToCognitiveTrajectory` 同源判据):
148
+ * - **live**:`agents.get(id)` 拿得到 ⇒ 目标在跑(或被加载)⇒ `steer` 当场注入当前轮;
149
+ * `steer` 不可用则退回 `followup`(宁可排队,不可静默丢)。
150
+ * - **cold-resume**:`sessionController.resolveAgent(id)` 冷载入后同样注入。
151
+ *
152
+ * ⚠️ 冷会话载入**会真起一个 agent**(消耗真实算力)⇒ 调用方必须自己决定要不要,
153
+ * 本函数不做数量限制(那是策略,归调用者)。
154
+ */
155
+ export declare function createResumeOne(deps: {
156
+ agents: {
157
+ get?: (id: string) => unknown;
158
+ } | undefined;
159
+ sessionController: {
160
+ resolveAgent?: (id: string) => Promise<{
161
+ agent?: unknown;
162
+ error?: string;
163
+ }>;
164
+ } | undefined;
165
+ makeMessage: (text: string) => unknown;
166
+ }): (hit: {
167
+ sessionId: string;
168
+ turn: number | null;
169
+ pendingTools: string[];
170
+ }) => Promise<ResumeOutcome>;
122
171
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shgroup/dsh-serenity-hooks",
3
- "version": "1.87.4",
3
+ "version": "1.87.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": {