Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
* text=auto eol=lf
*.tgz binary
*.pt binary
runtime/** linguist-vendored -whitespace
3 changes: 2 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,5 @@ jobs:
release/dsh-tmcra-memory-*.tgz \
release/SHA256SUMS \
--verify-tag \
--generate-notes
--generate-notes \
--prerelease
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## 1.0.0-rc.1 - 2026-09-06

- Add the redesigned local memory workspace, provider configuration, knowledge/graph views, task continuity, session modes, and recall budgets.
- Support confirmed targeted feedback and prevent disabled or correction-discussion turns from later queue replay.
- Add three pinned embedding/reranker profiles and Windows runtime preview controls; explicit local identity bypasses cloud login and disables cloud model task execution.
- Ship the verified backend with automatic private Python setup and local identity discovery. `local-install` opens setup without a TMCRA account or server; stale cloud requests are blocked after local selection.
- Ship all generated runtime chunks and workspace assets. Full-local compiler, organizer, and restart acceptance remains incomplete.

## 0.1.7 - 2026-09-04

- Activate the configured Writer and background-organizer providers through the authenticated TMCRA user-provider task protocol.
Expand Down
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ Cross-app continuity applies to memories that have reached TMCRA and requires bo

## What it does

Development branch adds a local memory control panel: `dsh-tmcra-memory memory --scope EXACT_PROJECT_SCOPE --session EXACT_SESSION_ID`. It offers tasks, source corrections, ignore/restore, normal/recall-only/off modes, and a 12000-character default recall budget. Disabled periods are never automatically backfilled; already submitted remote work is retained. Effective corrections require the corresponding backend update. New features are not yet published.

- Continues one project across TMCRA-connected tools such as Codex and DeepSeek Harness.
- Recalls user-global and current-project memory before the first model request of each turn.
- Continues project work across separate Harness conversations.
Expand Down Expand Up @@ -61,17 +63,17 @@ During the initial release period, TMCRA accounts are free to use with no memory
## Install the preview tarball

```bash
dsh plugin --profile web add https://github.com/reshuibuduo/tmcra-plugin-deepseek-harness/releases/download/v0.1.7/dsh-tmcra-memory-0.1.7.tgz
dsh plugin --profile web add https://github.com/reshuibuduo/tmcra-plugin-deepseek-harness/releases/download/v1.0.0-rc.1/dsh-tmcra-memory-1.0.0-rc.1.tgz
dsh plugin --profile web exec dsh-tmcra-memory login
dsh --profile web --dump-config
dsh web
```

Harness serves its Web UI at `http://127.0.0.1:3080` by default.

The package contributes `cordis.patch.yml`, so the install command activates the plugin in the selected profile. Prefer the prebuilt release tarball. A locally downloaded copy can also be installed with `dsh plugin --profile web add ./dsh-tmcra-memory-0.1.7.tgz`. Installing from a Git source may require an explicit `pnpm` build-script allowance.
The package contributes `cordis.patch.yml`, so the install command activates the plugin in the selected profile. Prefer the prebuilt release tarball. A locally downloaded copy can also be installed with `dsh plugin --profile web add ./dsh-tmcra-memory-1.0.0-rc.1.tgz`. Installing from a Git source may require an explicit `pnpm` build-script allowance.

DSH `0.1.1-rc.2` on Windows can still re-anchor a local package path incorrectly when the path contains spaces or non-ASCII characters. Copy the tarball to a short ASCII path first, such as `D:\\dsh-packages\\dsh-tmcra-memory-0.1.7.tgz`. The release URL above is not affected.
DSH `0.1.1-rc.2` on Windows can still re-anchor a local package path incorrectly when the path contains spaces or non-ASCII characters. Copy the tarball to a short ASCII path first, such as `D:\\dsh-packages\\dsh-tmcra-memory-1.0.0-rc.1.tgz`. The release URL above is not affected.

## Connect your TMCRA account

Expand All @@ -94,6 +96,14 @@ Harness keeps credential values out of settings and model requests. A model-oper

## Configure local Writer and organizer providers

### Full-local Windows preview

The package includes the full backend and E5/MiniLM, BGE-M3/BGE reranker, and Qwen3 embedding/reranker profiles. After installing the DSH plugin, run `dsh-tmcra-memory local-install` and choose a profile on the installation page. This entry requires no TMCRA login. Python, dependencies and verified model files are prepared automatically, with a private local identity discovered by DSH after restart. Windows x64 is supported; preinstalled Python and TMCRA servers/accounts are unnecessary. First-time downloads require internet. Existing cloud credentials are retained; stale cloud memory connections and background cloud model requests are blocked after local selection. Failed setup retains local selection. Clear an advanced `TMCRA_CONFIG_FILE` override before automatic setup.

CPU ingest/raw recall passed a synthetic test. Complex compilation timed out; organizer and full-service restart acceptance remains pending. Lightweight startup requires approximately 6.3 GiB free memory. See the [acceptance record](https://github.com/reshuibuduo/tmcra/blob/v1.0.0-rc.1/docs/LOCAL_DEPLOYMENT_PREVIEW.zh-CN.md). A host configured with a cloud main model can still send recalled evidence to its own provider.

### Separate provider APIs

Open the local setup page after installing the plugin:

```bash
Expand Down
22 changes: 19 additions & 3 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ Agent 回答前,TMCRA 会找回与当前问题有关的用户要求、决策

## 已实现能力

1.0.0-rc.1 新增任务接续、会话模式、完整证据块预算和本机记忆控制台。使用 `dsh-tmcra-memory memory --scope <当前项目的精确scope> --session <当前会话ID>` 打开面板;可管理任务、查看来源、纠错、忽略或恢复。三种模式为 `normal`、`recall_only`、`off`。关闭期间的内容不会在恢复后补写;已提交的远端任务保持原状态。有效纠错需要服务端反馈接口同步更新,线上服务须单独升级验收。

工作台现已集成 Writer / 后台整理 API 配置、个人知识库和知识图谱。模型密钥只在本机表单输入并保存在受保护文件中,读取配置仅返回是否已保存;测试使用虚构 JSON 推理样本。知识与图谱分别读取已有服务接口,支持范围切换、搜索、节点选择及原始证据追溯。

在支持工具与原生 ApprovalService 的 DSH 中,`tmcra_memory_control` 会对真实的记忆纠错请求先暂停该回合的自动写入,然后在聊天内展示来源、拟修改内容和范围,请用户确认。拒绝、取消或无确认渠道均不提交;已标识的其他正常回合不受影响。语义识别由宿主 Agent 按工具说明完成,假设性讨论不构成修改授权。此流程已通过 DSH 0.1.1-rc.2 原生工具/确认服务的隔离测试。

预算默认 12000 字符;仅在证据仍位于实际模型上下文时跨轮去重。任务状态按凭据指纹和项目隔离;多个本机适配器可使用同一个 `TMCRA_MEMORY_STATE_DIR`。不同登录凭据的本机任务独立,已提交的长期记忆通过相同服务端项目 scope 共享。

- 同一个项目可以在 Codex、DeepSeek Harness 等 TMCRA 接入工具之间继续推进。
- 每轮第一次模型请求前自动召回,无需 Agent 主动调用工具。
- 新开一个 Harness 对话后,可以继续同一项目的工作进度。
Expand Down Expand Up @@ -61,17 +69,17 @@ Agent 回答前,TMCRA 会找回与当前问题有关的用户要求、决策
## 安装技术预览包

```bash
dsh plugin --profile web add https://github.com/reshuibuduo/tmcra-plugin-deepseek-harness/releases/download/v0.1.7/dsh-tmcra-memory-0.1.7.tgz
dsh plugin --profile web add https://github.com/reshuibuduo/tmcra-plugin-deepseek-harness/releases/download/v1.0.0-rc.1/dsh-tmcra-memory-1.0.0-rc.1.tgz
dsh plugin --profile web exec dsh-tmcra-memory login
dsh --profile web --dump-config
dsh web
```

Harness Web UI 默认地址为 `http://127.0.0.1:3080`。

压缩包内含 `cordis.patch.yml`,安装后会自动加入指定 Profile 的配置层。建议使用 Release 中已经构建好的 `.tgz`。下载到本地后,也可以执行 `dsh plugin --profile web add ./dsh-tmcra-memory-0.1.7.tgz`。从 Git 源码安装可能还需要在 `pnpm` 中单独允许构建脚本。
压缩包内含 `cordis.patch.yml`,安装后会自动加入指定 Profile 的配置层。建议使用 Release 中已经构建好的 `.tgz`。下载到本地后,也可以执行 `dsh plugin --profile web add ./dsh-tmcra-memory-1.0.0-rc.1.tgz`。从 Git 源码安装可能还需要在 `pnpm` 中单独允许构建脚本。

DSH `0.1.1-rc.2` 的 Windows 版仍可能把包含空格或非 ASCII 字符的本地包路径错误重组。请先把压缩包复制到纯 ASCII 短路径,例如 `D:\\dsh-packages\\dsh-tmcra-memory-0.1.7.tgz`;上面的 Release URL 不受影响。
DSH `0.1.1-rc.2` 的 Windows 版仍可能把包含空格或非 ASCII 字符的本地包路径错误重组。请先把压缩包复制到纯 ASCII 短路径,例如 `D:\\dsh-packages\\dsh-tmcra-memory-1.0.0-rc.1.tgz`;上面的 Release URL 不受影响。

## 连接 TMCRA 账号

Expand All @@ -94,6 +102,14 @@ Harness 不会把凭据值写入普通设置或模型请求。如果模型控制

## 配置本地 Writer 与后台整理模型

### 完整本地部署预览

插件包内置完整后端,提供 E5/MiniLM、BGE-M3/BGE reranker、Qwen3 embedding/reranker 三档。装入 DSH 后运行 `dsh-tmcra-memory local-install`,免登录打开安装页并选择档位。Python、依赖和校验后的模型自动准备,本机身份自动生成,重启 DSH 后自动发现连接。支持 Windows x64,无需预装 Python、TMCRA 账号或 TMCRA 服务器。首次下载需要联网。原云端凭据保留;本地选择生效后,旧云端连接和后台云模型请求会被拦截,安装失败也保持本地选择。高级用户应先清除显式 `TMCRA_CONFIG_FILE` 覆盖。

CPU 合成写入和原文召回已通过;复杂编译超时,后台整理和完整重启恢复仍待验收。轻量启动需约 6.3GiB 空闲内存。详见[验收说明](https://github.com/reshuibuduo/tmcra/blob/v1.0.0-rc.1/docs/LOCAL_DEPLOYMENT_PREVIEW.zh-CN.md)。宿主主模型在云端时,召回证据仍可能由宿主发往云端。

### 配置独立模型 API

安装后执行:

```bash
Expand Down
Binary file added assets/tmcra-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
97 changes: 90 additions & 7 deletions dist/cli.mjs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
#!/usr/bin/env node
import { a as createMemoryActions, i as FilePendingTurnQueue, n as readLocalProviderConfig, o as startMemoryCenter, t as localProviderStageReady } from "./local-provider-config-CDBjMheh.mjs";
import { n as readFullLocalConfig } from "./full-local-config-BiZAIc60.mjs";
import { createHash, randomBytes } from "node:crypto";
import { existsSync } from "node:fs";
import { chmod, mkdir, readFile, rm, stat } from "node:fs/promises";
import { homedir, platform } from "node:os";
import { dirname, join, resolve } from "node:path";
import { chmod, mkdir, readFile, rm, stat } from "node:fs/promises";
import { spawn } from "node:child_process";
import { existsSync } from "node:fs";
import { fileURLToPath, pathToFileURL } from "node:url";
import { withFileLock, writeFileAtomic } from "@deepseek-ai/dsh-atomic-write";
import { Document, isMap, parseDocument } from "yaml";
Expand Down Expand Up @@ -58,7 +60,7 @@ async function postJson(fetchImpl, url, body) {
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"User-Agent": "dsh-tmcra-memory/0.1.7"
"User-Agent": "dsh-tmcra-memory/1.0.0-rc.1"
},
body: JSON.stringify(body),
signal: controller.signal
Expand Down Expand Up @@ -175,6 +177,15 @@ async function updateHarnessCredentials(updates, dshHome) {
return path;
}
async function readHarnessCredentialStatus(dshHome) {
const local = await readFullLocalConfig();
if (local) return {
configured: true,
credentialsPath: "private-local-installation",
apiBaseUrl: local.baseUrl,
globalScope: local.globalScope,
projectScopePrefix: local.projectScopePrefix,
deploymentMode: "local"
};
const path = credentialsPath(dshHome);
if (!existsSync(path)) return {
configured: false,
Expand All @@ -190,6 +201,24 @@ async function readHarnessCredentialStatus(dshHome) {
projectScopePrefix: value[CREDENTIAL_KEYS.projectScopePrefix] || null
};
}
/** Local control-panel transport only. Never print this object or send it to a model. */
async function readHarnessMemoryConnection(dshHome) {
const local = await readFullLocalConfig();
if (local) return local;
const path = credentialsPath(dshHome);
await assertOwnerOnly(path);
const values = existsSync(path) ? credentialsDocument(await readFile(path, "utf8")).toJS() : {};
const apiKey = process.env.TMCRA_API_KEY || values[CREDENTIAL_KEYS.apiKey];
const baseUrl = process.env.TMCRA_API_BASE_URL || values[CREDENTIAL_KEYS.apiBaseUrl] || "https://api.tmcra.com";
const url = new URL(baseUrl);
if (url.protocol !== "https:" || url.username || url.password || url.search || url.hash) throw new Error("TMCRA memory API must be an HTTPS origin");
if (!apiKey) throw new Error("Sign in with dsh-tmcra-memory login first");
return {
apiKey,
baseUrl,
globalScope: process.env.TMCRA_GLOBAL_SCOPE || values[CREDENTIAL_KEYS.globalScope]
};
}
async function atomicPending(path, value) {
await mkdir(dirname(path), { recursive: true });
await writeFileAtomic(path, `${JSON.stringify(value, null, 2)}\n`, {
Expand Down Expand Up @@ -277,7 +306,7 @@ async function authorizeDeepSeekHarness(options = {}) {
const started = await postJson(fetchImpl, `${authBaseUrl}/api/device/v1/authorizations`, {
clientId: CLIENT_ID,
clientName: `DeepSeek Harness (${platform()} ${process.arch})`,
clientVersion: "0.1.7",
clientVersion: "1.0.0-rc.1",
codeChallenge: challenge,
codeChallengeMethod: "S256"
});
Expand Down Expand Up @@ -383,9 +412,9 @@ function option(name) {
function printJson(value) {
process.stdout.write(`${JSON.stringify(value)}\n`);
}
async function runProviderSetup() {
async function runProviderSetup(filename = "provider_setup.mjs") {
const cliDirectory = dirname(fileURLToPath(import.meta.url));
const script = resolve(cliDirectory, "..", "scripts", "provider_setup.mjs");
const script = resolve(cliDirectory, "..", "scripts", filename);
const forwarded = process.argv.slice(3);
await new Promise((resolvePromise, reject) => {
const child = spawn(process.execPath, [script, ...forwarded], {
Expand All @@ -403,6 +432,60 @@ async function main() {
const command = process.argv[2] || "help";
const json = process.argv.includes("--json");
const dshHome = option("--dsh-home");
if (command === "local-install") {
await runProviderSetup("local_setup.mjs");
return;
}
if (command === "memory") {
const connection = await readHarnessMemoryConnection(dshHome);
const scope = option("--scope");
const sessionId = option("--session");
if (!scope || !sessionId) throw new Error("Use memory --scope EXACT_PROJECT_SCOPE --session EXACT_SESSION_ID");
const queue = new FilePendingTurnQueue(join(resolveDshHome(dshHome), "tmcra", "deepseek-harness-pending-turns.json"));
const invoke = createMemoryActions({
config: connection,
scope,
sessionId,
globalScope: connection.globalScope,
status: async () => ({ pending: (await queue.list()).filter((row) => row.scopeName === scope).map((row) => ({
id: row.idempotencyKey,
jobId: row.jobId,
state: row.observedStatus || "queued"
})) }),
request: async (path, options) => {
const provider = await readLocalProviderConfig().catch(() => null);
const localHeaders = {};
if (provider && localProviderStageReady(provider, "writer")) localHeaders["X-TMCRA-Writer-Execution"] = "user-provider";
if (provider && localProviderStageReady(provider, "organizer")) localHeaders["X-TMCRA-Organizer-Execution"] = "user-provider";
const response = await fetch(`${connection.baseUrl.replace(/\/+$/u, "")}${path}`, {
method: options.method,
headers: {
Authorization: `Bearer ${connection.apiKey}`,
"Content-Type": "application/json",
"X-TMCRA-Client-Platform": "deepseek_harness",
"X-TMCRA-Integration-ID": "tmcra-deepseek-harness",
...localHeaders,
...options.headers
},
body: JSON.stringify(options.body),
signal: AbortSignal.timeout(3e4),
redirect: "error"
});
if (!response.ok) throw new Error(`TMCRA request failed (${response.status}); check authorization and service version`);
return response.json();
}
});
const center = await startMemoryCenter({
invoke,
open: !process.argv.includes("--no-open")
});
printJson({
url: center.url,
credentialsLocalOnly: true
});
await new Promise((done) => center.server.once("close", done));
return;
}
if (command === "setup" || command === "configure-models") {
await runProviderSetup();
return;
Expand Down Expand Up @@ -447,7 +530,7 @@ async function main() {
else process.stdout.write(`TMCRA credentials were removed from ${path}. Revoke the connection in your TMCRA account if this device is no longer trusted.\n`);
return;
}
process.stdout.write(`Usage:\n dsh-tmcra-memory setup [--no-open] [--config-file PATH] [--json]\n dsh-tmcra-memory login [--no-open] [--auth-base-url URL] [--dsh-home PATH] [--json]\n dsh-tmcra-memory status [--dsh-home PATH] [--json]\n dsh-tmcra-memory logout [--dsh-home PATH] [--json]\n`);
process.stdout.write(`Usage:\n dsh-tmcra-memory local-install [--no-open]\n dsh-tmcra-memory setup [--no-open] [--config-file PATH] [--json]\n dsh-tmcra-memory memory --scope EXACT_PROJECT_SCOPE --session EXACT_SESSION_ID [--no-open] [--dsh-home PATH]\n dsh-tmcra-memory login [--no-open] [--auth-base-url URL] [--dsh-home PATH] [--json]\n dsh-tmcra-memory status [--dsh-home PATH] [--json]\n dsh-tmcra-memory logout [--dsh-home PATH] [--json]\n`);
}
const invokedPath = process.argv[1] ? pathToFileURL(process.argv[1]).href : "";
if (import.meta.url === invokedPath) await main().catch((error) => {
Expand Down
Loading
Loading