@thincoder/core 0.10.7 → 0.10.9
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/CHANGELOG.md +21 -0
- package/advisor/compaction.mjs +1 -1
- package/advisor/run.mjs +1 -1
- package/agent/chat-call.mjs +40 -27
- package/agent/child-marks.mjs +1 -1
- package/agent/dispatch-gates.mjs +7 -4
- package/agent/dispatch-run.mjs +1 -0
- package/agent/family-tools.mjs +13 -8
- package/agent/helpers.mjs +12 -10
- package/agent/image-heal.mjs +65 -0
- package/agent/light-round.mjs +4 -4
- package/agent/live-beat.mjs +4 -4
- package/agent/post-turn.mjs +34 -0
- package/agent/record-results.mjs +9 -1
- package/agent/run-stages.mjs +45 -10
- package/agent/setup-reminders.mjs +14 -13
- package/agent/setup.mjs +72 -48
- package/agent/spawn-child.mjs +1 -1
- package/agent/subagent-event.mjs +1 -1
- package/agent/suspension.mjs +2 -1
- package/agent/timers.mjs +8 -8
- package/agent/turn-loop.mjs +7 -1
- package/agent-tools/advisor.mjs +1 -1
- package/agent-tools/async-discard.mjs +40 -5
- package/agent-tools/async-settle.mjs +3 -1
- package/agent-tools/audit-block.mjs +5 -3
- package/agent-tools/batch-gate.mjs +198 -0
- package/agent-tools/batch-lifecycle.mjs +216 -36
- package/agent-tools/batch-paths.mjs +20 -20
- package/agent-tools/batch-skeleton.mjs +87 -0
- package/agent-tools/batch.mjs +11 -3
- package/agent-tools/checkpoint.mjs +1 -1
- package/agent-tools/context.mjs +28 -5
- package/agent-tools/design-slots.mjs +20 -7
- package/agent-tools/doc-check.mjs +75 -0
- package/agent-tools/eng.mjs +5 -3
- package/agent-tools/manifest.mjs +18 -18
- package/agent-tools/parent-channel.mjs +3 -3
- package/agent-tools/review-facts.mjs +2 -2
- package/agent-tools/settings.mjs +1 -1
- package/agent-tools/spawn-gates.mjs +108 -47
- package/agent-tools/ssh-session.mjs +486 -0
- package/agent-tools/ssh-transport.mjs +324 -0
- package/agent-tools/ssh-vault.mjs +291 -0
- package/agent-tools/subagent-scheduler.mjs +6 -5
- package/agent-tools/subagent-spawn.mjs +18 -11
- package/agent-tools/subagent.mjs +17 -9
- package/agent-tools/task.mjs +1 -1
- package/agent-tools/timer.mjs +8 -2
- package/agent-tools/zero-write-watch.mjs +2 -2
- package/agent-tools.mjs +3 -2
- package/attachments.mjs +4 -4
- package/browser/cdp.mjs +2 -2
- package/browser/launch.mjs +50 -4
- package/browser/snapshot.mjs +1 -1
- package/config-defaults.mjs +92 -0
- package/config-io.mjs +7 -2
- package/config-normalize.mjs +109 -0
- package/config-watch.mjs +2 -2
- package/config.mjs +88 -190
- package/declaration.mjs +5 -1
- package/doc-check/anchors.mjs +142 -0
- package/doc-check/index.mjs +210 -0
- package/doc-check/version.mjs +84 -0
- package/doc-check/width.mjs +132 -0
- package/file-refs.mjs +6 -6
- package/generate-title.mjs +1 -1
- package/hooks.mjs +1 -1
- package/i18n.mjs +13 -1
- package/ledger-cmd.mjs +314 -62
- package/ledger-db.mjs +122 -31
- package/ledger-migrate.mjs +18 -12
- package/ledger-read.mjs +6 -7
- package/ledger-tools.mjs +138 -77
- package/ledger.mjs +34 -62
- package/log.mjs +17 -3
- package/manifest-discovery.mjs +21 -18
- package/manifest-schema.mjs +17 -14
- package/manifest.mjs +37 -22
- package/mcp/transport-stdio.mjs +1 -1
- package/mcp.mjs +2 -2
- package/memory/core.mjs +1 -1
- package/memory/scan.mjs +1 -1
- package/memory/sweep.mjs +1 -1
- package/model-specs.mjs +7 -7
- package/notify-policy.mjs +6 -6
- package/package.json +2 -1
- package/permission.mjs +21 -1
- package/prompts/advisor-design.md +53 -23
- package/prompts/advisor-round1.md +34 -14
- package/prompts/advisor-round2.md +32 -19
- package/prompts/advisor-round3.md +34 -21
- package/prompts/common.md +148 -79
- package/prompts/consult-base.md +14 -8
- package/prompts/discipline-engineering.md +70 -66
- package/prompts/discipline-normal.md +86 -77
- package/prompts/persona-coder.md +6 -6
- package/prompts/persona-eng-coder.md +19 -18
- package/prompts/persona-eng-designer.md +40 -31
- package/prompts/persona-engineering.md +124 -92
- package/prompts/persona-explore.md +2 -2
- package/prompts/persona-normal.md +20 -17
- package/prompts/persona-plan.md +7 -7
- package/prompts/subagent-base.md +4 -4
- package/provider/anthropic.mjs +4 -2
- package/provider/core.mjs +4 -2
- package/provider/errors.mjs +8 -0
- package/provider/google.mjs +8 -1
- package/provider/normalize.mjs +42 -12
- package/provider/responses-request.mjs +4 -3
- package/provider/responses.mjs +2 -2
- package/provider/wait-status.mjs +1 -1
- package/provider-flows.mjs +1 -1
- package/queued.mjs +2 -2
- package/rules.mjs +4 -4
- package/session-gc.mjs +1 -1
- package/session-lifecycle.mjs +7 -7
- package/session-slot-write.mjs +2 -2
- package/session-slots-manifest.mjs +1 -1
- package/session.mjs +1 -1
- package/shell-candidates.mjs +2 -2
- package/shell-identity.mjs +1 -1
- package/team.mjs +63 -5
- package/think-off.mjs +3 -3
- package/token-ttl.mjs +1 -1
- package/token-window.mjs +1 -1
- package/tool-docs/bash.md +1 -1
- package/tool-docs/batch.md +1 -1
- package/tool-docs/browser.md +1 -1
- package/tool-docs/doc_check.md +54 -0
- package/tool-docs/fetch.md +3 -2
- package/tool-docs/ledger.md +7 -5
- package/tool-docs/manifest.md +14 -2
- package/tool-docs/ssh.md +51 -0
- package/tool-docs/subagent.md +6 -9
- package/tool-docs/timer.md +2 -1
- package/tool-docs/websearch.md +3 -1
- package/tools/browser.mjs +1 -1
- package/tools/execute.mjs +1 -1
- package/tools/git-run.mjs +2 -2
- package/tools/git.mjs +8 -8
- package/tools/index.mjs +3 -0
- package/tools/ops.mjs +1 -1
- package/tools/process-tree.mjs +2 -2
- package/tools/ssh-askpass.mjs +35 -0
- package/tools/ssh.mjs +105 -0
- package/tools/web-deepseek.mjs +172 -0
- package/tools/web.mjs +29 -4
- package/vision-reader.mjs +4 -4
package/manifest-discovery.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* manifest-discovery.mjs — **发现 ∕ 归属族**出档(2026-09-29 structure-split-2 · 台账 #620):自 `manifest.mjs`
|
|
3
|
-
*
|
|
3
|
+
* 全量迁出——`MANIFEST_REL` · 测试注入位(`_setProjectRootForTest` / `_resetProjectRootForTest`)·
|
|
4
4
|
* `scanChildren`(两条梯表共用 walk 内核)· `discoverProjects`(项目梯)· `discoverRepos`(仓梯)·
|
|
5
5
|
* `owningProject`(归属形)· `resolveProjectRoot`(归属 ∨ 发现);**结构拆分零语义**(面不变 ∕ 判据不变,
|
|
6
6
|
* 只换宿主档;切点 ∕ 缝单源 = 批档 `docs/batches/2026-09-29-structure-split-2.md` §2.2-C)。
|
|
@@ -41,13 +41,14 @@ function scanChildren(anchor, isHit) {
|
|
|
41
41
|
/**
|
|
42
42
|
* **项目发现**(项目梯五级——KD-M1-23 / 设计 `docs/core/design/MANIFEST.md` §2.2;**git 非前提**,
|
|
43
43
|
* 2026-09-21 用户裁定):① 锚自身带 `MANIFEST_REL` ⇒ 锚;② 锚含 `.git` ⇒ 锚(缺档 = 建档机会);
|
|
44
|
-
* ③ 直接子目录中**带档**者优先(非空即只看此级:恰一 ⇒ `unique` / ≥2 ⇒ `
|
|
45
|
-
*
|
|
44
|
+
* ③ 直接子目录中**带档**者优先(非空即只看此级:恰一 ⇒ `unique` / ≥2 ⇒ `workspace`——下辖多项目
|
|
45
|
+
* = 工作区常态,非错误态);④ 零带档才看含 `.git` 的**裸仓**(同判);⑤ 均无 ⇒ `none`(⇒ 建档流,
|
|
46
|
+
* 落点 = 会话锚)。
|
|
46
47
|
* `candidates` 一律**按名排序**(`self` / `none` ⇒ `[]`);`matched` ∈ `manifest` / `git` / `null`
|
|
47
|
-
*
|
|
48
|
+
* 记命中(或工作区)出自哪一级。**纯 fs**(只判存在性——不解析档内容)· **不抛** · **不向上** · **不递归**。
|
|
48
49
|
* **覆盖位**(`_setProjectRootForTest` 在场)⇒ **头部短路**(测试注入面——先于真判据,同 `discoverRepos`)。
|
|
49
50
|
* @param {string} [cwd] 会话锚(缺省 → 进程 cwd)
|
|
50
|
-
* @returns {{kind:'self'|'unique'|'none'|'
|
|
51
|
+
* @returns {{kind:'self'|'unique'|'none'|'workspace', root:string|null, candidates:string[], matched:'manifest'|'git'|null}}
|
|
51
52
|
*/
|
|
52
53
|
export function discoverProjects(cwd) {
|
|
53
54
|
if (_projectRootOverride) return { kind: "self", root: resolve(_projectRootOverride), candidates: [], matched: null }
|
|
@@ -55,10 +56,10 @@ export function discoverProjects(cwd) {
|
|
|
55
56
|
if (existsSync(join(anchor, MANIFEST_REL))) return { kind: "self", root: anchor, candidates: [], matched: "manifest" }
|
|
56
57
|
if (existsSync(join(anchor, ".git"))) return { kind: "self", root: anchor, candidates: [], matched: "git" }
|
|
57
58
|
const withManifest = scanChildren(anchor, (d) => existsSync(join(d, MANIFEST_REL)))
|
|
58
|
-
if (withManifest.length > 1) return { kind: "
|
|
59
|
+
if (withManifest.length > 1) return { kind: "workspace", root: null, candidates: withManifest, matched: "manifest" }
|
|
59
60
|
if (withManifest.length === 1) return { kind: "unique", root: withManifest[0], candidates: [...withManifest], matched: "manifest" }
|
|
60
61
|
const bareRepos = scanChildren(anchor, (d) => existsSync(join(d, ".git")))
|
|
61
|
-
if (bareRepos.length > 1) return { kind: "
|
|
62
|
+
if (bareRepos.length > 1) return { kind: "workspace", root: null, candidates: bareRepos, matched: "git" }
|
|
62
63
|
if (bareRepos.length === 1) return { kind: "unique", root: bareRepos[0], candidates: [...bareRepos], matched: "git" }
|
|
63
64
|
return { kind: "none", root: null, candidates: [], matched: null }
|
|
64
65
|
}
|
|
@@ -66,21 +67,22 @@ export function discoverProjects(cwd) {
|
|
|
66
67
|
/**
|
|
67
68
|
* **仓发现**(仓梯——KD-M1-23 / `docs/core/design/TOOLS.md` §6.13;**单源** KD-M1-22——`git` 工具
|
|
68
69
|
* 经此符号接线,禁第二份实现):① 锚含 `.git` ⇒ 锚;② 直接子目录中 `.git` **∧** 带档者恰一 ⇒ 命中
|
|
69
|
-
* (≥2 ⇒
|
|
70
|
+
* (≥2 ⇒ `workspace`——下辖多仓 = 常态);③ **零个此类时才看**含 `.git` 的裸仓(恰一 ⇒ 命中 /
|
|
71
|
+
* ≥2 ⇒ `workspace`);④ 均无 ⇒ `none`。
|
|
70
72
|
* 与 `discoverProjects` = **同一 walk 内核**(`scanChildren`)的两种梯表——差异只在谓词与级序。
|
|
71
73
|
* `candidates` 按名排序;`matched` 记档位;纯 fs / 不抛 / 不递归 / 不向上;覆盖位 ⇒ 头部短路。
|
|
72
74
|
* @param {string} [cwd] 会话锚(缺省 → 进程 cwd)
|
|
73
|
-
* @returns {{kind:'self'|'unique'|'none'|'
|
|
75
|
+
* @returns {{kind:'self'|'unique'|'none'|'workspace', root:string|null, candidates:string[], matched:'manifest'|'git'|null}}
|
|
74
76
|
*/
|
|
75
77
|
export function discoverRepos(cwd) {
|
|
76
78
|
if (_projectRootOverride) return { kind: "self", root: resolve(_projectRootOverride), candidates: [], matched: null }
|
|
77
79
|
const anchor = resolve(cwd ?? ".")
|
|
78
80
|
if (existsSync(join(anchor, ".git"))) return { kind: "self", root: anchor, candidates: [], matched: "git" }
|
|
79
81
|
const scoped = scanChildren(anchor, (d) => existsSync(join(d, ".git")) && existsSync(join(d, MANIFEST_REL)))
|
|
80
|
-
if (scoped.length > 1) return { kind: "
|
|
82
|
+
if (scoped.length > 1) return { kind: "workspace", root: null, candidates: scoped, matched: "manifest" }
|
|
81
83
|
if (scoped.length === 1) return { kind: "unique", root: scoped[0], candidates: [...scoped], matched: "manifest" }
|
|
82
84
|
const bare = scanChildren(anchor, (d) => existsSync(join(d, ".git")))
|
|
83
|
-
if (bare.length > 1) return { kind: "
|
|
85
|
+
if (bare.length > 1) return { kind: "workspace", root: null, candidates: bare, matched: "git" }
|
|
84
86
|
if (bare.length === 1) return { kind: "unique", root: bare[0], candidates: [...bare], matched: "git" }
|
|
85
87
|
return { kind: "none", root: null, candidates: [], matched: null }
|
|
86
88
|
}
|
|
@@ -107,23 +109,24 @@ export function owningProject(target) {
|
|
|
107
109
|
}
|
|
108
110
|
}
|
|
109
111
|
|
|
110
|
-
/**
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
112
|
+
/** **项目根解析的直读形**(判定单点——设计 `MANIFEST.md` §2.2 `projectRootView` 契约行 / §2.5
|
|
113
|
+
* 「单项目解析律与四处会话级缺省收口」条):`ok`(唯一解析:归属命中 ∥ 发现 `self` / `unique`)/
|
|
114
|
+
* `workspace`(锚自身无档 ∧ 下辖 **≥2** 项目 ⇒ `root` null + 下辖项目全列**按名排序**——工作区
|
|
115
|
+
* 常态,非错误态)/ `none`(无项目 ⇒ 双空);覆盖位在场 ⇒ 头部短路(`ok` + 覆盖值)。
|
|
116
|
+
* **非抛错 / 零写**;`resolveProjectRoot` 薄委托本函数(行为逐字零变)。
|
|
117
|
+
* @returns {{state:'ok'|'workspace'|'none', root:string|null, candidates:string[]}} */
|
|
115
118
|
export function projectRootView(cwd) {
|
|
116
119
|
const owning = owningProject(cwd)
|
|
117
120
|
if (owning) return { state: "ok", root: owning, candidates: [] }
|
|
118
121
|
const d = discoverProjects(cwd)
|
|
119
122
|
if (d.root) return { state: "ok", root: d.root, candidates: [] }
|
|
120
|
-
if (d.kind === "
|
|
123
|
+
if (d.kind === "workspace") return { state: "workspace", root: null, candidates: d.candidates }
|
|
121
124
|
return { state: "none", root: null, candidates: [] }
|
|
122
125
|
}
|
|
123
126
|
|
|
124
127
|
/** 项目根解析(**归属 ∨ 发现**——KD-M1-30 / M1-24):**薄委托** `projectRootView(cwd).root`(判定
|
|
125
128
|
* 单点见上——#828)。带档路径与批前**逐字同**;变更面两条(设计 §2.2 同条):① 项目树内路径
|
|
126
|
-
* (祖先带档)⇒ 该项目根;② 裸仓恰一 ⇒ 该仓根(零档降级 = 建档机会)。`none` / `
|
|
129
|
+
* (祖先带档)⇒ 该项目根;② 裸仓恰一 ⇒ 该仓根(零档降级 = 建档机会)。`none` / `workspace` ⇒
|
|
127
130
|
* `null`。调用方零改(行为随语义变更——设计 §2.5 键面条 / 错层条)。
|
|
128
131
|
* @returns {string|null} 项目根绝对路径 / null */
|
|
129
132
|
export function resolveProjectRoot(cwd) {
|
package/manifest-schema.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* manifest-schema.mjs — **校验 ∕ 默认值族**出档(2026-09-29 structure-split-2 · 台账 #620):自 `manifest.mjs`
|
|
3
|
-
*
|
|
4
|
-
* `DEFAULT_MANIFEST`(默认八键)· `MANIFEST_SCHEMA`(判据单源)·
|
|
3
|
+
* 全量迁出——`isValidDocRootValue`(docRoot 子键值形态判据)·
|
|
4
|
+
* `DEFAULT_MANIFEST`(默认八键)· `MANIFEST_SCHEMA`(判据单源)· 元素层谓词一件 · `validateManifest` ·
|
|
5
5
|
* `fillDefaults`;**结构拆分零语义**(面不变 ∕ 判据不变,只换宿主档;切点 ∕ 缝单源 =
|
|
6
6
|
* 批档 `docs/batches/2026-09-29-structure-split-2.md` §2.2-C)。
|
|
7
7
|
*
|
|
@@ -25,6 +25,20 @@ export function isValidDocRootValue(value) {
|
|
|
25
25
|
return value.every((p) => typeof p === "string" && p.trim() !== "")
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
/** `checkConfig.anchors.roots` **单元素值形判据**(判据单源——解析根 = 相对项目根的目录):
|
|
29
|
+
* 合法 ⇒ `null`;非法 ⇒ 理由句(非空字符串 ∥ 相对路径 ∥ 无 `..` 越界段)。
|
|
30
|
+
* 消费面两处:产品引擎 `doc-check/anchors.mjs`(报告态逐元素弃用)∥ `doc-check/index.mjs`
|
|
31
|
+
* (gate 面 `configError` 拒,fail-closed)。
|
|
32
|
+
* @param {unknown} value 解析根元素
|
|
33
|
+
* @returns {string|null}
|
|
34
|
+
*/
|
|
35
|
+
export function anchorRootError(value) {
|
|
36
|
+
if (typeof value !== "string" || value.trim() === "") return "元素须为非空字符串"
|
|
37
|
+
if (/^(?:[A-Za-z]:[\\/]|[\\/])/.test(value)) return "元素须为相对项目根的路径(不得为绝对路径)"
|
|
38
|
+
if (value.split(/[\\/]/).includes("..")) return "元素不得含 `..` 越界段"
|
|
39
|
+
return null
|
|
40
|
+
}
|
|
41
|
+
|
|
28
42
|
/** 默认八键(架构 §2.3 E1 五键 + 三族声明键——KD-M1-31)——整档初始化的写源与缺键 fallback 的补源。 */
|
|
29
43
|
export const DEFAULT_MANIFEST = Object.freeze({
|
|
30
44
|
version: 1,
|
|
@@ -41,9 +55,8 @@ export const DEFAULT_MANIFEST = Object.freeze({
|
|
|
41
55
|
scanDirs: Object.freeze(["docs"]),
|
|
42
56
|
lineWidth: 300,
|
|
43
57
|
widthExemptZones: Object.freeze([]),
|
|
44
|
-
anchors: Object.freeze({ domain: "docs", exclude: Object.freeze(["_archive", "batches"]) }),
|
|
58
|
+
anchors: Object.freeze({ domain: "docs", exclude: Object.freeze(["_archive", "batches"]), roots: Object.freeze([]) }),
|
|
45
59
|
exemptions: Object.freeze([]),
|
|
46
|
-
lineCounts: Object.freeze([]), // 行数面机检声明(#546):[] = 未载惰性(doc-check 行数族)
|
|
47
60
|
}),
|
|
48
61
|
// 项目声明三族(2026-09-27 声明载体唯一化批并入——键名 / 形态逐字承前;来源档已退役)。
|
|
49
62
|
codePaths: Object.freeze(["src"]),
|
|
@@ -72,12 +85,6 @@ function isNonEmptyStringArray(v) {
|
|
|
72
85
|
return Array.isArray(v) && v.every((e) => typeof e === "string" && e.trim() !== "")
|
|
73
86
|
}
|
|
74
87
|
|
|
75
|
-
/** `checkConfig.lineCounts` 元素层判据(#546):数组且各元素为非数组对象、`doc` / `section` 皆非空串(`trim` 后非空);`[]` = 未载惰性。 */
|
|
76
|
-
function isLineCountsValue(v) {
|
|
77
|
-
return Array.isArray(v) && v.every((e) => e !== null && typeof e === "object" && !Array.isArray(e)
|
|
78
|
-
&& typeof e.doc === "string" && e.doc.trim() !== "" && typeof e.section === "string" && e.section.trim() !== "")
|
|
79
|
-
}
|
|
80
|
-
|
|
81
88
|
/**
|
|
82
89
|
* 形状校验(模块设计 §2.2)——枚举 / version 数值恒做;**纯函数、零 fs**(原 `{ cwd }`
|
|
83
90
|
* 指针分支已随字段整链裁撤——KD-M1-5 墓志);不落盘。键存在性入 missingKeys(非拒):
|
|
@@ -116,10 +123,6 @@ export function validateManifest(obj) {
|
|
|
116
123
|
if (nested === "docRoot" && !isValidDocRootValue(value[sub])) {
|
|
117
124
|
errors.push(`docRoot.${sub} 值形态非法:${JSON.stringify(value[sub])}(须为非空字符串 / 非空字符串数组 / null(本面无)——KD-M1-6 / KD-M1-7 / KD-M1-37)`)
|
|
118
125
|
}
|
|
119
|
-
// checkConfig.lineCounts 元素层形态(#546):数组,元素 = { doc, section } 非空串;非法 → 拒(不静默跳过)。
|
|
120
|
-
if (nested === "checkConfig" && sub === "lineCounts" && !isLineCountsValue(value[sub])) {
|
|
121
|
-
errors.push(`checkConfig.lineCounts 值形态非法:${JSON.stringify(value[sub])}(须为数组,元素 = { doc: 非空串, section: 非空串 }——#546)`)
|
|
122
|
-
}
|
|
123
126
|
}
|
|
124
127
|
}
|
|
125
128
|
// 三族声明键形态(KD-M1-32——fail-closed:非法即 errors,不静默跳过;缺键仍在 missingKeys)。
|
package/manifest.mjs
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* 未知键(#802 / KD-M1-36)→ 产 unknownKeys + 一行可见告警(console.warn + logEvent;
|
|
11
11
|
* 同档同键集去重、读到零未知键清该档 memo)——非拒定性零变。
|
|
12
12
|
* - validateManifest(obj) → { ok, errors, missingKeys, unknownKeys }:枚举 / version 数值 /
|
|
13
|
-
* docRoot 子键值形态(串 | 数组 | null(本面无——KD-M1-37),F7
|
|
13
|
+
* docRoot 子键值形态(串 | 数组 | null(本面无——KD-M1-37),F7)——**纯函数、零 fs**;不落盘。
|
|
14
14
|
* - 三族声明键(`codePaths` / `index.{codeExtensions,docExtensions,publicRepos}` / `advisor.{docMap,standardsDoc}`——
|
|
15
15
|
* KD-M1-31 / M1-32):缺键补默认;形态错 = 档非法(fail-closed,与 docRoot 子键同款);
|
|
16
16
|
* 读向 = `declaration.mjs`(2026-10-01 自 `conventions.mjs` 迁出——经其转口可达)经 `readManifest` /
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
* - projectView(target) → { state, root, path, manifest?, candidates?, errors?, matched }:**按用点解析**
|
|
26
26
|
* 的读侧单点(归属 ∨ 发现兜底 / 五态 / 非抛错 / **零写**——KD-M1-24)。
|
|
27
27
|
* - resolveProjectRoot(cwd):项目根(归属 ∨ 发现——KD-M1-30)= `projectRootView(cwd).root`(薄委托);
|
|
28
|
-
* projectRootView(cwd) → { state: ok|
|
|
28
|
+
* projectRootView(cwd) → { state: ok|workspace|none, root, candidates }:项目根直读形(判定单点——§2.2)。
|
|
29
29
|
* - resolveEngineeringManifest(cwd, { writer, init }) → 入口决策树(**非抛错**——KD-M1-20):
|
|
30
30
|
* 两端入口钩子与翻转面(拒翻)共用同一张树(判据单源;§2.8 F1)——失败码五枚
|
|
31
|
-
* `missing` / `invalid` / `no-project` / `
|
|
31
|
+
* `missing` / `invalid` / `no-project` / `workspace` / `init-failed`(KD-M1-28)。名中 `Engineering` = 历史命名(沿用不改名);消费面 = 两端入口钩子 + 翻转面——**非**「模式拥有本模块」。
|
|
32
32
|
* - manifestFilePath(cwd) → 数据档绝对路径(档路径单源 KD-M1-18——读 / 写 / mtime 门控三处同源)。
|
|
33
33
|
* - initManifest(cwd, { writer = 'subagent' } = {}) → 经写门写 DEFAULT_MANIFEST,缺省拒。
|
|
34
34
|
* - writeManifest(cwd, manifest, { writer = 'subagent' } = {}) → 落盘前先校验(ok:false 拒
|
|
@@ -53,14 +53,14 @@ export { DEFAULT_MANIFEST, MANIFEST_SCHEMA, isValidDocRootValue, validateManifes
|
|
|
53
53
|
* · **归属(第一段——§⑥ 归属形)**:`owningProject(target)` 沿祖先链取最近带档目录
|
|
54
54
|
* (子优于根 / 不跨兄弟 / 无全局优先级)⇒ 读该档 ⇒ `ok` / `invalid`。
|
|
55
55
|
* · **发现兜底(第二段——§⑥ 发现规则,纯向下)**:祖先链无档 ⇒ `discoverProjects(target)` ⇒ 命中
|
|
56
|
-
* (`self` / `unique`)⇒ 读其档(带档 ⇒ `ok` / `invalid`;缺档 ⇒ `missing`);`
|
|
57
|
-
* `
|
|
56
|
+
* (`self` / `unique`)⇒ 读其档(带档 ⇒ `ok` / `invalid`;缺档 ⇒ `missing`);`workspace` ⇒
|
|
57
|
+
* `workspace`(+ `candidates`);`none` ⇒ `no-project`。
|
|
58
58
|
* 写侧(建档)**不在**此函数(归入口决策树——KD-M1-25 / M1-29)⇒ 注入器 / 只读消费面不会变写点。
|
|
59
59
|
* `matched` 契约:归属段命中 ⇒ `'manifest'`;发现段 ⇒ `discoverProjects.matched` 逐字;
|
|
60
|
-
* `no-project`(/ 覆盖位短路)⇒ `null
|
|
60
|
+
* `no-project`(/ 覆盖位短路)⇒ `null`——报明行工作区变体按它分野(§2.6 条 1b)。
|
|
61
61
|
* 读错(非 ENOENT——权限 / 目录等)收为 `invalid`(非抛错契约;`readManifest` 语义零改)。
|
|
62
62
|
* @param {string} [target] 目标路径(目录 / 文件——动作作用于哪个项目的路径)
|
|
63
|
-
* @returns {{state:'ok'|'missing'|'no-project'|'
|
|
63
|
+
* @returns {{state:'ok'|'missing'|'no-project'|'workspace'|'invalid', root:string|null, path:string|null,
|
|
64
64
|
* manifest?:object, candidates?:string[], errors?:string[], matched:'manifest'|'git'|null}}
|
|
65
65
|
*/
|
|
66
66
|
export function projectView(target) {
|
|
@@ -68,7 +68,7 @@ export function projectView(target) {
|
|
|
68
68
|
const owning = owningProject(anchor)
|
|
69
69
|
if (owning) return viewAtRoot(owning, "manifest")
|
|
70
70
|
const d = discoverProjects(anchor)
|
|
71
|
-
if (d.kind === "
|
|
71
|
+
if (d.kind === "workspace") return { state: "workspace", root: null, path: null, candidates: d.candidates, matched: d.matched }
|
|
72
72
|
if (d.kind === "none") return { state: "no-project", root: null, path: null, matched: null }
|
|
73
73
|
return viewAtRoot(d.root, d.matched)
|
|
74
74
|
}
|
|
@@ -187,6 +187,16 @@ export function requireManifest(cwd) {
|
|
|
187
187
|
return readManifest(cwd)
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
+
/** 建档(init 支)成功后的同步通知位(#1376——**反向注册**:`declaration.mjs` 已向依赖本模块,
|
|
191
|
+
* 订阅方由对侧注册 ⇒ 本模块保持零出边(MANIFEST.md KD-M1-33);形同 `config-io.mjs` `onConfigSelfWrite`
|
|
192
|
+
* ——返回退订函数;订阅方失败不影响建档)。 */
|
|
193
|
+
const manifestInitFns = new Set()
|
|
194
|
+
export function onManifestInit(fn) {
|
|
195
|
+
if (typeof fn !== "function") return () => {}
|
|
196
|
+
manifestInitFns.add(fn)
|
|
197
|
+
return () => { manifestInitFns.delete(fn) }
|
|
198
|
+
}
|
|
199
|
+
|
|
190
200
|
/**
|
|
191
201
|
* 入口决策树(**非抛错**形态——KD-M1-20;docs/core/design/MANIFEST.md §2.8 F1):三面共用——
|
|
192
202
|
* ① CLI 装配 / 重估薄包装 ② VSC `hydrateRun` 钩子块 ③ 翻转面(`eng` 工具 / `/eng` /
|
|
@@ -196,22 +206,22 @@ export function requireManifest(cwd) {
|
|
|
196
206
|
* 分支(两分支六出口——§2.8 F1 树):
|
|
197
207
|
* 档合法 → { ok:true, manifest, created:false }(manifest = 补默认值后的档内容)
|
|
198
208
|
* 缺档 + init → 梯②④⑤(锚 = 裸仓 / 裸仓命中 / 无项目)⇒ `initManifest(cwd, { writer })`
|
|
199
|
-
* (抛错 → `init-failed
|
|
200
|
-
* message, candidates }`(**不建 / 不猜**)
|
|
209
|
+
* (抛错 → `init-failed`);工作区(锚自身无档 ∧ 下辖 ≥2 项目)⇒
|
|
210
|
+
* `{ ok:false, code:'workspace', message, candidates }`(**不建 / 不猜**)
|
|
201
211
|
* 缺档 + !init → 梯⑤(无项目)⇒ `{ ok:false, code:'no-project' }`(KD-M1-28;`init:false` 面);
|
|
202
|
-
* 梯②④(裸仓可解析、档缺)⇒ `{ ok:false, code:'missing' }
|
|
212
|
+
* 梯②④(裸仓可解析、档缺)⇒ `{ ok:false, code:'missing' }`;工作区 ⇒ 同上
|
|
203
213
|
* 档非法 → { ok:false, code:'invalid', message, errors }
|
|
204
214
|
*
|
|
205
215
|
* `writer` 由调用点**显式**传(生产调用点全传 `'main'`):缺省 `'subagent'` 是写门 fail-closed
|
|
206
216
|
* 缺省(KD-M1-3),误用缺省 ⇒「缺档 + 梯②④⑤」退化为 `init-failed`(拒翻——与 §2.8 F2 /
|
|
207
217
|
* AC-20② 语义相反;T38 反证格)。
|
|
208
|
-
*
|
|
209
|
-
* 「项目不可解析」(稳定锚句
|
|
218
|
+
* 失败码文案分野(KD-M1-28):无项目 ⇒ 可在锚处落地 / 工作区 ⇒ 报明事实 + 点名项目根;文案族 =
|
|
219
|
+
* 「项目不可解析」(稳定锚句 `/项目不可解析/`)——**仅「档非法」格**(§2.8 F2 拒翻面唯一拒格)。
|
|
210
220
|
* 边界:`readManifest` 的非 ENOENT 读错(权限 / 目录等)由 `projectView` 收为 `invalid`(非抛错
|
|
211
221
|
* 契约——`readManifest` 返回语义零改);本树只承诺上列六出口。
|
|
212
222
|
* @param {string} [cwd] 会话锚(缺省 → 进程 cwd)
|
|
213
223
|
* @returns {{ok:true, manifest:object, created:boolean}
|
|
214
|
-
* | {ok:false, code:'missing'|'invalid'|'no-project'|'
|
|
224
|
+
* | {ok:false, code:'missing'|'invalid'|'no-project'|'workspace'|'init-failed',
|
|
215
225
|
* message?:string, errors?:string[], candidates?:string[]}}
|
|
216
226
|
*/
|
|
217
227
|
export function resolveEngineeringManifest(cwd, { writer = "subagent", init = true } = {}) {
|
|
@@ -223,24 +233,29 @@ export function resolveEngineeringManifest(cwd, { writer = "subagent", init = tr
|
|
|
223
233
|
message: `项目不可解析:${MANIFEST_REL} 非法(fail-closed):${(view.errors ?? []).join(";")}`,
|
|
224
234
|
}
|
|
225
235
|
}
|
|
226
|
-
if (view.state === "
|
|
227
|
-
return { ok: false, code: "
|
|
236
|
+
if (view.state === "workspace") {
|
|
237
|
+
return { ok: false, code: "workspace", candidates: view.candidates, message: workspaceProjectMessage(cwd, view.candidates) }
|
|
228
238
|
}
|
|
229
239
|
// 缺档(梯②④⑤):init ⇒ 就地建档(内容 = DEFAULT_MANIFEST,经写门 writer:'main');!init ⇒ 归码。
|
|
230
240
|
if (!init) return { ok: false, code: view.state === "no-project" ? "no-project" : "missing" }
|
|
231
241
|
try {
|
|
232
|
-
|
|
242
|
+
const manifest = initManifest(cwd, { writer })
|
|
243
|
+
// #1376:建档支成功 ⇒ 同步广播(进程内声明 ∥ 范围缓存即刻随动——如 eng 翻转面结束后
|
|
244
|
+
// 同进程的声明复读;订阅方失败不阻断建档;失败路径不广播)。
|
|
245
|
+
for (const fn of manifestInitFns) { try { fn() } catch (e) { console.warn(`[manifest] init subscriber failed: ${e?.message ?? e}`) } }
|
|
246
|
+
return { ok: true, manifest, created: true }
|
|
233
247
|
} catch (e) {
|
|
234
248
|
return { ok: false, code: "init-failed", message: e?.message ?? String(e) }
|
|
235
249
|
}
|
|
236
250
|
}
|
|
237
251
|
|
|
238
|
-
/**
|
|
239
|
-
*
|
|
240
|
-
|
|
252
|
+
/** 工作区消息(**事实行**——§2.5「单项目解析律」条 / §2.8 F2 工作区行):念明下辖项目**全列**
|
|
253
|
+
* (绝对路径、按名排序)+ 可执行下一步(点名项目根 / 目标路径)——报明事实,非错误框定
|
|
254
|
+
* (不书「项目不可解析」/ 候选二义)。 */
|
|
255
|
+
function workspaceProjectMessage(cwd, candidates) {
|
|
241
256
|
const list = (candidates ?? []).map((c) => `- ${c}`).join("\n")
|
|
242
|
-
return
|
|
243
|
-
`每个项目一份 ${MANIFEST_REL}
|
|
257
|
+
return `工作区:会话锚 ${cwd} 自身无 ${MANIFEST_REL},下辖 ${(candidates ?? []).length} 个项目(下列全部)——` +
|
|
258
|
+
`每个项目一份 ${MANIFEST_REL};请显式给出目标项目根或目标路径(动作按用点路径解析):\n${list}`
|
|
244
259
|
}
|
|
245
260
|
|
|
246
261
|
/**
|
package/mcp/transport-stdio.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { spawn, spawnSync } from "node:child_process"
|
|
|
5
5
|
import { rpcId, CALL_TIMEOUT_MS, withTimeout, quoteArg } from "./helpers.mjs"
|
|
6
6
|
|
|
7
7
|
/** 退出相位标志(D-MC19):模块加载期注册的 exit 钩子置位——退出相位无事件循环,
|
|
8
|
-
* 只同步操作可落地(注册序恒早于宿主 cleanup——`thincoder-cli/src/tui/index.mjs
|
|
8
|
+
* 只同步操作可落地(注册序恒早于宿主 cleanup——`thincoder-cli/src/tui/index.mjs` 的 `createExitCleanup`)。 */
|
|
9
9
|
let exiting = false
|
|
10
10
|
process.on("exit", () => { exiting = true })
|
|
11
11
|
|
package/mcp.mjs
CHANGED
|
@@ -93,14 +93,14 @@ async function createConnectedTransport(rawConfig, serverName) {
|
|
|
93
93
|
* 零副作用:不进 _sessions、不动 agent.tools、无 onDead 挂钩;finally close
|
|
94
94
|
* (closed=true 使 onDead 重连不会触发)。initialize 与 tools/list 同受
|
|
95
95
|
* INIT_TIMEOUT_MS 约束(见 doInitialize)。不复用 connectMcpServer(避免污染
|
|
96
|
-
* session
|
|
96
|
+
* session 幂等表)。读数 = `{ ok, toolCount, tools, latencyMs }`(`tools` = 工具名数组——控制台具名读数,2026-10-14 走查轮增补)。 */
|
|
97
97
|
export async function probeMcpServer(config) {
|
|
98
98
|
const start = Date.now()
|
|
99
99
|
let transport
|
|
100
100
|
let mcpTools
|
|
101
101
|
try {
|
|
102
102
|
;({ transport, mcpTools } = await createConnectedTransport(config, config.name ?? config.command ?? config.url ?? config.wsUrl))
|
|
103
|
-
|
|
103
|
+
return { ok: true, toolCount: mcpTools.length, tools: mcpTools.map((t) => (typeof t?.name === "string" ? t.name : "")).filter((n) => n !== ""), latencyMs: Date.now() - start }
|
|
104
104
|
} catch (error) {
|
|
105
105
|
return { ok: false, error: error?.message ?? String(error) }
|
|
106
106
|
} finally {
|
package/memory/core.mjs
CHANGED
|
@@ -132,7 +132,7 @@ export function fetchEntry(memory, uid) {
|
|
|
132
132
|
const lastColon = uid.lastIndexOf(":")
|
|
133
133
|
const origin = lastColon > layer.length ? uid.slice(layer.length + 1, lastColon) : ""
|
|
134
134
|
const path = lastColon > layer.length ? uid.slice(lastColon + 1) : uid.slice(layer.length + 1)
|
|
135
|
-
const projectOrigin = normalizeOrigin(memory.projectOrigin) // §6.11 读缝归一(uid
|
|
135
|
+
const projectOrigin = normalizeOrigin(memory.projectOrigin) // §6.11 读缝归一(uid 解析面零改——`fetchEntry` 余量兜底仍在)
|
|
136
136
|
if (layer === "project" && projectOrigin) {
|
|
137
137
|
const r = memory.db.prepare(`SELECT type, title, content, tags, author FROM files WHERE layer = ? AND origin = ? AND path = ?`).get(layer, origin || projectOrigin, path)
|
|
138
138
|
if (r) return { ...r, layer, id: uid }
|
package/memory/scan.mjs
CHANGED
|
@@ -90,7 +90,7 @@ export function createTopK(k) {
|
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
/** 末行键值元组:任一键列缺失(`undefined` / `null`)⇒ `null`(防呆①:等价现
|
|
93
|
+
/** 末行键值元组:任一键列缺失(`undefined` / `null`)⇒ `null`(防呆①:等价现 `createTopK` 的 `list()`)。 */
|
|
94
94
|
function cursorValues(keys, row) {
|
|
95
95
|
if (!row) return null
|
|
96
96
|
const out = []
|
package/memory/sweep.mjs
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* 折叠映射 + 备份路径 + 写后回读判据)。
|
|
16
16
|
* **折叠规则单源 = §6.11 步 2**(同归一键内 `(path, line_start)`(`files` = `(layer, path)`)恰一行——
|
|
17
17
|
* 保留 `mtime_ms` 最大者,并列取 `rowid` 最小者;FTS 由既有触发器随行同步)。
|
|
18
|
-
* 探针 fail-safe:**仅 ENOENT 判亡**,其余错误(权限 / 非法路径)⇒ 保留(先例 `session-stale.mjs
|
|
18
|
+
* 探针 fail-safe:**仅 ENOENT 判亡**,其余错误(权限 / 非法路径)⇒ 保留(先例 = `session-stale.mjs` 的 `pathExists`)。
|
|
19
19
|
* 执行分工:真实库写 = 父侧 ops;本档只在传入的库句柄上作业,写闸 = `confirm` 单一入参。
|
|
20
20
|
*/
|
|
21
21
|
import { existsSync, statSync } from "node:fs"
|
package/model-specs.mjs
CHANGED
|
@@ -33,8 +33,8 @@ const MODEL_SPECS = [
|
|
|
33
33
|
["deepseek-flash", { context: 1_000_000, maxOutput: 384_000, thinking: true, prefixMode: true, thinkApi: "type", reasoningEcho: "required", reasoningEffortEnum: ["low", "high", "max"], tempRange: [0, 2], multimodal: true }],
|
|
34
34
|
// deepseek-v4.1-flash = qwen-plan channel name for DeepSeek V4.1-Flash (token-plan GET /models verified 2026-09-15) — same fields as the row above; ".1" ≠ "-" so plain prefix lookup misses the existing rows (D-PR25)
|
|
35
35
|
["deepseek-v4.1-flash", { context: 1_000_000, maxOutput: 384_000, thinking: true, prefixMode: true, thinkApi: "type", reasoningEcho: "required", reasoningEffortEnum: ["low", "high", "max"], tempRange: [0, 2], multimodal: true }],
|
|
36
|
-
// deepseek-v4-pro (V4-Pro-0813): fields unchanged — 视觉面 **未探**(不声明 multimodal
|
|
37
|
-
//
|
|
36
|
+
// deepseek-v4-pro (V4-Pro-0813): fields unchanged — 视觉面 **未探**(不声明 multimodal——保守).
|
|
37
|
+
// From 2026-09-14 12:00 Beijing all requests route to V4.1-Flash.
|
|
38
38
|
["deepseek-v4-pro", { context: 1_000_000, maxOutput: 384_000, thinking: true, prefixMode: true, thinkApi: "type", reasoningEcho: "required", reasoningEffortEnum: ["low", "high", "max"], tempRange: [0, 2] }],
|
|
39
39
|
// deepseek-v4-flash: RETIRED name — still accepted, served by V4.1-Flash today → aligned row
|
|
40
40
|
["deepseek-v4-flash", { context: 1_000_000, maxOutput: 384_000, thinking: true, prefixMode: true, thinkApi: "type", reasoningEcho: "required", reasoningEffortEnum: ["low", "high", "max"], tempRange: [0, 2], multimodal: true }],
|
|
@@ -63,7 +63,7 @@ const MODEL_SPECS = [
|
|
|
63
63
|
// GLM series
|
|
64
64
|
// GLM-5.3: thinking always-on (no "disabled"); effort converges to low/high/max — NOT the
|
|
65
65
|
// 7-level glm-5.2 enum (verified vs docs.bigmodel.cn GLM-5.3 page, 2026-08).
|
|
66
|
-
// 视觉面 **未探**(不声明 multimodal
|
|
66
|
+
// 视觉面 **未探**(不声明 multimodal——保守)。
|
|
67
67
|
// 该事实 = 机制位 `thinkAlwaysOn`(单源 = `docs/core/design/MODEL-SPECS.md` §16.3)——**官方口径**
|
|
68
68
|
// (智谱 GLM-5.3 文档:thinking always-on、无 `disabled`)。
|
|
69
69
|
["glm-5.3", { context: 1_000_000, maxOutput: 128_000, thinking: true, thinkAlwaysOn: true, thinkApi: "type", reasoningEcho: "optional", reasoningEffortEnum: ["low", "high", "max"], tempRange: [0, 1], noUsageStream: true }],
|
|
@@ -199,9 +199,9 @@ const MODEL_SPECS = [
|
|
|
199
199
|
// (多源网络转述级,本机无该渠道——行值 + 行注即标级);thinking「always-on adaptive」= 弱源读数 ⇒ 零口径不落字段(§14.3)。
|
|
200
200
|
["claude-fable-5.1", { context: 1_000_000, maxOutput: 128_000 }],
|
|
201
201
|
// Gemini series (Google)
|
|
202
|
-
["gemini-3-pro", { context: 1_000_000, maxOutput: 64_000, thinking:
|
|
203
|
-
["gemini-2.5-pro", { context: 2_000_000, maxOutput: 64_000, thinking:
|
|
204
|
-
["gemini-2.5-flash", { context: 1_000_000, maxOutput: 64_000, thinking:
|
|
202
|
+
["gemini-3-pro", { context: 1_000_000, maxOutput: 64_000, thinking: true, multimodal: true, format: "google", noUsageStream: true }],
|
|
203
|
+
["gemini-2.5-pro", { context: 2_000_000, maxOutput: 64_000, thinking: true, multimodal: true, format: "google", noUsageStream: true }],
|
|
204
|
+
["gemini-2.5-flash", { context: 1_000_000, maxOutput: 64_000, thinking: true, multimodal: true, format: "google", noUsageStream: true }],
|
|
205
205
|
// gemini-3.1-pro(2026-09-25 批 §14.2 #2-6 · §1.7.1 父侧交付):**尺寸行**——context 1_048_576 / maxOutput 65_536(多源
|
|
206
206
|
// 网络转述级,本机无该渠道——行值 + 行注即标级);thinking「有·计入输出预算」= 弱源读数 ⇒ 零口径不落字段(§14.3)。
|
|
207
207
|
["gemini-3.1-pro", { context: 1_048_576, maxOutput: 65_536 }],
|
|
@@ -350,7 +350,7 @@ export function providerSpec(provider) {
|
|
|
350
350
|
*
|
|
351
351
|
* Callers (as-of 2026-10-10): thincoder-core/agent/turn-loop.mjs (main loop) · thincoder-core/advisor/loop.mjs
|
|
352
352
|
* (review mirror) · bench/lib/client.mjs (bench client) — each passes its own spec face; VSC 转口
|
|
353
|
-
* (thincoder-vscode/src/specs.mjs
|
|
353
|
+
* (`thincoder-vscode/src/specs.mjs` 的 `providerSpec` ∕ `assistantToolCallMessage` 再导出) 零调用点(父侧收口机械笔 · 可 revert)。
|
|
354
354
|
*/
|
|
355
355
|
export function assistantToolCallMessage(response, spec) {
|
|
356
356
|
const msg = {
|
package/notify-policy.mjs
CHANGED
|
@@ -2,24 +2,24 @@
|
|
|
2
2
|
* notify-policy.mjs — 完成提示面**策略**(失焦门 + 单档 + 载荷成形 + 词键)——「桌面处理流 · VSC 对齐」批 R6 上提产物。
|
|
3
3
|
*
|
|
4
4
|
* 上提源 = 桌面现状超集 `thincoder-desktop/src/main/notify.mjs`(零宿主依赖 —— **纯搬,零语义改**);
|
|
5
|
-
* 对位锚(迁移前坐标)= VSC `thincoder-vscode/src/extension/notify.mjs
|
|
6
|
-
* `panel-callbacks.mjs
|
|
5
|
+
* 对位锚(迁移前坐标)= VSC `thincoder-vscode/src/extension/notify.mjs` 的 `createVscNotify`(失焦门同判据)+
|
|
6
|
+
* `panel-callbacks.mjs` 的 `buildPanelCallbacks`(`!autoTurn` 门径)。平台落子(Electron `Notification` vs
|
|
7
7
|
* VSC `showInformationMessage`)= 宿主能力面(真端差登记 ①)⇒ **装配留端**(桌面 =
|
|
8
8
|
* `thincoder-desktop/src/main/main.mjs`;VSC = `notify.mjs` 宿主包装——已随 parity-b4 迁移落形);本档只承策略面。
|
|
9
9
|
*
|
|
10
10
|
* `notify`(平台落子)· `focused`(焦态判据)· `reveal`(点击面)· `localeOf`(语言取值缝——VSC
|
|
11
11
|
* wrapper 携 `vscode.env.language`,`normalizeLocale` 归一 `zh-CN → zh`;缺省 = `agent.config?.locale`,
|
|
12
12
|
* 桌面径零改)四件注入 ⇒ 平 node 直测。词键一键自此持本档(值 = 原 VSC 逐字 `notify.done`——该键已随
|
|
13
|
-
* parity-b4 迁移自 `thincoder-vscode/locales/{zh,en}.json
|
|
13
|
+
* parity-b4 迁移自 `thincoder-vscode/locales/{zh,en}.json` 的 `notify.done` 键删)。触发单档(`!autoTurn` 判据在调用面 —— 单回合
|
|
14
14
|
* 执行面;VSC 同判据):
|
|
15
|
-
* 用户回合完成(VSC 逐字同判据 = `panel-callbacks.mjs
|
|
15
|
+
* 用户回合完成(VSC 逐字同判据 = `panel-callbacks.mjs` 的 `buildPanelCallbacks` 的 `!autoTurn` 门)
|
|
16
16
|
* `title` = 会话标题(`agent.title`——槽装载面在场;空 ∕ 不可得 ⇒ **零携**);点击 = 聚焦窗口 ∕
|
|
17
17
|
* 打开 thincoder 视图(reveal 语义 —— 宿主面;不切会话)。
|
|
18
18
|
* 消费面 = 桌面 `thincoder-desktop/src/main/notify.mjs`(端胶水 re-export);VSC `notify.mjs`(宿主包装——已随 parity-b4 迁移落形)。
|
|
19
19
|
*/
|
|
20
20
|
import { normalizeLocale } from "./i18n.mjs"
|
|
21
21
|
|
|
22
|
-
/** 词键值(zh ∕ en 常量对:`notify.done` = 原 VSC `locales/{zh,en}.json
|
|
22
|
+
/** 词键值(zh ∕ en 常量对:`notify.done` = 原 VSC `locales/{zh,en}.json` 键逐字——该键已随 parity-b4 迁移自 locales 删)。 */
|
|
23
23
|
export const NOTIFY_TEXTS = Object.freeze({
|
|
24
24
|
zh: "ThinCoder:本轮完成",
|
|
25
25
|
en: "ThinCoder: turn complete",
|
|
@@ -36,7 +36,7 @@ export function createNotifier({ notify = null, focused = null, reveal = null, l
|
|
|
36
36
|
const isFocused = typeof focused === "function" ? focused : () => true
|
|
37
37
|
const langOf = (agent) => (normalizeLocale(typeof localeOf === "function" ? localeOf(agent) : agent?.config?.locale) === "zh" ? "zh" : "en")
|
|
38
38
|
const fire = ({ agent = null } = {}) => {
|
|
39
|
-
if (isFocused()) return false // 失焦门:聚焦 = no-op(never noise —— VSC `thincoder-vscode/src/extension/notify.mjs
|
|
39
|
+
if (isFocused()) return false // 失焦门:聚焦 = no-op(never noise —— VSC `thincoder-vscode/src/extension/notify.mjs` 的 `createVscNotify` 同判据)
|
|
40
40
|
const payload = { body: NOTIFY_TEXTS[langOf(agent)] }
|
|
41
41
|
const title = typeof agent?.title === "string" && agent.title.trim() !== "" ? agent.title : null
|
|
42
42
|
if (title !== null) payload.title = title // 会话标题在场才携(不可得 ⇒ 零携)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thincoder/core",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.9",
|
|
4
4
|
"description": "ThinCoder shared core — shared mechanism modules + shared prompt content (CLI ↔ VS Code extension).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"agent/",
|
|
42
42
|
"agent-tools/",
|
|
43
43
|
"browser/",
|
|
44
|
+
"doc-check/",
|
|
44
45
|
"git/",
|
|
45
46
|
"mcp/",
|
|
46
47
|
"memory/",
|
package/permission.mjs
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import { createInterface } from "node:readline"
|
|
16
16
|
import { lastPageUrl } from "./browser/session.mjs"
|
|
17
|
+
import { composeTaskBookBrief } from "./agent-tools/spawn-gates.mjs"
|
|
17
18
|
|
|
18
19
|
/** CLI tool arg summary (truncated long JSON) */
|
|
19
20
|
export function summarize(toolArgs) {
|
|
@@ -34,7 +35,7 @@ export function formatPermission(name, args) {
|
|
|
34
35
|
return `${args.path}\n${oldLines}\n ↓\n${newLines}`
|
|
35
36
|
}
|
|
36
37
|
if (base === "delete") return `${args.path}${args.force ? "(force:跟踪文件也删)" : ""}`
|
|
37
|
-
if (base === "subagent") return cap(args.task
|
|
38
|
+
if (base === "subagent") return cap(composeTaskBookBrief(args, args.role) || args.task || "", 500)
|
|
38
39
|
if (base === "memory") {
|
|
39
40
|
// §6 action-routed preview: put shows content, batch delete/clear show the gate args
|
|
40
41
|
const action = String(args.action ?? "")
|
|
@@ -75,6 +76,25 @@ export function formatPermission(name, args) {
|
|
|
75
76
|
const at = lastPageUrl() ? ` @ ${lastPageUrl()}` : ""
|
|
76
77
|
return cap(`${action}${shown ? ` ${shown}` : ""}${at}`, 300)
|
|
77
78
|
}
|
|
79
|
+
if (base === "ssh") {
|
|
80
|
+
// TOOLS.md §6.22 NS3:写动作展示「将发送的原文」(人可见判据——显示面提示,非拦截);
|
|
81
|
+
// 携密径(`secret_input`)改**掩码占位**——值入文案即入上下文 ∥ 审批记录 ⇒ 违 NS4(值不回显)。
|
|
82
|
+
const action = String(args.action ?? "")
|
|
83
|
+
const sid = args.id ? `ssh#${String(args.id).replace(/^ssh#/i, "")}` : "ssh"
|
|
84
|
+
if (action === "connect") {
|
|
85
|
+
const target = args.host ? `${args.user ? `${args.user}@` : ""}${args.host}${args.port ? `:${args.port}` : ""}` : "(missing host)"
|
|
86
|
+
return cap(`${target}${args.label ? `(${args.label})` : ""}`, 300)
|
|
87
|
+
}
|
|
88
|
+
if (action === "send") return `${sid} — 将发送:\n${cap(String(args.data ?? ""), 500)}`
|
|
89
|
+
if (action === "secret_input") return `${sid} — 将发送:••••••(携密——值不回显)${args.label ? `(${args.label})` : ""}`
|
|
90
|
+
if (action === "forget") {
|
|
91
|
+
// ⑫ 删除面:明示目标主机(无值——保存件不含可展示的凭据值)
|
|
92
|
+
const target = args.host ? `${args.host}${args.port ? `:${args.port}` : ""}` : "(missing host)"
|
|
93
|
+
return cap(`${target} — 删除已保存的 ssh 凭据`, 300)
|
|
94
|
+
}
|
|
95
|
+
if (action === "close") return `${sid} — 关闭会话`
|
|
96
|
+
return cap(`${action} ${sid}`, 300)
|
|
97
|
+
}
|
|
78
98
|
return cap(summarize(args), 300)
|
|
79
99
|
}
|
|
80
100
|
|