dominds 1.2.5 → 1.2.7
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/dist/agent-priming.js +2051 -0
- package/dist/apps/app-lock-file.js +228 -0
- package/dist/apps/assigned-port.js +124 -0
- package/dist/apps/enabled-apps.js +472 -7
- package/dist/apps/manifest.js +37 -0
- package/dist/apps/override-paths.js +19 -6
- package/dist/apps/problems.js +43 -0
- package/dist/apps/resolution-file.js +370 -0
- package/dist/apps/runtime.js +5 -17
- package/dist/apps/teammates.js +102 -1
- package/dist/cli/disable.js +10 -6
- package/dist/cli/enable.js +21 -19
- package/dist/cli/install.js +40 -18
- package/dist/cli/uninstall.js +6 -6
- package/dist/cli/update.js +38 -13
- package/dist/dialog.js +5 -0
- package/dist/docs/app-constitution.md +85 -18
- package/dist/docs/app-constitution.zh.md +86 -21
- package/dist/docs/dialog-system.md +1 -1
- package/dist/docs/dialog-system.zh.md +1 -1
- package/dist/docs/dominds-agent-priming.md +218 -0
- package/dist/docs/dominds-agent-priming.zh.md +196 -0
- package/dist/docs/drive-logic-context-refactor-plan.zh.md +338 -0
- package/dist/docs/keep-going.md +176 -0
- package/dist/docs/keep-going.zh.md +162 -0
- package/dist/docs/showing-by-doing.md +208 -0
- package/dist/docs/showing-by-doing.zh.md +177 -0
- package/dist/docs/team-mgmt-toolset.md +482 -0
- package/dist/docs/team-mgmt-toolset.zh.md +426 -0
- package/dist/llm/defaults.yaml +1 -1
- package/dist/llm/driver.js +4093 -0
- package/dist/llm/kernel-driver/drive.js +5 -2
- package/dist/llm/kernel-driver/flow.js +3 -0
- package/dist/minds/promptdocs.js +263 -0
- package/dist/problems.js +67 -16
- package/dist/server/api-routes.js +333 -0
- package/dist/server/prompts-routes.js +545 -0
- package/dist/server/server-core.js +4 -0
- package/dist/server/websocket-handler.js +17 -0
- package/dist/shared/team-mgmt-manual.js +120 -0
- package/dist/shared/types/prompts.js +2 -0
- package/dist/shared/types/tellask.js +8 -0
- package/dist/showing-by-doing.js +1091 -0
- package/dist/snippets/README.en.md +3 -0
- package/dist/snippets/README.md +4 -0
- package/dist/static/assets/{_basePickBy-CF9r08iy.js → _basePickBy-BMCtwrV7.js} +3 -3
- package/dist/static/assets/{_basePickBy-CF9r08iy.js.map → _basePickBy-BMCtwrV7.js.map} +1 -1
- package/dist/static/assets/{_baseUniq-CxKv0cd4.js → _baseUniq-BuyCgJiA.js} +2 -2
- package/dist/static/assets/{_baseUniq-CxKv0cd4.js.map → _baseUniq-BuyCgJiA.js.map} +1 -1
- package/dist/static/assets/{arc-C9JyvnlB.js → arc-BDuN8lwA.js} +2 -2
- package/dist/static/assets/{arc-C9JyvnlB.js.map → arc-BDuN8lwA.js.map} +1 -1
- package/dist/static/assets/{architectureDiagram-VXUJARFQ-CpcUgjHf.js → architectureDiagram-VXUJARFQ-C-ekqGAD.js} +7 -7
- package/dist/static/assets/{architectureDiagram-VXUJARFQ-CpcUgjHf.js.map → architectureDiagram-VXUJARFQ-C-ekqGAD.js.map} +1 -1
- package/dist/static/assets/{blockDiagram-VD42YOAC-BA9vtmm7.js → blockDiagram-VD42YOAC-CgQiNuuQ.js} +7 -7
- package/dist/static/assets/{blockDiagram-VD42YOAC-BA9vtmm7.js.map → blockDiagram-VD42YOAC-CgQiNuuQ.js.map} +1 -1
- package/dist/static/assets/{c4Diagram-YG6GDRKO-D49MGNdF.js → c4Diagram-YG6GDRKO-DONC39q-.js} +3 -3
- package/dist/static/assets/{c4Diagram-YG6GDRKO-D49MGNdF.js.map → c4Diagram-YG6GDRKO-DONC39q-.js.map} +1 -1
- package/dist/static/assets/{channel-B4KzL0Kg.js → channel-CJTFwXIG.js} +2 -2
- package/dist/static/assets/{channel-B4KzL0Kg.js.map → channel-CJTFwXIG.js.map} +1 -1
- package/dist/static/assets/{chunk-4BX2VUAB-0F-1ayl0.js → chunk-4BX2VUAB-NaIy4uLJ.js} +2 -2
- package/dist/static/assets/{chunk-4BX2VUAB-0F-1ayl0.js.map → chunk-4BX2VUAB-NaIy4uLJ.js.map} +1 -1
- package/dist/static/assets/{chunk-55IACEB6-Dnl2HDTZ.js → chunk-55IACEB6-JUKI_Ayx.js} +2 -2
- package/dist/static/assets/{chunk-55IACEB6-Dnl2HDTZ.js.map → chunk-55IACEB6-JUKI_Ayx.js.map} +1 -1
- package/dist/static/assets/{chunk-B4BG7PRW-Bhx5RbkQ.js → chunk-B4BG7PRW-dIswFJDn.js} +5 -5
- package/dist/static/assets/{chunk-B4BG7PRW-Bhx5RbkQ.js.map → chunk-B4BG7PRW-dIswFJDn.js.map} +1 -1
- package/dist/static/assets/{chunk-DI55MBZ5-EYd1wL3E.js → chunk-DI55MBZ5-DU2b_N30.js} +4 -4
- package/dist/static/assets/{chunk-DI55MBZ5-EYd1wL3E.js.map → chunk-DI55MBZ5-DU2b_N30.js.map} +1 -1
- package/dist/static/assets/{chunk-FMBD7UC4-DAjkhhUU.js → chunk-FMBD7UC4-BgExcScw.js} +2 -2
- package/dist/static/assets/{chunk-FMBD7UC4-DAjkhhUU.js.map → chunk-FMBD7UC4-BgExcScw.js.map} +1 -1
- package/dist/static/assets/{chunk-QN33PNHL-CK6TY7IE.js → chunk-QN33PNHL-bitxyqh7.js} +2 -2
- package/dist/static/assets/{chunk-QN33PNHL-CK6TY7IE.js.map → chunk-QN33PNHL-bitxyqh7.js.map} +1 -1
- package/dist/static/assets/{chunk-QZHKN3VN-CketngiE.js → chunk-QZHKN3VN-Cor8u7DT.js} +2 -2
- package/dist/static/assets/{chunk-QZHKN3VN-CketngiE.js.map → chunk-QZHKN3VN-Cor8u7DT.js.map} +1 -1
- package/dist/static/assets/{chunk-TZMSLE5B-Bcuvqo45.js → chunk-TZMSLE5B-Aceoxav_.js} +2 -2
- package/dist/static/assets/{chunk-TZMSLE5B-Bcuvqo45.js.map → chunk-TZMSLE5B-Aceoxav_.js.map} +1 -1
- package/dist/static/assets/{classDiagram-2ON5EDUG-CaP4T3r4.js → classDiagram-2ON5EDUG-D1Q6a8Hg.js} +6 -6
- package/dist/static/assets/{classDiagram-2ON5EDUG-CaP4T3r4.js.map → classDiagram-2ON5EDUG-D1Q6a8Hg.js.map} +1 -1
- package/dist/static/assets/{classDiagram-v2-WZHVMYZB-CaP4T3r4.js → classDiagram-v2-WZHVMYZB-D1Q6a8Hg.js} +6 -6
- package/dist/static/assets/{classDiagram-v2-WZHVMYZB-CaP4T3r4.js.map → classDiagram-v2-WZHVMYZB-D1Q6a8Hg.js.map} +1 -1
- package/dist/static/assets/{clone-C-JULvnG.js → clone-MlWbv1V0.js} +2 -2
- package/dist/static/assets/{clone-C-JULvnG.js.map → clone-MlWbv1V0.js.map} +1 -1
- package/dist/static/assets/{cose-bilkent-S5V4N54A-vXCmi_eC.js → cose-bilkent-S5V4N54A-DWPCXSrn.js} +2 -2
- package/dist/static/assets/{cose-bilkent-S5V4N54A-vXCmi_eC.js.map → cose-bilkent-S5V4N54A-DWPCXSrn.js.map} +1 -1
- package/dist/static/assets/{dagre-6UL2VRFP-bhGzX6kO.js → dagre-6UL2VRFP-C8ptQ9V3.js} +7 -7
- package/dist/static/assets/{dagre-6UL2VRFP-bhGzX6kO.js.map → dagre-6UL2VRFP-C8ptQ9V3.js.map} +1 -1
- package/dist/static/assets/{diagram-PSM6KHXK-BUKfmfGk.js → diagram-PSM6KHXK-Bgf1FqkE.js} +8 -8
- package/dist/static/assets/{diagram-PSM6KHXK-BUKfmfGk.js.map → diagram-PSM6KHXK-Bgf1FqkE.js.map} +1 -1
- package/dist/static/assets/{diagram-QEK2KX5R-DYlq3uFq.js → diagram-QEK2KX5R-BZ5xzofU.js} +7 -7
- package/dist/static/assets/{diagram-QEK2KX5R-DYlq3uFq.js.map → diagram-QEK2KX5R-BZ5xzofU.js.map} +1 -1
- package/dist/static/assets/{diagram-S2PKOQOG-CjxkLHWG.js → diagram-S2PKOQOG-Dwp47T9I.js} +7 -7
- package/dist/static/assets/{diagram-S2PKOQOG-CjxkLHWG.js.map → diagram-S2PKOQOG-Dwp47T9I.js.map} +1 -1
- package/dist/static/assets/{erDiagram-Q2GNP2WA-S3hR85On.js → erDiagram-Q2GNP2WA-Cx4weIHl.js} +5 -5
- package/dist/static/assets/{erDiagram-Q2GNP2WA-S3hR85On.js.map → erDiagram-Q2GNP2WA-Cx4weIHl.js.map} +1 -1
- package/dist/static/assets/{flowDiagram-NV44I4VS-aBmNMuQ0.js → flowDiagram-NV44I4VS-vNUuIeRk.js} +6 -6
- package/dist/static/assets/{flowDiagram-NV44I4VS-aBmNMuQ0.js.map → flowDiagram-NV44I4VS-vNUuIeRk.js.map} +1 -1
- package/dist/static/assets/{ganttDiagram-JELNMOA3-DJxXaiW1.js → ganttDiagram-JELNMOA3-BEfozJAr.js} +3 -3
- package/dist/static/assets/{ganttDiagram-JELNMOA3-DJxXaiW1.js.map → ganttDiagram-JELNMOA3-BEfozJAr.js.map} +1 -1
- package/dist/static/assets/{gitGraphDiagram-V2S2FVAM-DEOBCM0G.js → gitGraphDiagram-V2S2FVAM-eHxwc3d9.js} +8 -8
- package/dist/static/assets/{gitGraphDiagram-V2S2FVAM-DEOBCM0G.js.map → gitGraphDiagram-V2S2FVAM-eHxwc3d9.js.map} +1 -1
- package/dist/static/assets/{graph-DwrKSIE7.js → graph-C6a6uAok.js} +3 -3
- package/dist/static/assets/{graph-DwrKSIE7.js.map → graph-C6a6uAok.js.map} +1 -1
- package/dist/static/assets/{index-HWTRvE2k.js → index-D3TQbAKh.js} +383 -59
- package/dist/static/assets/index-D3TQbAKh.js.map +1 -0
- package/dist/static/assets/{infoDiagram-HS3SLOUP-BH9kVuYd.js → infoDiagram-HS3SLOUP-CX0NiId3.js} +6 -6
- package/dist/static/assets/{infoDiagram-HS3SLOUP-BH9kVuYd.js.map → infoDiagram-HS3SLOUP-CX0NiId3.js.map} +1 -1
- package/dist/static/assets/{journeyDiagram-XKPGCS4Q-Dap7AcjR.js → journeyDiagram-XKPGCS4Q-C1IepPZ-.js} +5 -5
- package/dist/static/assets/{journeyDiagram-XKPGCS4Q-Dap7AcjR.js.map → journeyDiagram-XKPGCS4Q-C1IepPZ-.js.map} +1 -1
- package/dist/static/assets/{kanban-definition-3W4ZIXB7-4NOl8MEj.js → kanban-definition-3W4ZIXB7-uMNX4Z1W.js} +3 -3
- package/dist/static/assets/{kanban-definition-3W4ZIXB7-4NOl8MEj.js.map → kanban-definition-3W4ZIXB7-uMNX4Z1W.js.map} +1 -1
- package/dist/static/assets/{layout-D6uIxu1E.js → layout-CpE3kk5z.js} +5 -5
- package/dist/static/assets/{layout-D6uIxu1E.js.map → layout-CpE3kk5z.js.map} +1 -1
- package/dist/static/assets/{linear-CvBOGQA2.js → linear-DV8laXr9.js} +2 -2
- package/dist/static/assets/{linear-CvBOGQA2.js.map → linear-DV8laXr9.js.map} +1 -1
- package/dist/static/assets/{mindmap-definition-VGOIOE7T-ugsrLNY5.js → mindmap-definition-VGOIOE7T-CKjgVM9S.js} +4 -4
- package/dist/static/assets/{mindmap-definition-VGOIOE7T-ugsrLNY5.js.map → mindmap-definition-VGOIOE7T-CKjgVM9S.js.map} +1 -1
- package/dist/static/assets/{pieDiagram-ADFJNKIX-CdVZjM8g.js → pieDiagram-ADFJNKIX-BBonlNyT.js} +8 -8
- package/dist/static/assets/{pieDiagram-ADFJNKIX-CdVZjM8g.js.map → pieDiagram-ADFJNKIX-BBonlNyT.js.map} +1 -1
- package/dist/static/assets/{quadrantDiagram-AYHSOK5B-A6m5lZKd.js → quadrantDiagram-AYHSOK5B-BTI8HbBu.js} +3 -3
- package/dist/static/assets/{quadrantDiagram-AYHSOK5B-A6m5lZKd.js.map → quadrantDiagram-AYHSOK5B-BTI8HbBu.js.map} +1 -1
- package/dist/static/assets/{requirementDiagram-UZGBJVZJ-Cac3zSJH.js → requirementDiagram-UZGBJVZJ-ZtSr9Q5R.js} +4 -4
- package/dist/static/assets/{requirementDiagram-UZGBJVZJ-Cac3zSJH.js.map → requirementDiagram-UZGBJVZJ-ZtSr9Q5R.js.map} +1 -1
- package/dist/static/assets/{sankeyDiagram-TZEHDZUN-DXDdUUl1.js → sankeyDiagram-TZEHDZUN-DibLVGzg.js} +2 -2
- package/dist/static/assets/{sankeyDiagram-TZEHDZUN-DXDdUUl1.js.map → sankeyDiagram-TZEHDZUN-DibLVGzg.js.map} +1 -1
- package/dist/static/assets/{sequenceDiagram-WL72ISMW-Domsjl5Y.js → sequenceDiagram-WL72ISMW-qXatfzVt.js} +4 -4
- package/dist/static/assets/{sequenceDiagram-WL72ISMW-Domsjl5Y.js.map → sequenceDiagram-WL72ISMW-qXatfzVt.js.map} +1 -1
- package/dist/static/assets/{stateDiagram-FKZM4ZOC-Bu0lRQK1.js → stateDiagram-FKZM4ZOC-7fgxCQHo.js} +9 -9
- package/dist/static/assets/{stateDiagram-FKZM4ZOC-Bu0lRQK1.js.map → stateDiagram-FKZM4ZOC-7fgxCQHo.js.map} +1 -1
- package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-D0K-n3ic.js → stateDiagram-v2-4FDKWEC3-DcWlOAnF.js} +5 -5
- package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-D0K-n3ic.js.map → stateDiagram-v2-4FDKWEC3-DcWlOAnF.js.map} +1 -1
- package/dist/static/assets/{timeline-definition-IT6M3QCI-BGvpddwR.js → timeline-definition-IT6M3QCI-iX2MRdpY.js} +3 -3
- package/dist/static/assets/{timeline-definition-IT6M3QCI-BGvpddwR.js.map → timeline-definition-IT6M3QCI-iX2MRdpY.js.map} +1 -1
- package/dist/static/assets/{treemap-GDKQZRPO-BoOzOm2j.js → treemap-GDKQZRPO-AVRnyXu1.js} +5 -5
- package/dist/static/assets/{treemap-GDKQZRPO-BoOzOm2j.js.map → treemap-GDKQZRPO-AVRnyXu1.js.map} +1 -1
- package/dist/static/assets/{xychartDiagram-PRI3JC2R-C_h3_ICR.js → xychartDiagram-PRI3JC2R-DVYEo5aJ.js} +3 -3
- package/dist/static/assets/{xychartDiagram-PRI3JC2R-C_h3_ICR.js.map → xychartDiagram-PRI3JC2R-DVYEo5aJ.js.map} +1 -1
- package/dist/static/index.html +1 -1
- package/dist/team.js +52 -48
- package/dist/tellask.js +439 -0
- package/dist/tools/context-health.js +177 -0
- package/dist/tools/diag.js +583 -0
- package/dist/tools/fs.js +194 -68
- package/dist/tools/prompts/memory/en/principles.md +13 -5
- package/dist/tools/prompts/memory/en/tools.md +11 -36
- package/dist/tools/prompts/memory/zh/principles.md +18 -8
- package/dist/tools/prompts/memory/zh/tools.md +11 -36
- package/dist/tools/team-mgmt.js +3487 -0
- package/dist/utils/task-doc.js +236 -0
- package/package.json +1 -1
- package/dist/static/assets/index-HWTRvE2k.js.map +0 -1
package/dist/tools/fs.js
CHANGED
|
@@ -17,6 +17,60 @@ const readline_1 = require("readline");
|
|
|
17
17
|
const access_control_1 = require("../access-control");
|
|
18
18
|
const log_1 = require("../log");
|
|
19
19
|
const runtime_language_1 = require("../shared/runtime-language");
|
|
20
|
+
async function statWithSymlinkInfo(absPath) {
|
|
21
|
+
const lstat = await promises_1.default.lstat(absPath);
|
|
22
|
+
if (!lstat.isSymbolicLink()) {
|
|
23
|
+
return {
|
|
24
|
+
lstat,
|
|
25
|
+
followStat: lstat,
|
|
26
|
+
isSymlink: false,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
let symlinkTarget;
|
|
30
|
+
try {
|
|
31
|
+
symlinkTarget = await promises_1.default.readlink(absPath);
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
log_1.log.warn(`Failed to read symlink ${absPath}:`, err);
|
|
35
|
+
}
|
|
36
|
+
const followStat = await promises_1.default.stat(absPath);
|
|
37
|
+
return {
|
|
38
|
+
lstat,
|
|
39
|
+
followStat,
|
|
40
|
+
isSymlink: true,
|
|
41
|
+
symlinkTarget,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function symlinkTargetText(target) {
|
|
45
|
+
return target ?? '<unreadable>';
|
|
46
|
+
}
|
|
47
|
+
function symlinkFollowNotice(workLanguage, relPath, target, asKind) {
|
|
48
|
+
const kindLabel = asKind === 'dir'
|
|
49
|
+
? workLanguage === 'zh'
|
|
50
|
+
? '目录'
|
|
51
|
+
: 'directory'
|
|
52
|
+
: workLanguage === 'zh'
|
|
53
|
+
? '文件'
|
|
54
|
+
: 'file';
|
|
55
|
+
const targetText = symlinkTargetText(target);
|
|
56
|
+
if (workLanguage === 'zh') {
|
|
57
|
+
return `🔗 说明:\`${relPath}\` 是符号链接(→ \`${targetText}\`),已按${kindLabel}跟随处理。`;
|
|
58
|
+
}
|
|
59
|
+
return `🔗 Note: \`${relPath}\` is a symlink (→ \`${targetText}\`) and was followed as a ${kindLabel}.`;
|
|
60
|
+
}
|
|
61
|
+
function symlinkRemovalNotice(workLanguage, relPath, target) {
|
|
62
|
+
const targetText = symlinkTargetText(target);
|
|
63
|
+
if (workLanguage === 'zh') {
|
|
64
|
+
return `🔗 说明:删除的是符号链接路径 \`${relPath}\` 本身(→ \`${targetText}\`),不会直接删除其目标。`;
|
|
65
|
+
}
|
|
66
|
+
return `🔗 Note: removed symlink path \`${relPath}\` itself (→ \`${targetText}\`), not the target directly.`;
|
|
67
|
+
}
|
|
68
|
+
function appendSymlinkYamlFields(lines, keyPrefix, info) {
|
|
69
|
+
if (!info || !info.isSymlink)
|
|
70
|
+
return;
|
|
71
|
+
lines.push(`${keyPrefix}_kind: symlink`);
|
|
72
|
+
lines.push(`${keyPrefix}_symlink_target: ${yamlQuote(symlinkTargetText(info.symlinkTarget))}`);
|
|
73
|
+
}
|
|
20
74
|
function formatSize(bytes) {
|
|
21
75
|
if (bytes === 0)
|
|
22
76
|
return '0 B';
|
|
@@ -99,6 +153,9 @@ exports.listDirTool = {
|
|
|
99
153
|
notDir: (p) => `❌ **错误**\n\n路径 \`${p}\` 不是目录。`,
|
|
100
154
|
readDirFailed: (msg) => `❌ **错误**\n\n读取目录失败:${msg}`,
|
|
101
155
|
dirHeader: '📁 **目录:**',
|
|
156
|
+
symlinkPathNotice: (p, target) => target
|
|
157
|
+
? `🔗 **说明:** \`${p}\` 是符号链接(→ \`${target}\`),已按目录跟随读取。`
|
|
158
|
+
: `🔗 **说明:** \`${p}\` 是符号链接,已按目录跟随读取。`,
|
|
102
159
|
emptyDir: '_此目录为空。_',
|
|
103
160
|
table: {
|
|
104
161
|
name: '名称',
|
|
@@ -114,6 +171,9 @@ exports.listDirTool = {
|
|
|
114
171
|
notDir: (p) => `❌ **Error**\n\nPath \`${p}\` is not a directory.`,
|
|
115
172
|
readDirFailed: (msg) => `❌ **Error**\n\nFailed to read directory: ${msg}`,
|
|
116
173
|
dirHeader: '📁 **Directory:**',
|
|
174
|
+
symlinkPathNotice: (p, target) => target
|
|
175
|
+
? `🔗 **Note:** \`${p}\` is a symlink (→ \`${target}\`), and was followed as a directory.`
|
|
176
|
+
: `🔗 **Note:** \`${p}\` is a symlink and was followed as a directory.`,
|
|
117
177
|
emptyDir: '_This directory is empty._',
|
|
118
178
|
table: {
|
|
119
179
|
name: 'Name',
|
|
@@ -141,9 +201,13 @@ exports.listDirTool = {
|
|
|
141
201
|
return content;
|
|
142
202
|
}
|
|
143
203
|
try {
|
|
204
|
+
let inputPathIsSymlink = false;
|
|
205
|
+
let inputPathSymlinkTarget;
|
|
144
206
|
try {
|
|
145
|
-
const
|
|
146
|
-
|
|
207
|
+
const statsInfo = await statWithSymlinkInfo(dir);
|
|
208
|
+
inputPathIsSymlink = statsInfo.isSymlink;
|
|
209
|
+
inputPathSymlinkTarget = statsInfo.symlinkTarget;
|
|
210
|
+
if (!statsInfo.followStat.isDirectory()) {
|
|
147
211
|
const content = labels.notDir(rel);
|
|
148
212
|
return content;
|
|
149
213
|
}
|
|
@@ -188,21 +252,31 @@ exports.listDirTool = {
|
|
|
188
252
|
try {
|
|
189
253
|
const target = await promises_1.default.readlink(entryPath);
|
|
190
254
|
dirEntry.target = target;
|
|
191
|
-
// If symlink points to a text file, count lines from the target
|
|
192
255
|
try {
|
|
193
256
|
const targetStats = await promises_1.default.stat(entryPath); // Follow the symlink
|
|
194
|
-
if (targetStats.
|
|
257
|
+
if (targetStats.isDirectory()) {
|
|
258
|
+
dirEntry.symlinkResolvedType = 'dir';
|
|
259
|
+
}
|
|
260
|
+
else if (targetStats.isFile()) {
|
|
261
|
+
dirEntry.symlinkResolvedType = 'file';
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
dirEntry.symlinkResolvedType = 'other';
|
|
265
|
+
}
|
|
266
|
+
// If symlink points to a text file, count lines from the target
|
|
267
|
+
if (targetStats.isFile() && (isTextFile(entry.name) || isTextFile(target))) {
|
|
195
268
|
dirEntry.lines = await countLines(entryPath);
|
|
196
269
|
}
|
|
197
270
|
}
|
|
198
271
|
catch (err) {
|
|
199
272
|
log_1.log.warn(`Failed to stat symlink target ${entryPath}:`, err);
|
|
200
|
-
|
|
273
|
+
dirEntry.symlinkResolvedType = 'broken';
|
|
201
274
|
}
|
|
202
275
|
}
|
|
203
276
|
catch (err) {
|
|
204
277
|
log_1.log.warn(`Failed to read symlink ${entryPath}:`, err);
|
|
205
278
|
dirEntry.target = '<unreadable>';
|
|
279
|
+
dirEntry.symlinkResolvedType = 'other';
|
|
206
280
|
}
|
|
207
281
|
}
|
|
208
282
|
else {
|
|
@@ -228,6 +302,9 @@ exports.listDirTool = {
|
|
|
228
302
|
const relativeDir = path_1.default.relative(cwd, dir) || '.';
|
|
229
303
|
// Create markdown table for directory entries
|
|
230
304
|
let markdown = `${labels.dirHeader} \`${relativeDir}\`\n\n`;
|
|
305
|
+
if (inputPathIsSymlink) {
|
|
306
|
+
markdown += `${labels.symlinkPathNotice(rel, inputPathSymlinkTarget)}\n\n`;
|
|
307
|
+
}
|
|
231
308
|
if (data.length === 0) {
|
|
232
309
|
markdown += labels.emptyDir;
|
|
233
310
|
}
|
|
@@ -244,7 +321,10 @@ exports.listDirTool = {
|
|
|
244
321
|
: '❓';
|
|
245
322
|
const sizeStr = entry.size ? formatSize(entry.size) : '-';
|
|
246
323
|
const linesStr = entry.lines ? entry.lines.toString() : '-';
|
|
247
|
-
const
|
|
324
|
+
const targetTypeStr = entry.type === 'symlink' && entry.symlinkResolvedType
|
|
325
|
+
? ` (${entry.symlinkResolvedType})`
|
|
326
|
+
: '';
|
|
327
|
+
const targetStr = entry.target ? `→ ${entry.target}${targetTypeStr}` : '-';
|
|
248
328
|
markdown += `| ${typeIcon} \`${entry.name}\` | ${entry.type} | ${sizeStr} | ${linesStr} | ${targetStr} |\n`;
|
|
249
329
|
}
|
|
250
330
|
}
|
|
@@ -335,20 +415,27 @@ exports.rmDirTool = {
|
|
|
335
415
|
return (0, access_control_1.getAccessDeniedMessage)('write', rel, workLanguage);
|
|
336
416
|
}
|
|
337
417
|
try {
|
|
418
|
+
let pathInfo;
|
|
338
419
|
// Check if path exists and is a directory
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
420
|
+
pathInfo = await statWithSymlinkInfo(targetPath);
|
|
421
|
+
const followNotice = pathInfo.isSymlink
|
|
422
|
+
? `\n\n${symlinkFollowNotice(workLanguage, rel, pathInfo.symlinkTarget, 'dir')}`
|
|
423
|
+
: '';
|
|
424
|
+
if (!pathInfo.followStat.isDirectory()) {
|
|
425
|
+
return `${labels.notDir(rel)}${followNotice}`;
|
|
342
426
|
}
|
|
343
427
|
// Check if directory is empty when not using recursive
|
|
344
428
|
if (!recursive) {
|
|
345
429
|
const entries = await promises_1.default.readdir(targetPath);
|
|
346
430
|
if (entries.length > 0) {
|
|
347
|
-
return labels.notEmpty(rel)
|
|
431
|
+
return `${labels.notEmpty(rel)}${followNotice}`;
|
|
348
432
|
}
|
|
349
433
|
}
|
|
350
434
|
// Node.js >=22+ types deprecate recursive rmdir in favor of rm.
|
|
351
435
|
await promises_1.default.rm(targetPath, { recursive, force: false });
|
|
436
|
+
if (pathInfo.isSymlink) {
|
|
437
|
+
return `${labels.removed(rel)}\n\n${symlinkFollowNotice(workLanguage, rel, pathInfo.symlinkTarget, 'dir')}\n\n${symlinkRemovalNotice(workLanguage, rel, pathInfo.symlinkTarget)}`;
|
|
438
|
+
}
|
|
352
439
|
return labels.removed(rel);
|
|
353
440
|
}
|
|
354
441
|
catch (error) {
|
|
@@ -416,13 +503,20 @@ exports.rmFileTool = {
|
|
|
416
503
|
return (0, access_control_1.getAccessDeniedMessage)('write', rel, workLanguage);
|
|
417
504
|
}
|
|
418
505
|
try {
|
|
506
|
+
let pathInfo;
|
|
419
507
|
// Check if path exists and is a file
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
508
|
+
pathInfo = await statWithSymlinkInfo(targetPath);
|
|
509
|
+
const followNotice = pathInfo.isSymlink
|
|
510
|
+
? `\n\n${symlinkFollowNotice(workLanguage, rel, pathInfo.symlinkTarget, 'file')}`
|
|
511
|
+
: '';
|
|
512
|
+
if (!pathInfo.followStat.isFile()) {
|
|
513
|
+
return `${labels.notFile(rel)}${followNotice}`;
|
|
423
514
|
}
|
|
424
515
|
// Remove the file
|
|
425
516
|
await promises_1.default.unlink(targetPath);
|
|
517
|
+
if (pathInfo.isSymlink) {
|
|
518
|
+
return `${labels.removed(rel)}\n\n${symlinkFollowNotice(workLanguage, rel, pathInfo.symlinkTarget, 'file')}\n\n${symlinkRemovalNotice(workLanguage, rel, pathInfo.symlinkTarget)}`;
|
|
519
|
+
}
|
|
426
520
|
return labels.removed(rel);
|
|
427
521
|
}
|
|
428
522
|
catch (error) {
|
|
@@ -518,7 +612,7 @@ exports.mkDirTool = {
|
|
|
518
612
|
return (0, access_control_1.getAccessDeniedMessage)('write', rel, workLanguage);
|
|
519
613
|
}
|
|
520
614
|
try {
|
|
521
|
-
const
|
|
615
|
+
const pathInfo = await statWithSymlinkInfo(targetPath).catch((err) => {
|
|
522
616
|
if (typeof err === 'object' &&
|
|
523
617
|
err !== null &&
|
|
524
618
|
'code' in err &&
|
|
@@ -527,25 +621,30 @@ exports.mkDirTool = {
|
|
|
527
621
|
}
|
|
528
622
|
throw err;
|
|
529
623
|
});
|
|
530
|
-
if (
|
|
531
|
-
|
|
532
|
-
|
|
624
|
+
if (pathInfo) {
|
|
625
|
+
const symlinkSummary = pathInfo.isSymlink
|
|
626
|
+
? ` ${symlinkFollowNotice(workLanguage, rel, pathInfo.symlinkTarget, 'dir')}`
|
|
627
|
+
: '';
|
|
628
|
+
if (!pathInfo.followStat.isDirectory()) {
|
|
629
|
+
const yamlLines = [
|
|
533
630
|
`status: error`,
|
|
534
631
|
`path: ${yamlQuote(rel)}`,
|
|
535
632
|
`error: PATH_EXISTS_NOT_DIR`,
|
|
536
633
|
`summary: ${yamlQuote(workLanguage === 'zh'
|
|
537
|
-
?
|
|
538
|
-
:
|
|
539
|
-
]
|
|
540
|
-
|
|
634
|
+
? `Mk-dir failed: path exists and is not a directory.${symlinkSummary}`
|
|
635
|
+
: `Mk-dir failed: path exists and is not a directory.${symlinkSummary}`)}`,
|
|
636
|
+
];
|
|
637
|
+
appendSymlinkYamlFields(yamlLines, 'path', pathInfo);
|
|
638
|
+
return formatYamlCodeBlock(yamlLines.join('\n'));
|
|
541
639
|
}
|
|
542
|
-
const
|
|
640
|
+
const yamlLines = [
|
|
543
641
|
`status: ok`,
|
|
544
642
|
`path: ${yamlQuote(rel)}`,
|
|
545
643
|
`created: false`,
|
|
546
|
-
`summary: ${yamlQuote(`Mk-dir: ${rel} (parents=${parents})
|
|
547
|
-
]
|
|
548
|
-
|
|
644
|
+
`summary: ${yamlQuote(`Mk-dir: ${rel} (parents=${parents}).${symlinkSummary}`)}`,
|
|
645
|
+
];
|
|
646
|
+
appendSymlinkYamlFields(yamlLines, 'path', pathInfo);
|
|
647
|
+
return formatYamlCodeBlock(yamlLines.join('\n'));
|
|
549
648
|
}
|
|
550
649
|
await promises_1.default.mkdir(targetPath, { recursive: parents });
|
|
551
650
|
const yaml = [
|
|
@@ -620,32 +719,40 @@ exports.moveFileTool = {
|
|
|
620
719
|
return (0, access_control_1.getAccessDeniedMessage)('write', from, workLanguage);
|
|
621
720
|
}
|
|
622
721
|
try {
|
|
623
|
-
const
|
|
624
|
-
|
|
625
|
-
|
|
722
|
+
const fromInfo = await statWithSymlinkInfo(absFrom);
|
|
723
|
+
const fromSymlinkSummary = fromInfo.isSymlink
|
|
724
|
+
? ` ${symlinkFollowNotice(workLanguage, from, fromInfo.symlinkTarget, 'file')}`
|
|
725
|
+
: '';
|
|
726
|
+
if (!fromInfo.followStat.isFile()) {
|
|
727
|
+
const yamlLines = [
|
|
626
728
|
`status: error`,
|
|
627
729
|
`from: ${yamlQuote(from)}`,
|
|
628
730
|
`to: ${yamlQuote(to)}`,
|
|
629
731
|
`error: FROM_NOT_FILE`,
|
|
630
732
|
`summary: ${yamlQuote(workLanguage === 'zh'
|
|
631
|
-
?
|
|
632
|
-
:
|
|
633
|
-
]
|
|
634
|
-
|
|
733
|
+
? `Move-file failed: from is not a file.${fromSymlinkSummary}`
|
|
734
|
+
: `Move-file failed: from is not a file.${fromSymlinkSummary}`)}`,
|
|
735
|
+
];
|
|
736
|
+
appendSymlinkYamlFields(yamlLines, 'from_path', fromInfo);
|
|
737
|
+
return formatYamlCodeBlock(yamlLines.join('\n'));
|
|
635
738
|
}
|
|
636
739
|
const toParent = path_1.default.dirname(absTo);
|
|
637
|
-
const
|
|
638
|
-
|
|
639
|
-
|
|
740
|
+
const toParentInfo = await statWithSymlinkInfo(toParent).catch(() => undefined);
|
|
741
|
+
const toParentSymlinkSummary = toParentInfo && toParentInfo.isSymlink
|
|
742
|
+
? ` ${symlinkFollowNotice(workLanguage, path_1.default.relative(cwd, toParent) || '.', toParentInfo.symlinkTarget, 'dir')}`
|
|
743
|
+
: '';
|
|
744
|
+
if (!toParentInfo || !toParentInfo.followStat.isDirectory()) {
|
|
745
|
+
const yamlLines = [
|
|
640
746
|
`status: error`,
|
|
641
747
|
`from: ${yamlQuote(from)}`,
|
|
642
748
|
`to: ${yamlQuote(to)}`,
|
|
643
749
|
`error: TO_PARENT_NOT_DIR`,
|
|
644
750
|
`summary: ${yamlQuote(workLanguage === 'zh'
|
|
645
|
-
?
|
|
646
|
-
:
|
|
647
|
-
]
|
|
648
|
-
|
|
751
|
+
? `Move-file failed: destination parent directory does not exist. Use mk_dir first.${toParentSymlinkSummary}`
|
|
752
|
+
: `Move-file failed: destination parent directory does not exist. Use mk_dir first.${toParentSymlinkSummary}`)}`,
|
|
753
|
+
];
|
|
754
|
+
appendSymlinkYamlFields(yamlLines, 'to_parent_path', toParentInfo);
|
|
755
|
+
return formatYamlCodeBlock(yamlLines.join('\n'));
|
|
649
756
|
}
|
|
650
757
|
const toExists = await promises_1.default
|
|
651
758
|
.lstat(absTo)
|
|
@@ -660,7 +767,7 @@ exports.moveFileTool = {
|
|
|
660
767
|
throw err;
|
|
661
768
|
});
|
|
662
769
|
if (toExists) {
|
|
663
|
-
const
|
|
770
|
+
const yamlLines = [
|
|
664
771
|
`status: error`,
|
|
665
772
|
`from: ${yamlQuote(from)}`,
|
|
666
773
|
`to: ${yamlQuote(to)}`,
|
|
@@ -668,17 +775,21 @@ exports.moveFileTool = {
|
|
|
668
775
|
`summary: ${yamlQuote(workLanguage === 'zh'
|
|
669
776
|
? 'Move-file failed: destination already exists.'
|
|
670
777
|
: 'Move-file failed: destination already exists.')}`,
|
|
671
|
-
]
|
|
672
|
-
|
|
778
|
+
];
|
|
779
|
+
appendSymlinkYamlFields(yamlLines, 'from_path', fromInfo);
|
|
780
|
+
appendSymlinkYamlFields(yamlLines, 'to_parent_path', toParentInfo);
|
|
781
|
+
return formatYamlCodeBlock(yamlLines.join('\n'));
|
|
673
782
|
}
|
|
674
783
|
await promises_1.default.rename(absFrom, absTo);
|
|
675
|
-
const
|
|
784
|
+
const yamlLines = [
|
|
676
785
|
`status: ok`,
|
|
677
786
|
`from: ${yamlQuote(from)}`,
|
|
678
787
|
`to: ${yamlQuote(to)}`,
|
|
679
|
-
`summary: ${yamlQuote(`Move-file: ${from} \u2192 ${to}
|
|
680
|
-
]
|
|
681
|
-
|
|
788
|
+
`summary: ${yamlQuote(`Move-file: ${from} \u2192 ${to}.${fromSymlinkSummary}${toParentSymlinkSummary}`)}`,
|
|
789
|
+
];
|
|
790
|
+
appendSymlinkYamlFields(yamlLines, 'from_path', fromInfo);
|
|
791
|
+
appendSymlinkYamlFields(yamlLines, 'to_parent_path', toParentInfo);
|
|
792
|
+
return formatYamlCodeBlock(yamlLines.join('\n'));
|
|
682
793
|
}
|
|
683
794
|
catch (error) {
|
|
684
795
|
const yaml = [
|
|
@@ -745,32 +856,40 @@ exports.moveDirTool = {
|
|
|
745
856
|
return (0, access_control_1.getAccessDeniedMessage)('write', from, workLanguage);
|
|
746
857
|
}
|
|
747
858
|
try {
|
|
748
|
-
const
|
|
749
|
-
|
|
750
|
-
|
|
859
|
+
const fromInfo = await statWithSymlinkInfo(absFrom);
|
|
860
|
+
const fromSymlinkSummary = fromInfo.isSymlink
|
|
861
|
+
? ` ${symlinkFollowNotice(workLanguage, from, fromInfo.symlinkTarget, 'dir')}`
|
|
862
|
+
: '';
|
|
863
|
+
if (!fromInfo.followStat.isDirectory()) {
|
|
864
|
+
const yamlLines = [
|
|
751
865
|
`status: error`,
|
|
752
866
|
`from: ${yamlQuote(from)}`,
|
|
753
867
|
`to: ${yamlQuote(to)}`,
|
|
754
868
|
`error: FROM_NOT_DIR`,
|
|
755
869
|
`summary: ${yamlQuote(workLanguage === 'zh'
|
|
756
|
-
?
|
|
757
|
-
:
|
|
758
|
-
]
|
|
759
|
-
|
|
870
|
+
? `Move-dir failed: from is not a directory.${fromSymlinkSummary}`
|
|
871
|
+
: `Move-dir failed: from is not a directory.${fromSymlinkSummary}`)}`,
|
|
872
|
+
];
|
|
873
|
+
appendSymlinkYamlFields(yamlLines, 'from_path', fromInfo);
|
|
874
|
+
return formatYamlCodeBlock(yamlLines.join('\n'));
|
|
760
875
|
}
|
|
761
876
|
const toParent = path_1.default.dirname(absTo);
|
|
762
|
-
const
|
|
763
|
-
|
|
764
|
-
|
|
877
|
+
const toParentInfo = await statWithSymlinkInfo(toParent).catch(() => undefined);
|
|
878
|
+
const toParentSymlinkSummary = toParentInfo && toParentInfo.isSymlink
|
|
879
|
+
? ` ${symlinkFollowNotice(workLanguage, path_1.default.relative(cwd, toParent) || '.', toParentInfo.symlinkTarget, 'dir')}`
|
|
880
|
+
: '';
|
|
881
|
+
if (!toParentInfo || !toParentInfo.followStat.isDirectory()) {
|
|
882
|
+
const yamlLines = [
|
|
765
883
|
`status: error`,
|
|
766
884
|
`from: ${yamlQuote(from)}`,
|
|
767
885
|
`to: ${yamlQuote(to)}`,
|
|
768
886
|
`error: TO_PARENT_NOT_DIR`,
|
|
769
887
|
`summary: ${yamlQuote(workLanguage === 'zh'
|
|
770
|
-
?
|
|
771
|
-
:
|
|
772
|
-
]
|
|
773
|
-
|
|
888
|
+
? `Move-dir failed: destination parent directory does not exist. Use mk_dir first.${toParentSymlinkSummary}`
|
|
889
|
+
: `Move-dir failed: destination parent directory does not exist. Use mk_dir first.${toParentSymlinkSummary}`)}`,
|
|
890
|
+
];
|
|
891
|
+
appendSymlinkYamlFields(yamlLines, 'to_parent_path', toParentInfo);
|
|
892
|
+
return formatYamlCodeBlock(yamlLines.join('\n'));
|
|
774
893
|
}
|
|
775
894
|
const toExists = await promises_1.default
|
|
776
895
|
.lstat(absTo)
|
|
@@ -785,7 +904,7 @@ exports.moveDirTool = {
|
|
|
785
904
|
throw err;
|
|
786
905
|
});
|
|
787
906
|
if (toExists) {
|
|
788
|
-
const
|
|
907
|
+
const yamlLines = [
|
|
789
908
|
`status: error`,
|
|
790
909
|
`from: ${yamlQuote(from)}`,
|
|
791
910
|
`to: ${yamlQuote(to)}`,
|
|
@@ -793,19 +912,26 @@ exports.moveDirTool = {
|
|
|
793
912
|
`summary: ${yamlQuote(workLanguage === 'zh'
|
|
794
913
|
? 'Move-dir failed: destination already exists.'
|
|
795
914
|
: 'Move-dir failed: destination already exists.')}`,
|
|
796
|
-
]
|
|
797
|
-
|
|
915
|
+
];
|
|
916
|
+
appendSymlinkYamlFields(yamlLines, 'from_path', fromInfo);
|
|
917
|
+
appendSymlinkYamlFields(yamlLines, 'to_parent_path', toParentInfo);
|
|
918
|
+
return formatYamlCodeBlock(yamlLines.join('\n'));
|
|
798
919
|
}
|
|
799
|
-
const movedEntryCount = await countDirEntries(absFrom);
|
|
920
|
+
const movedEntryCount = fromInfo.isSymlink ? 1 : await countDirEntries(absFrom);
|
|
800
921
|
await promises_1.default.rename(absFrom, absTo);
|
|
801
|
-
const
|
|
922
|
+
const symlinkMoveNotice = fromInfo.isSymlink
|
|
923
|
+
? ` ${symlinkRemovalNotice(workLanguage, from, fromInfo.symlinkTarget)}`
|
|
924
|
+
: '';
|
|
925
|
+
const yamlLines = [
|
|
802
926
|
`status: ok`,
|
|
803
927
|
`from: ${yamlQuote(from)}`,
|
|
804
928
|
`to: ${yamlQuote(to)}`,
|
|
805
929
|
`moved_entry_count: ${movedEntryCount}`,
|
|
806
|
-
`summary: ${yamlQuote(`Move-dir: ${from} \u2192 ${to} (${movedEntryCount} entries)
|
|
807
|
-
]
|
|
808
|
-
|
|
930
|
+
`summary: ${yamlQuote(`Move-dir: ${from} \u2192 ${to} (${movedEntryCount} entries).${fromSymlinkSummary}${toParentSymlinkSummary}${symlinkMoveNotice}`)}`,
|
|
931
|
+
];
|
|
932
|
+
appendSymlinkYamlFields(yamlLines, 'from_path', fromInfo);
|
|
933
|
+
appendSymlinkYamlFields(yamlLines, 'to_parent_path', toParentInfo);
|
|
934
|
+
return formatYamlCodeBlock(yamlLines.join('\n'));
|
|
809
935
|
}
|
|
810
936
|
catch (error) {
|
|
811
937
|
const yaml = [
|
|
@@ -51,14 +51,20 @@ The memory toolset uses a **path key-value storage** model:
|
|
|
51
51
|
### 1. Path Naming Conventions
|
|
52
52
|
|
|
53
53
|
- Use descriptive paths: `project/architecture`, `user/preferences/language`
|
|
54
|
-
-
|
|
55
|
-
-
|
|
54
|
+
- Use `/` to organize hierarchy (this is the recommended usage), with guardrails:
|
|
55
|
+
- Absolute paths are forbidden (must not start with `/`)
|
|
56
|
+
- Path traversal is forbidden (`..` is not allowed)
|
|
57
|
+
- Avoid `\\` (cross-platform readability; prefer `/`)
|
|
58
|
+
- Keep paths _flat_: prefer a small number of topic files rather than a deep directory tree.
|
|
56
59
|
|
|
57
60
|
### 2. Content Format
|
|
58
61
|
|
|
59
|
-
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
62
|
+
- Treat personal memory as a **carry-along stable-facts memo**: enable **0 ripgrep** startup within your scope.
|
|
63
|
+
- Store stable facts only: **anchor points (file/symbol) + 1-line meaning + key contracts/priorities (≤3)**.
|
|
64
|
+
- Fewer memory files is better: group facts that will be updated together into one file; avoid adding extra “directory-of-directory” layers.
|
|
65
|
+
- Do not store task progress or daily state here:
|
|
66
|
+
- Team-visible progress belongs in Taskdoc `progress`
|
|
67
|
+
- Short-term working set belongs in reminders
|
|
62
68
|
|
|
63
69
|
### 3. Usage Scenarios
|
|
64
70
|
|
|
@@ -66,6 +72,8 @@ The memory toolset uses a **path key-value storage** model:
|
|
|
66
72
|
- **Context memory**: Save important information from conversation context
|
|
67
73
|
- **Preference settings**: Save user preferences and configuration information
|
|
68
74
|
|
|
75
|
+
> Note: If you find yourself using personal memory to store “current progress of this run”, it likely belongs in Taskdoc `progress` or reminders instead.
|
|
76
|
+
|
|
69
77
|
## Relationship with Other Tools
|
|
70
78
|
|
|
71
79
|
- **team_memory**: Team shared memory, visible to all members
|
|
@@ -30,12 +30,8 @@ Create new memory (when path does not exist).
|
|
|
30
30
|
|
|
31
31
|
**Returns:**
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
path: <memory path>
|
|
36
|
-
content_size: <content size in bytes>
|
|
37
|
-
created_at: <creation timestamp>
|
|
38
|
-
```
|
|
33
|
+
- Success: a short plain-text message in the work language (e.g. `Added`).
|
|
34
|
+
- Failure: a plain-text error message (often starts with `Error:`) with an actionable next step (e.g. use `replace_memory`).
|
|
39
35
|
|
|
40
36
|
**Errors:**
|
|
41
37
|
|
|
@@ -52,12 +48,8 @@ Update existing memory (when path exists).
|
|
|
52
48
|
|
|
53
49
|
**Returns:**
|
|
54
50
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
path: <memory path>
|
|
58
|
-
content_size: <content size in bytes>
|
|
59
|
-
updated_at: <update timestamp>
|
|
60
|
-
```
|
|
51
|
+
- Success: a short plain-text message in the work language (e.g. `Updated`).
|
|
52
|
+
- Failure: a plain-text error message (often starts with `Error:`) with an actionable next step (e.g. use `add_memory`).
|
|
61
53
|
|
|
62
54
|
**Errors:**
|
|
63
55
|
|
|
@@ -73,11 +65,8 @@ Delete specified memory.
|
|
|
73
65
|
|
|
74
66
|
**Returns:**
|
|
75
67
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
path: <memory path>
|
|
79
|
-
deleted_at: <deletion timestamp>
|
|
80
|
-
```
|
|
68
|
+
- Success: a short plain-text message in the work language (e.g. `Deleted`).
|
|
69
|
+
- Failure: a plain-text error message (often starts with `Error:`).
|
|
81
70
|
|
|
82
71
|
**Errors:**
|
|
83
72
|
|
|
@@ -93,11 +82,8 @@ Clear all personal memory.
|
|
|
93
82
|
|
|
94
83
|
**Returns:**
|
|
95
84
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
cleared_count: <number of memories deleted>
|
|
99
|
-
cleared_at: <deletion timestamp>
|
|
100
|
-
```
|
|
85
|
+
- Success: a short plain-text message in the work language (e.g. `Cleared`). If there is nothing to clear, returns a message like `No personal memory to clear.`
|
|
86
|
+
- Failure: a plain-text error message.
|
|
101
87
|
|
|
102
88
|
**Errors:**
|
|
103
89
|
|
|
@@ -137,18 +123,7 @@ drop_memory({
|
|
|
137
123
|
clear_memory({});
|
|
138
124
|
```
|
|
139
125
|
|
|
140
|
-
##
|
|
126
|
+
## Output and Language
|
|
141
127
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
- `status`: Operation status, `ok` for success, `error` for failure
|
|
145
|
-
- `path`: Memory path
|
|
146
|
-
- Other fields: Additional information for specific operations
|
|
147
|
-
|
|
148
|
-
On error, returns:
|
|
149
|
-
|
|
150
|
-
```yaml
|
|
151
|
-
status: error
|
|
152
|
-
error_code: <error code>
|
|
153
|
-
message: <error message>
|
|
154
|
-
```
|
|
128
|
+
- Output is **plain text**, not structured JSON/YAML.
|
|
129
|
+
- The message language follows the current **work language**.
|
|
@@ -51,14 +51,20 @@ memory 工具集采用**路径键值存储**模型:
|
|
|
51
51
|
### 1. 路径命名规范
|
|
52
52
|
|
|
53
53
|
- 使用描述性路径:`project/architecture`、`user/preferences/language`
|
|
54
|
-
-
|
|
55
|
-
-
|
|
54
|
+
- 允许用 `/` 组织层级(这就是推荐用法),但必须遵守护栏:
|
|
55
|
+
- 不允许绝对路径(不能以 `/` 开头)
|
|
56
|
+
- 不允许路径穿越(`..` 禁止)
|
|
57
|
+
- 避免使用 `\\`(跨平台可读性差,统一用 `/`)
|
|
58
|
+
- 保持路径扁平:优先少量主题文件,而不是深层目录树(个人记忆的目标是“快速索引”,不是建文件系统)。
|
|
56
59
|
|
|
57
60
|
### 2. 内容格式
|
|
58
61
|
|
|
59
|
-
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
62
|
+
- 把个人记忆当作“长期随身携带的稳定事实备忘”:让你在职责范围内尽量做到 **0 次 ripgrep 就能开工**。
|
|
63
|
+
- 内容只写稳定事实:**落点(文件/符号)+ 一句话语义 + 关键契约/优先级(≤3 条)**。
|
|
64
|
+
- 记忆文件更少更好:按“未来会一起更新的内容”合并在同一文件里;不要为了“看起来整齐”引入额外的“目录套目录”。
|
|
65
|
+
- 不要把任务进度/当天状态写进个人记忆:
|
|
66
|
+
- 任务协作公告板用差遣牒(Taskdoc 的 `progress`)
|
|
67
|
+
- 短期工作集用提醒项(reminders)
|
|
62
68
|
|
|
63
69
|
### 3. 使用场景
|
|
64
70
|
|
|
@@ -66,6 +72,8 @@ memory 工具集采用**路径键值存储**模型:
|
|
|
66
72
|
- **上下文记忆**:保存对话上下文中的重要信息
|
|
67
73
|
- **偏好设置**:保存用户偏好和配置信息
|
|
68
74
|
|
|
75
|
+
> 注:如果你发现自己在用个人记忆保存“这次对话的当前进展”,大概率应该写到 Taskdoc `progress` 或 reminders。
|
|
76
|
+
|
|
69
77
|
## 与其他工具的关系
|
|
70
78
|
|
|
71
79
|
- **team_memory**:团队共享记忆,所有成员可见
|
|
@@ -74,6 +82,8 @@ memory 工具集采用**路径键值存储**模型:
|
|
|
74
82
|
|
|
75
83
|
## 限制与注意事项
|
|
76
84
|
|
|
77
|
-
1.
|
|
78
|
-
2.
|
|
79
|
-
3. `clear_memory`
|
|
85
|
+
1. 路径护栏:不允许绝对路径;不允许包含 `..`。
|
|
86
|
+
2. 内容护栏:`content` 不能为空字符串。
|
|
87
|
+
3. `clear_memory` 会删除当前智能体的全部个人记忆,**不可恢复**。
|
|
88
|
+
|
|
89
|
+
> 建议:即使当前实现没有硬性 size 限制,也应保持记忆内容精炼,否则会显著增加上下文成本与过期风险。
|