🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

Hindsight 记忆设置 Echo-Note/dsh-hindsight-settings

DeepSeek Harness
Echo-Note21 天前有提交已提供中文文档扫描:含敏感能力

在图形界面里编辑 Hindsight 记忆配置文件

29.9/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/14 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add Echo-Note/dsh-hindsight-settings
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:待复验
是什么
dsh 原生插件 · chat
装得上吗
曾在 dsh 0.2.0-rc.2 下真实安装成功,但当前 dsh 已更新至 0.2.1-rc.5,本站尚未在新版下复验
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 21 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件
查看扫描证据(共 59 处,展示前 49 条)
  • 读取本地文件
    lib/index.js:798
    text = readFileSync(path, "utf8");
  • 写入本地文件
    lib/index.js:926
    mkdirSync(directory, { recursive: true, mode: 448 });
  • 写入本地文件
    lib/index.js:928
    writeFileSync(temporary, `${JSON.stringify(values, null, 2)}
  • 写入本地文件
    lib/index.js:933
    renameSync(temporary, path);
  • 读取本地文件
    lib/index.js:1015
    const parsed = JSON.parse(readFileSync2(path, "utf8"));
  • 写入本地文件
    lib/index.js:1051
    mkdirSync2(dirname2(path), { recursive: true });
  • 写入本地文件
    lib/index.js:1052
    writeFileSync2(path, `${JSON.stringify(next, null, 2)}
  • 读取本地文件
    src/client/model.test.ts:253
    const source = readFileSync(join(CLIENT_DIR, file), "utf8");
  • 读取本地文件
    src/client/model.test.ts:260
    const source = readFileSync(join(CLIENT_DIR, "model.ts"), "utf8");
  • 读取本地文件
    src/config-store.test.ts:22
    const written = (): Record<string, unknown> => JSON.parse(readFileSync(file, "utf8"));
  • 写入本地文件
    src/config-store.test.ts:46
    writeFileSync(file, "{ not json");
  • 写入本地文件
    src/config-store.test.ts:53
    writeFileSync(
  • 写入本地文件
    src/config-store.test.ts:87
    writeFileSync(
  • 写入本地文件
    src/config-store.test.ts:102
    writeFileSync(file, JSON.stringify({ bankId: "same" }));
  • 读取本地文件
    src/config-store.test.ts:103
    const before = statSync(file).mtimeMs;
  • 读取本地文件
    src/config-store.test.ts:106
    expect(statSync(file).mtimeMs).toBe(before);
  • 写入本地文件
    src/config-store.test.ts:110
    writeFileSync(file, JSON.stringify({ bankId: "x", logLevel: "debug" }));
  • 写入本地文件
    src/config-store.test.ts:117
    writeFileSync(file, "{ broken");
  • 读取本地文件
    src/config-store.test.ts:119
    expect(readFileSync(file, "utf8")).toBe("{ broken");
  • 读取本地文件
    src/config-store.test.ts:124
    expect(statSync(file).mode & 0o777).toBe(0o600);
  • 读取本地文件
    src/config-store.test.ts:129
    expect(() => readFileSync(file, "utf8")).toThrow();
  • 读取本地文件
    src/config-store.ts:55
    text = readFileSync(path, "utf8");
  • 写入本地文件
    src/config-store.ts:277
    mkdirSync(directory, { recursive: true, mode: 0o700 });
  • 写入本地文件
    src/config-store.ts:279
    writeFileSync(temporary, `${JSON.stringify(values, null, 2)}\n`, {
  • 写入本地文件
    src/config-store.ts:283
    renameSync(temporary, path);
  • 执行外部命令固定命令
    src/fields.test.ts:125
    committed = execFileSync("git", ["show", "HEAD:src/fields.ts"], {
  • 读取本地文件
    src/fields.test.ts:182
    const shipped = readFileSync(join(packageRoot, "src", "fields.ts"), "utf8");
  • 读取本地文件
    src/fields.test.ts:202
    const manifest = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf8")) as {
  • 读取本地文件
    src/fields.test.ts:220
    const patch = readFileSync(join(packageRoot, patchPath ?? ""), "utf8");
  • 写入本地文件
    src/index.test.ts:56
    writeFileSync(file, JSON.stringify({ bankId: "gaoxiaogang", reflectTimeoutMs: 20000 }));
  • 写入本地文件
    src/index.test.ts:70
    writeFileSync(
  • 写入本地文件
    src/index.test.ts:83
    writeFileSync(file, JSON.stringify({ apiToken: "super-secret", logLevel: "debug" }));
  • 写入本地文件
    src/index.test.ts:95
    writeFileSync(file, "{ broken");
  • 写入本地文件
    src/index.test.ts:103
    writeFileSync(file, JSON.stringify({ apiToken: "tok", banks: { "a::b": {} } }));
  • 读取本地文件
    src/index.test.ts:108
    expect(JSON.parse(readFileSync(file, "utf8"))).toEqual({
  • 写入本地文件
    src/index.test.ts:117
    writeFileSync(file, JSON.stringify({ bankId: "team", logLevel: "debug" }));
  • 读取本地文件
    src/index.test.ts:122
    expect(JSON.parse(readFileSync(file, "utf8"))).toEqual({ logLevel: "debug" });
  • 读取本地文件
    src/index.test.ts:132
    expect(readFileSync(file, "utf8")).toBe("{}");
  • 读取本地文件
    src/index.test.ts:140
    const trail = JSON.parse(readFileSync(statusPath(), "utf8")) as {
  • 读取本地文件
    src/index.test.ts:186
    const written = JSON.parse(readFileSync(file, "utf8")) as Record<string, unknown>;
  • 读取本地文件
    src/index.test.ts:200
    expect(JSON.parse(readFileSync(file, "utf8"))).toEqual({});
  • 写入本地文件
    src/status.test.ts:39
    writeFileSync(statusPath(file), "{ not json");
  • 读取本地文件
    src/status.test.ts:52
    expect(statSync(statusPath(file)).mode & 0o777).toBe(0o600);
  • 读取本地文件
    src/status.ts:46
    const parsed = JSON.parse(readFileSync(path, "utf8")) as Partial<StatusFile>;
  • 写入本地文件
    src/status.ts:97
    mkdirSync(dirname(path), { recursive: true });
  • 写入本地文件
    src/status.ts:98
    writeFileSync(path, `${JSON.stringify(next, null, 2)}\n`, { encoding: "utf8", mode: 0o600 });
  • 读取本地文件
    src/typert.test.ts:113
    const manifestJson = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf8")) as {
  • 读取本地文件
    src/upstream.test.ts:26
    return candidates.find((candidate) => existsSync(candidate));
  • 读取本地文件
    src/upstream.test.ts:30
    const source = bundlePath === undefined ? undefined : readFileSync(bundlePath, "utf8");
扫描于 2026/11/3(1 天前) · 范围 入口闭包 + 全包扫描 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

DSH 里 Hindsight 编程智能体插件的设置页:在 DeepSeek Harness 图形界面里编辑 ~/.hindsight/coding-agent.json

README

由 DeepSeek 最新模型翻译生成
@Echo-Note/dsh-hindsight-settings DeepSeek Harness 里的 Hindsight 设置页一个 DeepSeek Harness(DSH)配套插件,在 Settings 中新增 Hindsight 记忆设置 页面,使得 ~/.hindsight/coding-agent.json 可以直接在 GUI 里编辑,而不必手工修改。 它是刻意做成配套插件的。@vectorize-io/hindsight-coding-agents 以 子路径行(…/coding-agents/dsh)挂载,而 DSH 的客户端模块系统只会给 specifier 为裸包名的那一行附上浏览器半边 —— 因此该包若不改变每个既有用户的挂载方式,就无法自带设置页面。它也没有声明任何 Config:它不从 dsh 导入任何东西,而是从自己的文件解析设置,随包发布的设置表单(由 schema 派生、持久化进 profile patch)够不到这个文件。因此本包自带页面和自己的宿主服务,对该插件不做任何改动。
展开完整文档(README 剩余 1 节)
@Echo-Note/dsh-hindsight-settings

DeepSeek Harness 里的 Hindsight 设置页一个 DeepSeek Harness(DSH)配套插件,在 Settings 中新增 Hindsight 记忆设置 页面,使得 ~/.hindsight/coding-agent.json 可以直接在 GUI 里编辑,而不必手工修改。

它是刻意做成配套插件的。@vectorize-io/hindsight-coding-agents 以 子路径行(…/coding-agents/dsh)挂载,而 DSH 的客户端模块系统只会给 specifier 为裸包名的那一行附上浏览器半边 —— 因此该包若不改变每个既有用户的挂载方式,就无法自带设置页面。它也没有声明任何 Config:它不从 dsh 导入任何东西,而是从自己的文件解析设置,随包发布的设置表单(由 schema 派生、持久化进 profile patch)够不到这个文件。因此本包自带页面和自己的宿主服务,对该插件不做任何改动。

安装

从 GitHub 安装 —— 该包直接从本仓库消费,它的 @vectorize-io/hindsight-coding-agents 依赖会随之安装,所以一次安装即可得到两者:

Any profile except a packaged Desktop one, whose profile the CLI refuses to write:
dsh plugin --profile <profile> add github:Echo-Note/dsh-hindsight-settings

在 桌面应用 中(即 Electron 外壳所拥有的那个 profile),CLI 按设计会拒绝写入;此时应改从 GUI 安装 —— Settings → Plugins → install,粘贴同一个 spec:

github:Echo-Note/dsh-hindsight-settings

它解析到的那个 40 字符的 commit 由包管理器的 lockfile 固定,所以之后的一次 git push 不会悄悄改变你运行的内容:要移动它,就重新安装(或更新)。Git 安装不构建任何东西 —— 编译后的 lib/ 已提交 —— 所以安装是一次检出,而不是一次构建。

带 scope 命名是可选的。github:Echo-Note/dsh-hindsight-settings 会按本包 package.json 里的名字安装它;要强制使用另一个键,就用 npm alias 形式,本仓库自己的 dry-run 用的正是这种:

dsh plugin --profile <profile> add '@Echo-Note/dsh-hindsight-settings@github:Echo-Note/dsh-hindsight-settings'

从本地检出安装(在编辑本包期间):

git clone https://github.com/Echo-Note/dsh-hindsight-settings.git
cd dsh-hindsight-settings
npm install # dev dependencies only; nothing is needed at runtime but the peer packages
npm run build # optional: refreshes lib/ from src/
dsh plugin --profile <profile> add link:"$PWD"

link:(而不是 file:)才是你可能要编辑的包该用的 spec:file: 会把快照复制进 profile,link: 则做符号链接,所以重建后的浏览器半边会在下一次页面加载时被采用。

唯一需要手动的一步

只有当 profile 在 dsh.profile.bundles 里选中某个 bundle 时,包里的 bundle 才会被挂载,而 dsh 自己的 plugin-manager README 指出 "an unselected plain dependency is left out"(未选中的普通依赖会被略过)—— 管理器会列出某个依赖提供的 bundle,但不会选中它们。所以在安装本包之后,要在 Settings → Plugins 里启用一次 Hindsight(按名字安装该 bundle,dsh plugin --profile <profile> add @vectorize-io/hindsight-coding-agents,效果相同)。

dsh 没有 bundle-depends-on-bundle 字段来表达这件事(DshManifest 只携带 manifestVersion、bundle.patch、 client、engines.dsh),而另一种做法 —— 由我们的 patch 直接插入 Hindsight 那一行 —— 在它自己的 bundle 也被启用时会重复组合同一行,因为 patch 的 insert 追加时不会对 entry id 去重。

宿主半边、./typert 清单和浏览器 bundle 都在启动时读取,而 dsh 的插件管理器指出 "package replacements require restarting the process to load a fresh JavaScript module generation" (替换包需要重启进程才能加载新的 JavaScript 模块代次)—— 所以安装后要 重启一次。

工作原理

~/.hindsight/coding-agent.json ← the one file every Hindsight harness reads
▲ │
│ apply() │ describe() (host, src/service.ts + src/typert.host.ts)
│ ▼
ctx.provide('hindsightSettings') ──Remote──▶ POST /api/hindsightSettings/<method>
▲ │
└──────────────────────────────────────────────────┘
browser (src/client/index.tsx)
page in Settings, mounted via ctx.remote.$mount(contribution)

- 宿主发布一个 Cordis 服务;它的 ./typert 清单把 describe 和 apply 暴露给页面(docs/api-gateway.md)。
- 页面渲染来自 src/fields.ts 的每一个字段 —— 配置面的唯一声明 —— 并且只写回发生变化的部分。
用户清空的字段以 null 发送,这会删除该键,于是该项设置回退到环境变量,再回退到插件自身的默认值。
- 字段按分组各占一个标签页,另加一个 按项目(banks) 标签页。bank 标签页编辑 banks.<id>,上游正是靠它让某个仓库与共享的顶层有所不同;打开一个 bank 会调用 describe({ kind: "bank", id }),保存会调用 applyScoped(...)。paths.<dir> 只读列出。
- 文件没有设置的字段仍会显示其 实际生效 的值 —— 插件默认值 —— 并如此标注,而清空的单元格仍然意味着「删除该键」。在单元格真正发生变化之前不会写入任何内容。
- 密钥从不下发给页面:apiToken 显示为已设置但空白(「已设置(不显示明文)」),输入会替换它,只有显式的 清空 按钮才会移除它。这与 dsh 自己的设置服务一致,那里的 role('secret') 值不会出现在表单响应中。
- 没有任何东西经过 DSH 的设置表单或 profile patch。更早的一个修订试图把该文件镜像进本插件自己的 Config,好让随包发布的表单把它显示出来;一次真实安装以 _"HMR transactions cannot be nested"_(HMR 事务不能嵌套)拒绝了那次写入(该行挂载在加载器的事务内部,是一个连定时器都会继承的 AsyncLocalStorage 作用域),而表单也从未服务过该命名空间。直接与文件对话既更简单,也是宿主状态的文档化路径。

安全

- 只接管受管键:本包不认识的键,以及嵌套的 banks / paths / harnesses 段落,都原样保留。
- null 会删除一个键;没有别的删除方式,页面从未发送的字段则不受影响。
- 写入经由临时文件 + rename,权限为 0600 —— 该文件可能存放 apiToken。
- 无法解析的文件 绝不 被覆盖:页面会报告它并禁用保存。
- 非法值(类型错误、未知键、仅文件可编辑的嵌套映射)会在磁盘被触碰之前被拒绝。

接口字段

mapPathToBank、pages、customPages、recallOptions、retainMetadata、defaultBankConfig、 harnesses 以及已废弃的 autoReflect 在分组标签页中以 只读 显示:它们是单个表单字段无法表达的嵌套映射,上游把它们记为仅文件可编辑。页面逐字段说明这一点,而不是把它们藏起来。banks 和 paths 不是只读的: bank 标签页通过一次受作用域的写入编辑 banks.<id>,而文件里的 paths 段落只读列出。

优先级与改动何时生效

上游按 defaults → HINDSIGHT_* → 文件顶层 → harnesses.<name> → banks.<id> / paths.<dir> 解析,后者胜。
页面写的是顶层,所以同一键上的 harnesses.dsh 条目仍然胜出 —— 页面会给这些字段打标记。上游在插件加载时按 workspace 读取该文件一次,所以一次编辑要在 dsh 重启之后才会到达正在运行的会话;apiToken 是例外(它的客户端在服务器拒绝之后的下一次调用会重新读取该凭据,因此轮换它无需重启)。

故障排查

宿主半边会把它做过的事追加到 ~/.hindsight/dsh-settings-status.json:

{
"events": [
{
"at": "…", "step": "apply", "provided": "hindsightSettings", "entryId": "hindsight-settings", }, { "at": "…", "step": "describe", "path": "…/coding-agent.json", "error": null, "fields": 52 }, { "at": "…", "step": "apply", "changed": true, "removed": [] }, ], }

打开页面后没有 describe 行,说明浏览器从未到达该服务:先确认 Settings → Hindsight 记忆设置 条目存在,再看插件列表里页面本地的同步消息。apply 带 changed: false 表示文件里本来就是这样。

开发

npm install --legacy-peer-deps # pinned in .npmrc: npm's arborist crashes on vitest's peer set
npm test # host service, the file rules, the field table's drift guard
npm run build # lib/index.js + lib/typert.host.js (host) and lib/client.js (browser)
npm run test:smoke # bundle shape / laziness / registration smoke test
npm run typecheck
npm run format # prettier, the repo's .prettierrc

两个半边都落在 lib/,所以 npm run build 会先删除一次 lib/,然后按 host → client 构建;只有确实想重建一个半边时才用 npm run build:host / npm run build:client。

src/fields.ts 是配置面的唯一声明。src/upstream.test.ts 拿它对照 已安装的 Hindsight 插件检查(该插件的 bundle 保留着源码形态),所以升级那个插件会让本包的测试失败,而不是悄悄藏起一个新设置项。

许可证

Apache-2.0 —— 见 LICENSE。
预览分享卡片长什么样 ↓Echo-Note/dsh-hindsight-settings
分享 · DeepSeek Harness Hub
Echo-Note/dsh-hindsight-settings

在图形界面里编辑 Hindsight 记忆配置文件

这是你的仓库?认领条目

回到顶部