codexmate 0.0.48 → 0.0.49
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/README.md +2 -0
- package/README.zh.md +2 -0
- package/cli/agents-files.js +97 -28
- package/cli.js +10 -2
- package/package.json +1 -1
- package/web-ui/app.js +28 -1
- package/web-ui/logic.agents-diff.mjs +6 -0
- package/web-ui/modules/app.methods.agents.mjs +82 -16
- package/web-ui/modules/i18n/locales/en.mjs +12 -6
- package/web-ui/modules/i18n/locales/ja.mjs +12 -6
- package/web-ui/modules/i18n/locales/vi.mjs +12 -2
- package/web-ui/modules/i18n/locales/zh-tw.mjs +12 -6
- package/web-ui/modules/i18n/locales/zh.mjs +12 -6
- package/web-ui/partials/index/layout-header.html +5 -5
- package/web-ui/partials/index/modal-config-template-agents.html +2 -2
- package/web-ui/partials/index/panel-prompts.html +24 -2
- package/web-ui/res/web-ui-render.precompiled.js +47 -11
- package/web-ui/styles/modals-core.css +33 -0
- package/web-ui/styles/titles-cards.css +2 -2
package/README.md
CHANGED
|
@@ -58,6 +58,7 @@ Unlike simple wrappers, Codex Mate acts as a **Local Agent Bridge**:
|
|
|
58
58
|
- **Claude Provider Bridge**: Connect Claude Code to OpenAI Chat Completions-compatible providers and Ollama through the built-in local Claude-compatible proxy.
|
|
59
59
|
- **OpenCode Provider Control**: Manage OpenCode provider/model selection with a CodexMate-owned provider store under `~/.codexmate`, projecting only the active provider into native OpenCode config to avoid polluting or deleting user-owned settings.
|
|
60
60
|
- **Skills Marketplace**: A local-first market to share and import skills between different agent apps.
|
|
61
|
+
- **Prompt File Editor**: Unified editor for global and project-level `CLAUDE.md` and `AGENTS.md` with auto-detection of project paths.
|
|
61
62
|
- **Task Orchestrator**: Plan and execute complex tasks with dependency tracking.
|
|
62
63
|
|
|
63
64
|
---
|
|
@@ -76,6 +77,7 @@ Unlike simple wrappers, Codex Mate acts as a **Local Agent Bridge**:
|
|
|
76
77
|
| **Claude Provider Bridge** | ✅ | Connect Claude Code to OpenAI Chat Completions-compatible providers and Ollama via the built-in Claude-compatible proxy |
|
|
77
78
|
| **OpenCode Provider Store** | ✅ | Keep multiple OpenCode providers in `~/.codexmate` while projecting only the selected provider to native OpenCode config |
|
|
78
79
|
| **Prompt Templates** | ✅ | Reusable prompt plugins with variables |
|
|
80
|
+
| **Prompt File Editor** | ✅ | Edit global and project-level CLAUDE.md / AGENTS.md with auto-detect and path switching |
|
|
79
81
|
| **MCP Integration** | ✅ | Expose local tools and resources via MCP stdio |
|
|
80
82
|
| **Auto Update** | ✅ | Quick update CLI via `codexmate update` |
|
|
81
83
|
|
package/README.zh.md
CHANGED
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
- **Claude Provider 桥接**:通过内建本地 Claude 兼容代理,让 Claude Code 接入 OpenAI Chat Completions 兼容 provider 与 Ollama。
|
|
59
59
|
- **OpenCode Provider 控制**:在 `~/.codexmate` 下维护 CodexMate 自有的 OpenCode 多 provider 存储,只将当前选中的 provider 投影到 OpenCode 原生配置,避免污染或误删用户已有配置。
|
|
60
60
|
- **Skills 市场**:本地优先的市场,支持在不同的智能体应用之间共享和导入 Skills。
|
|
61
|
+
- **提示词文件编辑器**:统一编辑全局和项目级 `CLAUDE.md` 与 `AGENTS.md`,支持项目路径自动检测。
|
|
61
62
|
- **任务编排器**:支持带有依赖跟踪的复杂任务规划与执行。
|
|
62
63
|
|
|
63
64
|
---
|
|
@@ -76,6 +77,7 @@
|
|
|
76
77
|
| **Claude Provider 桥接** | ✅ | 通过内建 Claude 兼容代理,让 Claude Code 接入 OpenAI Chat Completions 兼容 provider 与 Ollama |
|
|
77
78
|
| **OpenCode Provider 存储** | ✅ | 在 `~/.codexmate` 中保留多个 OpenCode provider,只将当前选中的 provider 投影到 OpenCode 原生配置 |
|
|
78
79
|
| **提示词模板** | ✅ | 支持变量的可复用提示词插件 |
|
|
80
|
+
| **提示词文件编辑器** | ✅ | 编辑全局和项目级 CLAUDE.md / AGENTS.md,支持自动检测与路径切换 |
|
|
79
81
|
| **MCP 集成** | ✅ | 通过 MCP stdio 暴露本地工具与资源 |
|
|
80
82
|
| **自动更新** | ✅ | 通过 `codexmate update` 快速更新 CLI |
|
|
81
83
|
|
package/cli/agents-files.js
CHANGED
|
@@ -53,57 +53,119 @@ function createAgentsFileController(deps = {}) {
|
|
|
53
53
|
return { ok: true, dirPath };
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
function
|
|
57
|
-
|
|
56
|
+
function detectProjectClaudeMdDir(baseDir) {
|
|
57
|
+
if (typeof baseDir !== 'string' || !baseDir.trim()) {
|
|
58
|
+
return { error: 'project path is required' };
|
|
59
|
+
}
|
|
60
|
+
const root = baseDir.trim();
|
|
61
|
+
const rootPath = path.join(root, CLAUDE_MD_FILE_NAME);
|
|
62
|
+
const dotDirPath = path.join(root, '.claude', CLAUDE_MD_FILE_NAME);
|
|
63
|
+
try {
|
|
64
|
+
if (fs.statSync(rootPath).isFile()) {
|
|
65
|
+
return { path: rootPath, source: 'root', dir: root };
|
|
66
|
+
}
|
|
67
|
+
} catch (_) {}
|
|
68
|
+
try {
|
|
69
|
+
if (fs.statSync(dotDirPath).isFile()) {
|
|
70
|
+
return { path: dotDirPath, source: 'dotdir', dir: path.join(root, '.claude') };
|
|
71
|
+
}
|
|
72
|
+
} catch (_) {}
|
|
73
|
+
return { path: rootPath, source: 'root', dir: root };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function validateClaudeMdBaseDir(filePath) {
|
|
77
|
+
const dirPath = path.dirname(filePath);
|
|
78
|
+
try {
|
|
79
|
+
const stat = fs.statSync(dirPath);
|
|
80
|
+
if (!stat.isDirectory()) {
|
|
81
|
+
return { error: 'project directory is not a directory: ' + dirPath };
|
|
82
|
+
}
|
|
83
|
+
} catch (e) {
|
|
84
|
+
return { error: 'project directory does not exist: ' + dirPath };
|
|
85
|
+
}
|
|
86
|
+
return { ok: true, dirPath };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function resolveClaudeMdFilePath(params = {}) {
|
|
90
|
+
const baseDir = typeof params.baseDir === 'string' && params.baseDir.trim()
|
|
91
|
+
? params.baseDir.trim()
|
|
92
|
+
: '';
|
|
93
|
+
if (!baseDir) {
|
|
94
|
+
return { filePath: path.join(CLAUDE_DIR, CLAUDE_MD_FILE_NAME), isProject: false };
|
|
95
|
+
}
|
|
96
|
+
var detected = detectProjectClaudeMdDir(baseDir);
|
|
97
|
+
if (detected.error) {
|
|
98
|
+
return { filePath: path.join(CLAUDE_DIR, CLAUDE_MD_FILE_NAME), isProject: false, detectionError: detected.error };
|
|
99
|
+
}
|
|
100
|
+
return { filePath: detected.path, isProject: true, detectionSource: detected.source, projectPath: baseDir };
|
|
58
101
|
}
|
|
59
102
|
|
|
60
103
|
function readClaudeMdFile(params = {}) {
|
|
61
|
-
|
|
62
|
-
|
|
104
|
+
var resolved = resolveClaudeMdFilePath(params);
|
|
105
|
+
var filePath = resolved.filePath;
|
|
106
|
+
var lineEndingFallback = os.EOL === '\r\n' ? '\r\n' : '\n';
|
|
107
|
+
var base = {
|
|
108
|
+
path: filePath,
|
|
109
|
+
lineEnding: lineEndingFallback
|
|
110
|
+
};
|
|
111
|
+
if (resolved.isProject) {
|
|
112
|
+
base.detectionSource = resolved.detectionSource;
|
|
113
|
+
base.projectPath = resolved.projectPath;
|
|
114
|
+
}
|
|
115
|
+
if (resolved.detectionError) {
|
|
116
|
+
base.detectionError = resolved.detectionError;
|
|
117
|
+
}
|
|
118
|
+
if (resolved.isProject) {
|
|
119
|
+
var dirCheck = validateClaudeMdBaseDir(filePath);
|
|
120
|
+
if (dirCheck.error) {
|
|
121
|
+
return { error: dirCheck.error };
|
|
122
|
+
}
|
|
123
|
+
}
|
|
63
124
|
if (!fs.existsSync(filePath)) {
|
|
64
|
-
return {
|
|
65
|
-
exists: false,
|
|
66
|
-
path: filePath,
|
|
67
|
-
content: '',
|
|
68
|
-
lineEnding: lineEndingFallback
|
|
69
|
-
};
|
|
125
|
+
return Object.assign({ exists: false, content: '' }, base);
|
|
70
126
|
}
|
|
71
127
|
if (params.metaOnly) {
|
|
72
|
-
return {
|
|
73
|
-
exists: true,
|
|
74
|
-
path: filePath,
|
|
75
|
-
content: '',
|
|
76
|
-
lineEnding: lineEndingFallback
|
|
77
|
-
};
|
|
128
|
+
return Object.assign({ exists: true, content: '' }, base);
|
|
78
129
|
}
|
|
79
130
|
try {
|
|
80
|
-
|
|
81
|
-
|
|
131
|
+
var raw = fs.readFileSync(filePath, 'utf-8');
|
|
132
|
+
var result = {
|
|
82
133
|
exists: true,
|
|
83
134
|
path: filePath,
|
|
84
135
|
content: stripUtf8Bom(raw),
|
|
85
136
|
lineEnding: detectLineEnding(raw)
|
|
86
137
|
};
|
|
138
|
+
if (resolved.isProject) {
|
|
139
|
+
result.detectionSource = resolved.detectionSource;
|
|
140
|
+
result.projectPath = resolved.projectPath;
|
|
141
|
+
}
|
|
142
|
+
return result;
|
|
87
143
|
} catch (e) {
|
|
88
|
-
return { error:
|
|
144
|
+
return { error: 'read CLAUDE.md failed: ' + e.message };
|
|
89
145
|
}
|
|
90
146
|
}
|
|
91
147
|
|
|
92
148
|
function applyClaudeMdFile(params = {}) {
|
|
93
|
-
|
|
94
|
-
|
|
149
|
+
var resolved = resolveClaudeMdFilePath(params);
|
|
150
|
+
var filePath = resolved.filePath;
|
|
151
|
+
var content = typeof params.content === 'string' ? params.content : '';
|
|
95
152
|
if (content.length > 2 * 1024 * 1024) {
|
|
96
|
-
return { error: '
|
|
153
|
+
return { error: 'content too large (max 2MB)' };
|
|
97
154
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
155
|
+
var lineEnding = params.lineEnding === '\r\n' ? '\r\n' : '\n';
|
|
156
|
+
var normalized = normalizeLineEnding(content, lineEnding);
|
|
157
|
+
var finalContent = ensureUtf8Bom(normalized);
|
|
101
158
|
try {
|
|
102
|
-
ensureDir(
|
|
159
|
+
ensureDir(path.dirname(filePath));
|
|
103
160
|
fs.writeFileSync(filePath, finalContent, 'utf-8');
|
|
104
|
-
|
|
161
|
+
var result = { success: true, path: filePath };
|
|
162
|
+
if (resolved.isProject) {
|
|
163
|
+
result.projectPath = resolved.projectPath;
|
|
164
|
+
result.detectionSource = resolved.detectionSource;
|
|
165
|
+
}
|
|
166
|
+
return result;
|
|
105
167
|
} catch (e) {
|
|
106
|
-
return { error:
|
|
168
|
+
return { error: 'write CLAUDE.md failed: ' + e.message };
|
|
107
169
|
}
|
|
108
170
|
}
|
|
109
171
|
|
|
@@ -181,6 +243,11 @@ function createAgentsFileController(deps = {}) {
|
|
|
181
243
|
let readResult;
|
|
182
244
|
if (context === 'claude-md') {
|
|
183
245
|
readResult = readClaudeMdFile({ metaOnly });
|
|
246
|
+
} else if (context === 'claude-project') {
|
|
247
|
+
if (!params.baseDir || !String(params.baseDir).trim()) {
|
|
248
|
+
return { error: 'project path is required for claude-project context' };
|
|
249
|
+
}
|
|
250
|
+
readResult = readClaudeMdFile({ ...params, metaOnly });
|
|
184
251
|
} else if (context === 'openclaw') {
|
|
185
252
|
readResult = readOpenclawAgentsFile({ metaOnly });
|
|
186
253
|
} else if (context === 'openclaw-workspace') {
|
|
@@ -215,6 +282,8 @@ function createAgentsFileController(deps = {}) {
|
|
|
215
282
|
return {
|
|
216
283
|
resolveAgentsFilePath,
|
|
217
284
|
validateAgentsBaseDir,
|
|
285
|
+
detectProjectClaudeMdDir,
|
|
286
|
+
validateClaudeMdBaseDir,
|
|
218
287
|
resolveClaudeMdFilePath,
|
|
219
288
|
readClaudeMdFile,
|
|
220
289
|
applyClaudeMdFile,
|
package/cli.js
CHANGED
|
@@ -1828,6 +1828,8 @@ async function fetchProviderModels(providerName, overrides = {}) {
|
|
|
1828
1828
|
const {
|
|
1829
1829
|
resolveAgentsFilePath,
|
|
1830
1830
|
validateAgentsBaseDir,
|
|
1831
|
+
detectProjectClaudeMdDir,
|
|
1832
|
+
validateClaudeMdBaseDir,
|
|
1831
1833
|
resolveClaudeMdFilePath,
|
|
1832
1834
|
readClaudeMdFile,
|
|
1833
1835
|
applyClaudeMdFile,
|
|
@@ -11876,10 +11878,16 @@ function createWebServer({ htmlPath, assetsDir, webDir, host, port, openBrowser
|
|
|
11876
11878
|
case 'apply-claude-md-file':
|
|
11877
11879
|
result = applyClaudeMdFile(params || {});
|
|
11878
11880
|
if (result && !result.error) {
|
|
11879
|
-
const
|
|
11880
|
-
|
|
11881
|
+
const mdBaseDir = params && params.baseDir ? String(params.baseDir).trim() : '';
|
|
11882
|
+
const mdTarget = mdBaseDir
|
|
11883
|
+
? path.join(mdBaseDir, 'CLAUDE.md')
|
|
11884
|
+
: ((params && params.targetPath) ? String(params.targetPath) : 'CLAUDE.md');
|
|
11885
|
+
notifyWebhook('claude-md-edit', 'CLAUDE.md modified: ' + mdTarget, { targetPath: mdTarget, projectPath: mdBaseDir }).catch(function () { });
|
|
11881
11886
|
}
|
|
11882
11887
|
break;
|
|
11888
|
+
case 'detect-project-claude-md':
|
|
11889
|
+
result = detectProjectClaudeMdDir((params && params.baseDir) || '');
|
|
11890
|
+
break;
|
|
11883
11891
|
case 'preview-agents-diff':
|
|
11884
11892
|
result = buildAgentsDiff(params || {});
|
|
11885
11893
|
break;
|
package/package.json
CHANGED
package/web-ui/app.js
CHANGED
|
@@ -74,6 +74,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
74
74
|
showConfigTemplateModal: false,
|
|
75
75
|
showAgentsModal: false,
|
|
76
76
|
promptsSubTab: 'codex',
|
|
77
|
+
projectClaudeMdPath: '',
|
|
78
|
+
projectPathOptions: [],
|
|
79
|
+
projectPathOptionsLoading: false,
|
|
77
80
|
showSkillsModal: false,
|
|
78
81
|
showHealthCheckModal: false,
|
|
79
82
|
showCodexBridgePoolModal: false,
|
|
@@ -574,6 +577,18 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
574
577
|
this.sessionTrashEnabled = this.normalizeSessionTrashEnabled(localStorage.getItem('codexmateSessionTrashEnabled'));
|
|
575
578
|
this.sessionTrashRetentionDays = this.normalizeSessionTrashRetentionDays(localStorage.getItem('codexmateSessionTrashRetentionDays'));
|
|
576
579
|
this.configTemplateDiffConfirmEnabled = loadConfigTemplateDiffConfirmEnabledFromStorage(localStorage);
|
|
580
|
+
try {
|
|
581
|
+
var savedProjectPath = localStorage.getItem('codexmate_project_claude_md_path');
|
|
582
|
+
if (savedProjectPath) {
|
|
583
|
+
this.projectClaudeMdPath = savedProjectPath;
|
|
584
|
+
}
|
|
585
|
+
} catch (_) {}
|
|
586
|
+
try {
|
|
587
|
+
var savedSubTab = localStorage.getItem('codexmate_prompts_sub_tab');
|
|
588
|
+
if (savedSubTab === 'codex' || savedSubTab === 'claude-project') {
|
|
589
|
+
this.promptsSubTab = savedSubTab;
|
|
590
|
+
}
|
|
591
|
+
} catch (_) {}
|
|
577
592
|
window.addEventListener('resize', this.onWindowResize);
|
|
578
593
|
window.addEventListener('keydown', this.handleGlobalKeydown);
|
|
579
594
|
window.addEventListener('beforeunload', this.handleBeforeUnload);
|
|
@@ -740,10 +755,22 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
740
755
|
this.loadPromptsContent();
|
|
741
756
|
}
|
|
742
757
|
},
|
|
743
|
-
promptsSubTab() {
|
|
758
|
+
promptsSubTab(newVal) {
|
|
759
|
+
try {
|
|
760
|
+
localStorage.setItem('codexmate_prompts_sub_tab', newVal);
|
|
761
|
+
} catch (_) {}
|
|
744
762
|
if (this.mainTab === 'prompts' && typeof this.loadPromptsContent === 'function') {
|
|
745
763
|
this.loadPromptsContent();
|
|
746
764
|
}
|
|
765
|
+
},
|
|
766
|
+
projectClaudeMdPath(newPath) {
|
|
767
|
+
try {
|
|
768
|
+
if (newPath) {
|
|
769
|
+
localStorage.setItem('codexmate_project_claude_md_path', newPath);
|
|
770
|
+
} else {
|
|
771
|
+
localStorage.removeItem('codexmate_project_claude_md_path');
|
|
772
|
+
}
|
|
773
|
+
} catch (_) {}
|
|
747
774
|
}
|
|
748
775
|
},
|
|
749
776
|
|
|
@@ -336,6 +336,12 @@ export function buildAgentsDiffPreviewRequest(options = {}) {
|
|
|
336
336
|
params.fileName = fileName;
|
|
337
337
|
}
|
|
338
338
|
}
|
|
339
|
+
if (context === 'claude-project') {
|
|
340
|
+
const baseDir = typeof options.baseDir === 'string' ? options.baseDir.trim() : '';
|
|
341
|
+
if (baseDir) {
|
|
342
|
+
params.baseDir = baseDir;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
339
345
|
|
|
340
346
|
const maxRequestBytes = Number.isFinite(options.maxRequestBytes)
|
|
341
347
|
? Math.max(1024, Math.floor(options.maxRequestBytes))
|
|
@@ -37,11 +37,16 @@ export function createAgentsMethods(options = {}) {
|
|
|
37
37
|
|
|
38
38
|
return {
|
|
39
39
|
async openClaudeMdEditor() {
|
|
40
|
-
this.setAgentsModalContext('claude-
|
|
40
|
+
this.setAgentsModalContext('claude-project');
|
|
41
41
|
const requestToken = issueLatestRequestToken(this, '_agentsOpenRequestToken');
|
|
42
42
|
this.agentsLoading = true;
|
|
43
43
|
try {
|
|
44
|
-
const
|
|
44
|
+
const rpcParams = {};
|
|
45
|
+
var projectPath = (this.projectClaudeMdPath || '').trim();
|
|
46
|
+
if (projectPath) {
|
|
47
|
+
rpcParams.baseDir = projectPath;
|
|
48
|
+
}
|
|
49
|
+
const res = await api('get-claude-md-file', rpcParams);
|
|
45
50
|
if (!isLatestRequestToken(this, '_agentsOpenRequestToken', requestToken)) {
|
|
46
51
|
return;
|
|
47
52
|
}
|
|
@@ -182,11 +187,18 @@ export function createAgentsMethods(options = {}) {
|
|
|
182
187
|
setAgentsModalContext(context, options = {}) {
|
|
183
188
|
const t = typeof this.t === 'function' ? this.t : null;
|
|
184
189
|
const tr = (key, fallback, params = null) => (t ? t(key, params) : fallback);
|
|
185
|
-
if (context === 'claude-
|
|
186
|
-
this.
|
|
190
|
+
if (context === 'claude-project') {
|
|
191
|
+
var projectPath = (options.projectPath || this.projectClaudeMdPath || '').trim();
|
|
192
|
+
this.agentsContext = 'claude-project';
|
|
187
193
|
this.agentsWorkspaceFileName = '';
|
|
188
|
-
this.
|
|
189
|
-
|
|
194
|
+
this.projectClaudeMdPath = projectPath;
|
|
195
|
+
if (projectPath) {
|
|
196
|
+
this.agentsModalTitle = tr('modal.agents.title.claudeProject', 'Project CLAUDE.md: ' + projectPath, { path: projectPath });
|
|
197
|
+
this.agentsModalHint = tr('modal.agents.hint.claudeProject', 'Saved content will be written to CLAUDE.md in: ' + projectPath, { path: projectPath });
|
|
198
|
+
} else {
|
|
199
|
+
this.agentsModalTitle = tr('modal.agents.title.claudeProjectGlobal', 'Global CLAUDE.md');
|
|
200
|
+
this.agentsModalHint = tr('modal.agents.hint.claudeProjectGlobal', 'Saved content will be written to ~/.claude/CLAUDE.md.');
|
|
201
|
+
}
|
|
190
202
|
return;
|
|
191
203
|
}
|
|
192
204
|
if (context === 'openclaw-workspace') {
|
|
@@ -420,6 +432,41 @@ export function createAgentsMethods(options = {}) {
|
|
|
420
432
|
this.resetAgentsDiffState();
|
|
421
433
|
}
|
|
422
434
|
},
|
|
435
|
+
selectProjectClaudeMdPath(pathValue) {
|
|
436
|
+
this.projectClaudeMdPath = (pathValue || '').trim();
|
|
437
|
+
if (this.promptsSubTab === 'claude-project' && this.mainTab === 'prompts') {
|
|
438
|
+
this.loadPromptsContent();
|
|
439
|
+
}
|
|
440
|
+
},
|
|
441
|
+
setProjectClaudeMdPathManual(pathValue) {
|
|
442
|
+
var trimmed = (pathValue || '').trim();
|
|
443
|
+
if (trimmed === (this.projectClaudeMdPath || '').trim()) {
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
this.projectClaudeMdPath = trimmed;
|
|
447
|
+
if (this.promptsSubTab === 'claude-project' && this.mainTab === 'prompts') {
|
|
448
|
+
this.loadPromptsContent();
|
|
449
|
+
}
|
|
450
|
+
},
|
|
451
|
+
async loadProjectPathOptions() {
|
|
452
|
+
if (this.projectPathOptionsLoading) {
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
this.projectPathOptionsLoading = true;
|
|
456
|
+
try {
|
|
457
|
+
const res = await api('list-session-paths', { source: 'claude', limit: 100 });
|
|
458
|
+
if (res && Array.isArray(res.paths)) {
|
|
459
|
+
this.projectPathOptions = res.paths
|
|
460
|
+
.map(function (p) { return (p && p.cwd) || p || ''; })
|
|
461
|
+
.filter(Boolean)
|
|
462
|
+
.filter(function (v, i, a) { return a.indexOf(v) === i; });
|
|
463
|
+
}
|
|
464
|
+
} catch (_) {
|
|
465
|
+
// silent
|
|
466
|
+
} finally {
|
|
467
|
+
this.projectPathOptionsLoading = false;
|
|
468
|
+
}
|
|
469
|
+
},
|
|
423
470
|
async pasteAgentsContent() {
|
|
424
471
|
if (this.agentsLoading || this.agentsSaving || this.agentsDiffVisible) {
|
|
425
472
|
return;
|
|
@@ -444,10 +491,11 @@ export function createAgentsMethods(options = {}) {
|
|
|
444
491
|
const fileName = context === 'openclaw-workspace'
|
|
445
492
|
? (this.agentsWorkspaceFileName || '')
|
|
446
493
|
: '';
|
|
494
|
+
const projectPath = context === 'claude-project' ? (this.projectClaudeMdPath || '') : '';
|
|
447
495
|
const lineEnding = this.agentsLineEnding || '\n';
|
|
448
496
|
const content = typeof this.agentsContent === 'string' ? this.agentsContent : '';
|
|
449
497
|
const original = typeof this.agentsOriginalContent === 'string' ? this.agentsOriginalContent : '';
|
|
450
|
-
return `${context}::${fileName}::${lineEnding}::${content.length}::${content}::${original.length}::${original}`;
|
|
498
|
+
return `${context}::${fileName}::${projectPath}::${lineEnding}::${content.length}::${content}::${original.length}::${original}`;
|
|
451
499
|
},
|
|
452
500
|
async prepareAgentsDiff() {
|
|
453
501
|
const requestFingerprint = this.buildAgentsDiffFingerprint();
|
|
@@ -504,7 +552,8 @@ export function createAgentsMethods(options = {}) {
|
|
|
504
552
|
content: this.agentsContent,
|
|
505
553
|
lineEnding: this.agentsLineEnding,
|
|
506
554
|
context: this.agentsContext,
|
|
507
|
-
fileName: this.agentsWorkspaceFileName
|
|
555
|
+
fileName: this.agentsWorkspaceFileName,
|
|
556
|
+
baseDir: this.agentsContext === 'claude-project' ? this.projectClaudeMdPath : undefined
|
|
508
557
|
});
|
|
509
558
|
if (previewRequest.exceedsBodyLimit) {
|
|
510
559
|
applyPreviewState(buildAgentsDiffPreview({
|
|
@@ -621,8 +670,12 @@ export function createAgentsMethods(options = {}) {
|
|
|
621
670
|
content: this.agentsContent,
|
|
622
671
|
lineEnding: this.agentsLineEnding
|
|
623
672
|
};
|
|
624
|
-
if (this.agentsContext === 'claude-
|
|
673
|
+
if (this.agentsContext === 'claude-project') {
|
|
625
674
|
action = 'apply-claude-md-file';
|
|
675
|
+
const projectPath = (this.projectClaudeMdPath || '').trim();
|
|
676
|
+
if (projectPath) {
|
|
677
|
+
params.baseDir = projectPath;
|
|
678
|
+
}
|
|
626
679
|
} else if (this.agentsContext === 'openclaw') {
|
|
627
680
|
action = 'apply-openclaw-agents-file';
|
|
628
681
|
} else if (this.agentsContext === 'openclaw-workspace') {
|
|
@@ -636,8 +689,8 @@ export function createAgentsMethods(options = {}) {
|
|
|
636
689
|
}
|
|
637
690
|
const successLabel = this.agentsContext === 'openclaw-workspace'
|
|
638
691
|
? this.t('toast.agents.saved.workspace', { name: this.agentsWorkspaceFileName || '' }).replace(/:\s*$/, '')
|
|
639
|
-
: (this.agentsContext === 'claude-
|
|
640
|
-
? this.t('toast.agents.saved.
|
|
692
|
+
: (this.agentsContext === 'claude-project'
|
|
693
|
+
? this.t('toast.agents.saved.claudeProject')
|
|
641
694
|
: (this.agentsContext === 'openclaw' ? this.t('toast.agents.saved.openclaw') : this.t('toast.agents.saved.agents')));
|
|
642
695
|
this.showMessage(successLabel, 'success');
|
|
643
696
|
if (this.mainTab === 'prompts') {
|
|
@@ -653,7 +706,10 @@ export function createAgentsMethods(options = {}) {
|
|
|
653
706
|
},
|
|
654
707
|
|
|
655
708
|
switchPromptsSubTab(subTab) {
|
|
656
|
-
const normalized = subTab === 'claude-
|
|
709
|
+
const normalized = subTab === 'claude-project' ? 'claude-project' : 'codex';
|
|
710
|
+
if (normalized === 'claude-project' && !this.projectPathOptions.length && !this.projectPathOptionsLoading) {
|
|
711
|
+
this.loadProjectPathOptions();
|
|
712
|
+
}
|
|
657
713
|
if (this.promptsSubTab === normalized) {
|
|
658
714
|
this.loadPromptsContent();
|
|
659
715
|
return;
|
|
@@ -666,9 +722,19 @@ export function createAgentsMethods(options = {}) {
|
|
|
666
722
|
this.agentsLoading = true;
|
|
667
723
|
this.resetAgentsDiffState();
|
|
668
724
|
try {
|
|
669
|
-
const
|
|
670
|
-
|
|
671
|
-
const
|
|
725
|
+
const subTab = this.promptsSubTab;
|
|
726
|
+
let action;
|
|
727
|
+
const rpcParams = {};
|
|
728
|
+
if (subTab === 'claude-project') {
|
|
729
|
+
action = 'get-claude-md-file';
|
|
730
|
+
const projectPath = (this.projectClaudeMdPath || '').trim();
|
|
731
|
+
if (projectPath) {
|
|
732
|
+
rpcParams.baseDir = projectPath;
|
|
733
|
+
}
|
|
734
|
+
} else {
|
|
735
|
+
action = 'get-agents-file';
|
|
736
|
+
}
|
|
737
|
+
const res = await api(action, rpcParams);
|
|
672
738
|
if (!isLatestRequestToken(this, '_agentsOpenRequestToken', requestToken)) {
|
|
673
739
|
return;
|
|
674
740
|
}
|
|
@@ -681,7 +747,7 @@ export function createAgentsMethods(options = {}) {
|
|
|
681
747
|
this.agentsPath = res.path || '';
|
|
682
748
|
this.agentsExists = !!res.exists;
|
|
683
749
|
this.agentsLineEnding = res.lineEnding === '\r\n' ? '\r\n' : '\n';
|
|
684
|
-
this.agentsContext =
|
|
750
|
+
this.agentsContext = subTab === 'claude-project' ? 'claude-project' : 'codex';
|
|
685
751
|
} catch (e) {
|
|
686
752
|
if (!isLatestRequestToken(this, '_agentsOpenRequestToken', requestToken)) {
|
|
687
753
|
return;
|
|
@@ -220,7 +220,11 @@ const en = Object.freeze({
|
|
|
220
220
|
'subtitle.settings': 'Manage downloads, directories, and trash.',
|
|
221
221
|
'subtitle.prompts': 'Edit AGENTS.md and CLAUDE.md.',
|
|
222
222
|
'prompts.subTab.codex': 'AGENTS.md (Codex)',
|
|
223
|
-
'prompts.subTab.
|
|
223
|
+
'prompts.subTab.project': 'CLAUDE.md',
|
|
224
|
+
'prompts.project.pathLabel': 'Project path (optional)',
|
|
225
|
+
'prompts.project.selectPlaceholder': '-- Global (~/.claude/CLAUDE.md) --',
|
|
226
|
+
'prompts.project.manualPlaceholder': 'Or enter a project root path...',
|
|
227
|
+
'prompts.project.detected': 'Editing CLAUDE.md in: {path}',
|
|
224
228
|
'dashboard.doctor.title': 'Doctor',
|
|
225
229
|
'dashboard.doctor.runChecks': 'Run checks',
|
|
226
230
|
'dashboard.doctor.checking': 'Checking...',
|
|
@@ -401,7 +405,7 @@ const en = Object.freeze({
|
|
|
401
405
|
'toast.save.ok': 'Saved',
|
|
402
406
|
'toast.save.fail': 'Save failed',
|
|
403
407
|
'toast.agents.saved.agents': 'AGENTS.md saved',
|
|
404
|
-
'toast.agents.saved.
|
|
408
|
+
'toast.agents.saved.claudeProject': 'Project CLAUDE.md saved',
|
|
405
409
|
'toast.agents.saved.openclaw': 'OpenClaw AGENTS.md saved',
|
|
406
410
|
'toast.agents.saved.workspace': 'Workspace file saved: {name}',
|
|
407
411
|
'toast.delete.ok': 'Deleted',
|
|
@@ -872,12 +876,14 @@ const en = Object.freeze({
|
|
|
872
876
|
'config.autoCompact.hint': 'Auto-compaction threshold (default 185000).',
|
|
873
877
|
'config.agents.open': 'Open AGENTS.md',
|
|
874
878
|
'modal.agents.title.default': 'AGENTS.md editor',
|
|
875
|
-
'modal.agents.title.claudeMd': 'CLAUDE.md editor',
|
|
876
879
|
'modal.agents.title.openclaw': 'OpenClaw AGENTS.md editor',
|
|
877
880
|
'modal.agents.hint.default': 'Saved content will be written to AGENTS.md (next to config.toml).',
|
|
878
|
-
'modal.agents.
|
|
879
|
-
'modal.agents.
|
|
880
|
-
'modal.agents.
|
|
881
|
+
'modal.agents.title.claudeProject': 'Project CLAUDE.md: {path}',
|
|
882
|
+
'modal.agents.hint.claudeProject': 'Saved content will be written to CLAUDE.md in: {path}',
|
|
883
|
+
'modal.agents.title.claudeProjectGlobal': 'Global CLAUDE.md',
|
|
884
|
+
'modal.agents.hint.claudeProjectGlobal': 'Saved content will be written to ~/.claude/CLAUDE.md.',
|
|
885
|
+
'modal.agents.contentLabel.claudeProject': 'CLAUDE.md content',
|
|
886
|
+
'modal.agents.placeholder.claudeProject': 'Edit CLAUDE.md here',
|
|
881
887
|
'modal.agents.hint.openclaw': 'Saved content will be written to OpenClaw workspace AGENTS.md.',
|
|
882
888
|
'modal.agents.title.openclawWorkspaceFile': 'OpenClaw workspace file: {fileName}',
|
|
883
889
|
'modal.agents.hint.openclawWorkspaceFile': 'Saved content will be written to OpenClaw workspace {fileName}.',
|
|
@@ -221,7 +221,11 @@ const ja = Object.freeze({
|
|
|
221
221
|
'subtitle.settings': 'ダウンロード・ディレクトリ・ゴミ箱の管理。',
|
|
222
222
|
'subtitle.prompts': 'AGENTS.md と CLAUDE.md を編集。',
|
|
223
223
|
'prompts.subTab.codex': 'AGENTS.md (Codex)',
|
|
224
|
-
'prompts.subTab.
|
|
224
|
+
'prompts.subTab.project': 'CLAUDE.md',
|
|
225
|
+
'prompts.project.pathLabel': 'プロジェクトパス(任意)',
|
|
226
|
+
'prompts.project.selectPlaceholder': '-- グローバル (~/.claude/CLAUDE.md) --',
|
|
227
|
+
'prompts.project.manualPlaceholder': 'またはプロジェクトルートパスを入力...',
|
|
228
|
+
'prompts.project.detected': '編集中: {path}',
|
|
225
229
|
|
|
226
230
|
'dashboard.doctor.title': 'Doctor',
|
|
227
231
|
'dashboard.doctor.runChecks': 'チェックを実行',
|
|
@@ -403,7 +407,7 @@ const ja = Object.freeze({
|
|
|
403
407
|
'toast.save.ok': '保存しました',
|
|
404
408
|
'toast.save.fail': '保存に失敗しました',
|
|
405
409
|
'toast.agents.saved.agents': 'AGENTS.md 保存しました',
|
|
406
|
-
'toast.agents.saved.
|
|
410
|
+
'toast.agents.saved.claudeProject': 'プロジェクト CLAUDE.md 保存しました',
|
|
407
411
|
'toast.agents.saved.openclaw': 'OpenClaw AGENTS.md 保存しました',
|
|
408
412
|
'toast.agents.saved.workspace': 'ワークスペースファイル保存済み: {name}',
|
|
409
413
|
'toast.delete.ok': '削除しました',
|
|
@@ -861,12 +865,14 @@ const ja = Object.freeze({
|
|
|
861
865
|
'config.autoCompact.hint': '自動圧縮閾値、デフォルト 185000。',
|
|
862
866
|
'config.agents.open': 'AGENTS.md を開く',
|
|
863
867
|
'modal.agents.title.default': 'AGENTS.md エディタ',
|
|
864
|
-
'modal.agents.title.claudeMd': 'CLAUDE.md エディタ',
|
|
865
868
|
'modal.agents.title.openclaw': 'OpenClaw AGENTS.md エディタ',
|
|
866
869
|
'modal.agents.hint.default': '保存すると対象の AGENTS.md(config.toml と同階層)に書き込まれます。',
|
|
867
|
-
'modal.agents.
|
|
868
|
-
'modal.agents.
|
|
869
|
-
'modal.agents.
|
|
870
|
+
'modal.agents.title.claudeProject': 'プロジェクト CLAUDE.md: {path}',
|
|
871
|
+
'modal.agents.hint.claudeProject': '保存するとプロジェクトの CLAUDE.md に書き込まれます: {path}',
|
|
872
|
+
'modal.agents.title.claudeProjectGlobal': 'グローバル CLAUDE.md',
|
|
873
|
+
'modal.agents.hint.claudeProjectGlobal': '保存すると ~/.claude/CLAUDE.md に書き込まれます。',
|
|
874
|
+
'modal.agents.contentLabel.claudeProject': 'CLAUDE.md 内容',
|
|
875
|
+
'modal.agents.placeholder.claudeProject': 'CLAUDE.md を編集',
|
|
870
876
|
'modal.agents.hint.openclaw': '保存すると OpenClaw Workspace の AGENTS.md に書き込まれます。',
|
|
871
877
|
'modal.agents.title.openclawWorkspaceFile': 'OpenClaw ワークスペースファイル: {fileName}',
|
|
872
878
|
'modal.agents.hint.openclawWorkspaceFile': '保存すると OpenClaw Workspace の {fileName} に書き込まれます。',
|
|
@@ -234,7 +234,11 @@ const vi = Object.freeze({
|
|
|
234
234
|
'subtitle.settings': 'Quản lý tải xuống, thư mục và dữ liệu.',
|
|
235
235
|
'subtitle.prompts': 'Chỉnh sửa AGENTS.md và CLAUDE.md.',
|
|
236
236
|
'prompts.subTab.codex': 'AGENTS.md (Codex)',
|
|
237
|
-
'prompts.subTab.
|
|
237
|
+
'prompts.subTab.project': 'CLAUDE.md',
|
|
238
|
+
'prompts.project.pathLabel': 'Đường dẫn dự án (tùy chọn)',
|
|
239
|
+
'prompts.project.selectPlaceholder': '-- Toàn cục (~/.claude/CLAUDE.md) --',
|
|
240
|
+
'prompts.project.manualPlaceholder': 'Hoặc nhập đường dẫn gốc dự án...',
|
|
241
|
+
'prompts.project.detected': 'Đang chỉnh sửa CLAUDE.md trong: {path}',
|
|
238
242
|
|
|
239
243
|
|
|
240
244
|
// Task orchestration readiness
|
|
@@ -317,7 +321,7 @@ const vi = Object.freeze({
|
|
|
317
321
|
'toast.save.ok': 'Đã lưu',
|
|
318
322
|
'toast.save.fail': 'Lưu thất bại',
|
|
319
323
|
'toast.agents.saved.agents': 'AGENTS.md đã lưu',
|
|
320
|
-
'toast.agents.saved.
|
|
324
|
+
'toast.agents.saved.claudeProject': 'CLAUDE.md dự án đã lưu',
|
|
321
325
|
'toast.agents.saved.openclaw': 'OpenClaw AGENTS.md đã lưu',
|
|
322
326
|
'toast.agents.saved.workspace': 'Tệp workspace đã lưu: {name}',
|
|
323
327
|
'toast.delete.ok': 'Đã xóa',
|
|
@@ -385,6 +389,12 @@ const vi = Object.freeze({
|
|
|
385
389
|
'diff.hint.previewMode': 'Đang xem trước. Nhấp "Lưu" để ghi hoặc "Quay lại chỉnh sửa" để tiếp tục.',
|
|
386
390
|
'modal.agents.unsaved.detectedHint': 'Phát hiện thay đổi chưa lưu: lưu trước khi đóng hoặc áp dụng.',
|
|
387
391
|
'modal.agents.hint.twoStepSave': 'Lưu hai bước: "Xem trước" để kiểm tra diff, rồi "Lưu" để ghi.',
|
|
392
|
+
'modal.agents.title.claudeProject': 'CLAUDE.md dự án: {path}',
|
|
393
|
+
'modal.agents.hint.claudeProject': 'Nội dung sẽ được ghi vào CLAUDE.md trong dự án: {path}',
|
|
394
|
+
'modal.agents.title.claudeProjectGlobal': 'CLAUDE.md toàn cục',
|
|
395
|
+
'modal.agents.hint.claudeProjectGlobal': 'Nội dung sẽ được ghi vào ~/.claude/CLAUDE.md.',
|
|
396
|
+
'modal.agents.contentLabel.claudeProject': 'Nội dung CLAUDE.md',
|
|
397
|
+
'modal.agents.placeholder.claudeProject': 'Chỉnh sửa CLAUDE.md tại đây',
|
|
388
398
|
'diff.viewHint.preview': 'Đang xem trước. Nhấp "Lưu" để ghi hoặc "Quay lại chỉnh sửa" để tiếp tục.',
|
|
389
399
|
'diff.viewHint.truncated': 'Bỏ qua xem trước do nội dung quá lớn. Nhấp "Lưu" để ghi hoặc "Quay lại chỉnh sửa" để tiếp tục.',
|
|
390
400
|
});
|
|
@@ -220,7 +220,11 @@ const zhTw = Object.freeze({
|
|
|
220
220
|
'subtitle.settings': '管理下載、目錄與回收站。',
|
|
221
221
|
'subtitle.prompts': '編輯 AGENTS.md 與 CLAUDE.md。',
|
|
222
222
|
'prompts.subTab.codex': 'AGENTS.md (Codex)',
|
|
223
|
-
'prompts.subTab.
|
|
223
|
+
'prompts.subTab.project': 'CLAUDE.md',
|
|
224
|
+
'prompts.project.pathLabel': '專案路徑(可選)',
|
|
225
|
+
'prompts.project.selectPlaceholder': '-- 全域 (~/.claude/CLAUDE.md) --',
|
|
226
|
+
'prompts.project.manualPlaceholder': '或手動輸入專案根路徑...',
|
|
227
|
+
'prompts.project.detected': '正在編輯: {path}',
|
|
224
228
|
'dashboard.doctor.title': 'Doctor',
|
|
225
229
|
'dashboard.doctor.runChecks': '運行檢查',
|
|
226
230
|
'dashboard.doctor.checking': '檢查中...',
|
|
@@ -401,7 +405,7 @@ const zhTw = Object.freeze({
|
|
|
401
405
|
'toast.save.ok': '已保存',
|
|
402
406
|
'toast.save.fail': '保存失敗',
|
|
403
407
|
'toast.agents.saved.agents': 'AGENTS.md 已保存',
|
|
404
|
-
'toast.agents.saved.
|
|
408
|
+
'toast.agents.saved.claudeProject': '專案 CLAUDE.md 已保存',
|
|
405
409
|
'toast.agents.saved.openclaw': 'OpenClaw AGENTS.md 已保存',
|
|
406
410
|
'toast.agents.saved.workspace': '工作區文件已保存: {name}',
|
|
407
411
|
'toast.delete.ok': '已刪除',
|
|
@@ -871,12 +875,14 @@ const zhTw = Object.freeze({
|
|
|
871
875
|
'config.autoCompact.hint': '自動壓縮閾值,預設 185000。',
|
|
872
876
|
'config.agents.open': '打開 AGENTS.md',
|
|
873
877
|
'modal.agents.title.default': 'AGENTS.md 編輯器',
|
|
874
|
-
'modal.agents.title.claudeMd': 'CLAUDE.md 編輯器',
|
|
875
878
|
'modal.agents.title.openclaw': 'OpenClaw AGENTS.md 編輯器',
|
|
876
879
|
'modal.agents.hint.default': '保存後會寫入目標 AGENTS.md(與 config.toml 同級)。',
|
|
877
|
-
'modal.agents.
|
|
878
|
-
'modal.agents.
|
|
879
|
-
'modal.agents.
|
|
880
|
+
'modal.agents.title.claudeProject': '專案 CLAUDE.md: {path}',
|
|
881
|
+
'modal.agents.hint.claudeProject': '保存後會寫入專案目錄下的 CLAUDE.md: {path}',
|
|
882
|
+
'modal.agents.title.claudeProjectGlobal': '全域 CLAUDE.md',
|
|
883
|
+
'modal.agents.hint.claudeProjectGlobal': '保存後會寫入 ~/.claude/CLAUDE.md。',
|
|
884
|
+
'modal.agents.contentLabel.claudeProject': 'CLAUDE.md 內容',
|
|
885
|
+
'modal.agents.placeholder.claudeProject': '在這裡編輯 CLAUDE.md',
|
|
880
886
|
'modal.agents.hint.openclaw': '保存後會寫入 OpenClaw Workspace 下的 AGENTS.md。',
|
|
881
887
|
'modal.agents.title.openclawWorkspaceFile': 'OpenClaw 工作區文件: {fileName}',
|
|
882
888
|
'modal.agents.hint.openclawWorkspaceFile': '保存後會寫入 OpenClaw Workspace 下的 {fileName}。',
|
|
@@ -220,7 +220,11 @@ const zh = Object.freeze({
|
|
|
220
220
|
'subtitle.settings': '管理下载、目录与回收站。',
|
|
221
221
|
'subtitle.prompts': '编辑 AGENTS.md 与 CLAUDE.md。',
|
|
222
222
|
'prompts.subTab.codex': 'AGENTS.md (Codex)',
|
|
223
|
-
'prompts.subTab.
|
|
223
|
+
'prompts.subTab.project': 'CLAUDE.md',
|
|
224
|
+
'prompts.project.pathLabel': '项目路径(可选)',
|
|
225
|
+
'prompts.project.selectPlaceholder': '-- 全局 (~/.claude/CLAUDE.md) --',
|
|
226
|
+
'prompts.project.manualPlaceholder': '或手动输入项目根路径...',
|
|
227
|
+
'prompts.project.detected': '正在编辑: {path}',
|
|
224
228
|
'dashboard.doctor.title': 'Doctor',
|
|
225
229
|
'dashboard.doctor.runChecks': '运行检查',
|
|
226
230
|
'dashboard.doctor.checking': '检查中...',
|
|
@@ -401,7 +405,7 @@ const zh = Object.freeze({
|
|
|
401
405
|
'toast.save.ok': '已保存',
|
|
402
406
|
'toast.save.fail': '保存失败',
|
|
403
407
|
'toast.agents.saved.agents': 'AGENTS.md 已保存',
|
|
404
|
-
'toast.agents.saved.
|
|
408
|
+
'toast.agents.saved.claudeProject': '项目 CLAUDE.md 已保存',
|
|
405
409
|
'toast.agents.saved.openclaw': 'OpenClaw AGENTS.md 已保存',
|
|
406
410
|
'toast.agents.saved.workspace': '工作区文件已保存: {name}',
|
|
407
411
|
'toast.delete.ok': '已删除',
|
|
@@ -871,12 +875,14 @@ const zh = Object.freeze({
|
|
|
871
875
|
'config.autoCompact.hint': '自动压缩阈值,默认 185000。',
|
|
872
876
|
'config.agents.open': '打开 AGENTS.md',
|
|
873
877
|
'modal.agents.title.default': 'AGENTS.md 编辑器',
|
|
874
|
-
'modal.agents.title.claudeMd': 'CLAUDE.md 编辑器',
|
|
875
878
|
'modal.agents.title.openclaw': 'OpenClaw AGENTS.md 编辑器',
|
|
876
879
|
'modal.agents.hint.default': '保存后会写入目标 AGENTS.md(与 config.toml 同级)。',
|
|
877
|
-
'modal.agents.
|
|
878
|
-
'modal.agents.
|
|
879
|
-
'modal.agents.
|
|
880
|
+
'modal.agents.title.claudeProject': '项目 CLAUDE.md: {path}',
|
|
881
|
+
'modal.agents.hint.claudeProject': '保存后会写入项目目录下的 CLAUDE.md: {path}',
|
|
882
|
+
'modal.agents.title.claudeProjectGlobal': '全局 CLAUDE.md',
|
|
883
|
+
'modal.agents.hint.claudeProjectGlobal': '保存后会写入 ~/.claude/CLAUDE.md。',
|
|
884
|
+
'modal.agents.contentLabel.claudeProject': 'CLAUDE.md 内容',
|
|
885
|
+
'modal.agents.placeholder.claudeProject': '在这里编辑 CLAUDE.md',
|
|
880
886
|
'modal.agents.hint.openclaw': '保存后会写入 OpenClaw Workspace 下的 AGENTS.md。',
|
|
881
887
|
'modal.agents.title.openclawWorkspaceFile': 'OpenClaw 工作区文件: {fileName}',
|
|
882
888
|
'modal.agents.hint.openclawWorkspaceFile': '保存后会写入 OpenClaw Workspace 下的 {fileName}。',
|
|
@@ -255,13 +255,13 @@
|
|
|
255
255
|
</div>
|
|
256
256
|
</button>
|
|
257
257
|
<button
|
|
258
|
-
id="side-tab-prompts-
|
|
258
|
+
id="side-tab-prompts-project"
|
|
259
259
|
data-main-tab="prompts"
|
|
260
|
-
data-prompts-sub-tab="claude-
|
|
261
|
-
:aria-current="mainTab === 'prompts' && promptsSubTab === 'claude-
|
|
262
|
-
:class="['side-item', { active: isMainTabNavActive('prompts') && promptsSubTab === 'claude-
|
|
260
|
+
data-prompts-sub-tab="claude-project"
|
|
261
|
+
:aria-current="mainTab === 'prompts' && promptsSubTab === 'claude-project' ? 'page' : null"
|
|
262
|
+
:class="['side-item', { active: isMainTabNavActive('prompts') && promptsSubTab === 'claude-project' }]"
|
|
263
263
|
@pointerdown="onMainTabPointerDown('prompts', $event)"
|
|
264
|
-
@click="switchPromptsSubTab('claude-
|
|
264
|
+
@click="switchPromptsSubTab('claude-project'); onMainTabClick('prompts')">
|
|
265
265
|
<div class="side-item-title">{{ t('side.prompts.claude') }}</div>
|
|
266
266
|
<div class="side-item-meta">
|
|
267
267
|
<span>{{ t('side.prompts.claude.meta') }}</span>
|
|
@@ -130,7 +130,7 @@
|
|
|
130
130
|
|
|
131
131
|
|
|
132
132
|
<div class="form-group">
|
|
133
|
-
<label class="form-label">{{ t(agentsContext === 'claude-
|
|
133
|
+
<label class="form-label">{{ t(agentsContext === 'claude-project' ? 'modal.agents.contentLabel.claudeProject' : 'modal.agents.contentLabel') }}</label>
|
|
134
134
|
<div
|
|
135
135
|
v-if="!agentsLoading && (hasAgentsContentChanged() || agentsDiffVisible)"
|
|
136
136
|
class="agents-diff-save-alert">
|
|
@@ -165,7 +165,7 @@
|
|
|
165
165
|
spellcheck="false"
|
|
166
166
|
:readonly="agentsLoading || agentsSaving || agentsDiffVisible"
|
|
167
167
|
@input="onAgentsContentInput"
|
|
168
|
-
:placeholder="t(agentsContext === 'claude-
|
|
168
|
+
:placeholder="t(agentsContext === 'claude-project' ? 'modal.agents.placeholder.claudeProject' : 'modal.agents.placeholder')"></textarea>
|
|
169
169
|
<div class="template-editor-warning">
|
|
170
170
|
{{ agentsModalHint }}
|
|
171
171
|
<div class="agents-diff-hint">{{ t('modal.agents.hint.shortcuts') }}</div>
|
|
@@ -7,7 +7,29 @@
|
|
|
7
7
|
aria-labelledby="tab-prompts">
|
|
8
8
|
<div class="segmented-control">
|
|
9
9
|
<button type="button" :class="['segment', { active: promptsSubTab === 'codex' }]" @click="switchPromptsSubTab('codex')">{{ t('prompts.subTab.codex') }}</button>
|
|
10
|
-
<button type="button" :class="['segment', { active: promptsSubTab === 'claude-
|
|
10
|
+
<button type="button" :class="['segment', { active: promptsSubTab === 'claude-project' }]" @click="switchPromptsSubTab('claude-project')">{{ t('prompts.subTab.project') }}</button>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<div v-if="promptsSubTab === 'claude-project'" class="project-path-selector">
|
|
14
|
+
<label class="project-path-label">{{ t('prompts.project.pathLabel') }}</label>
|
|
15
|
+
<div class="project-path-row">
|
|
16
|
+
<select
|
|
17
|
+
class="form-input project-path-select"
|
|
18
|
+
:value="projectClaudeMdPath"
|
|
19
|
+
@change="selectProjectClaudeMdPath($event.target.value)">
|
|
20
|
+
<option value="">{{ t('prompts.project.selectPlaceholder') }}</option>
|
|
21
|
+
<option v-for="p in projectPathOptions" :key="p" :value="p">{{ p }}</option>
|
|
22
|
+
</select>
|
|
23
|
+
<input
|
|
24
|
+
type="text"
|
|
25
|
+
class="form-input project-path-manual"
|
|
26
|
+
:placeholder="t('prompts.project.manualPlaceholder')"
|
|
27
|
+
:value="projectClaudeMdPath"
|
|
28
|
+
@change="setProjectClaudeMdPathManual($event.target.value)">
|
|
29
|
+
</div>
|
|
30
|
+
<div v-if="projectClaudeMdPath" class="form-hint project-path-detected">
|
|
31
|
+
{{ t('prompts.project.detected', { path: projectClaudeMdPath }) }}
|
|
32
|
+
</div>
|
|
11
33
|
</div>
|
|
12
34
|
|
|
13
35
|
<div class="prompts-editor">
|
|
@@ -89,7 +111,7 @@
|
|
|
89
111
|
spellcheck="false"
|
|
90
112
|
:readonly="agentsLoading || agentsSaving || agentsDiffVisible"
|
|
91
113
|
@input="onAgentsContentInput"
|
|
92
|
-
:placeholder="t(promptsSubTab === 'claude-
|
|
114
|
+
:placeholder="t(promptsSubTab === 'claude-project' ? 'modal.agents.placeholder.claudeProject' : 'modal.agents.placeholder')"></textarea>
|
|
93
115
|
</div>
|
|
94
116
|
<div v-if="promptsContextHint" :class="['prompts-context-hint', { 'prompts-context-hint--warn': promptsContextHint.warn }]">
|
|
95
117
|
{{ promptsContextHint.text }}
|
|
@@ -351,13 +351,13 @@ return function render(_ctx, _cache) {
|
|
|
351
351
|
])
|
|
352
352
|
], 42 /* CLASS, PROPS, NEED_HYDRATION */, ["aria-current", "onPointerdown", "onClick"]),
|
|
353
353
|
_createElementVNode("button", {
|
|
354
|
-
id: "side-tab-prompts-
|
|
354
|
+
id: "side-tab-prompts-project",
|
|
355
355
|
"data-main-tab": "prompts",
|
|
356
|
-
"data-prompts-sub-tab": "claude-
|
|
357
|
-
"aria-current": _ctx.mainTab === 'prompts' && _ctx.promptsSubTab === 'claude-
|
|
358
|
-
class: _normalizeClass(['side-item', { active: _ctx.isMainTabNavActive('prompts') && _ctx.promptsSubTab === 'claude-
|
|
356
|
+
"data-prompts-sub-tab": "claude-project",
|
|
357
|
+
"aria-current": _ctx.mainTab === 'prompts' && _ctx.promptsSubTab === 'claude-project' ? 'page' : null,
|
|
358
|
+
class: _normalizeClass(['side-item', { active: _ctx.isMainTabNavActive('prompts') && _ctx.promptsSubTab === 'claude-project' }]),
|
|
359
359
|
onPointerdown: $event => (_ctx.onMainTabPointerDown('prompts', $event)),
|
|
360
|
-
onClick: $event => {_ctx.switchPromptsSubTab('claude-
|
|
360
|
+
onClick: $event => {_ctx.switchPromptsSubTab('claude-project'); _ctx.onMainTabClick('prompts')}
|
|
361
361
|
}, [
|
|
362
362
|
_createElementVNode("div", { class: "side-item-title" }, _toDisplayString(_ctx.t('side.prompts.claude')), 1 /* TEXT */),
|
|
363
363
|
_createElementVNode("div", { class: "side-item-meta" }, [
|
|
@@ -5977,10 +5977,46 @@ return function render(_ctx, _cache) {
|
|
|
5977
5977
|
}, _toDisplayString(_ctx.t('prompts.subTab.codex')), 11 /* TEXT, CLASS, PROPS */, ["onClick"]),
|
|
5978
5978
|
_createElementVNode("button", {
|
|
5979
5979
|
type: "button",
|
|
5980
|
-
class: _normalizeClass(['segment', { active: _ctx.promptsSubTab === 'claude-
|
|
5981
|
-
onClick: $event => (_ctx.switchPromptsSubTab('claude-
|
|
5982
|
-
}, _toDisplayString(_ctx.t('prompts.subTab.
|
|
5980
|
+
class: _normalizeClass(['segment', { active: _ctx.promptsSubTab === 'claude-project' }]),
|
|
5981
|
+
onClick: $event => (_ctx.switchPromptsSubTab('claude-project'))
|
|
5982
|
+
}, _toDisplayString(_ctx.t('prompts.subTab.project')), 11 /* TEXT, CLASS, PROPS */, ["onClick"])
|
|
5983
5983
|
]),
|
|
5984
|
+
(_ctx.promptsSubTab === 'claude-project')
|
|
5985
|
+
? (_openBlock(), _createElementBlock("div", {
|
|
5986
|
+
key: 0,
|
|
5987
|
+
class: "project-path-selector"
|
|
5988
|
+
}, [
|
|
5989
|
+
_createElementVNode("label", { class: "project-path-label" }, _toDisplayString(_ctx.t('prompts.project.pathLabel')), 1 /* TEXT */),
|
|
5990
|
+
_createElementVNode("div", { class: "project-path-row" }, [
|
|
5991
|
+
_createElementVNode("select", {
|
|
5992
|
+
class: "form-input project-path-select",
|
|
5993
|
+
value: _ctx.projectClaudeMdPath,
|
|
5994
|
+
onChange: $event => (_ctx.selectProjectClaudeMdPath($event.target.value))
|
|
5995
|
+
}, [
|
|
5996
|
+
_createElementVNode("option", { value: "" }, _toDisplayString(_ctx.t('prompts.project.selectPlaceholder')), 1 /* TEXT */),
|
|
5997
|
+
(_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.projectPathOptions, (p) => {
|
|
5998
|
+
return (_openBlock(), _createElementBlock("option", {
|
|
5999
|
+
key: p,
|
|
6000
|
+
value: p
|
|
6001
|
+
}, _toDisplayString(p), 9 /* TEXT, PROPS */, ["value"]))
|
|
6002
|
+
}), 128 /* KEYED_FRAGMENT */))
|
|
6003
|
+
], 40 /* PROPS, NEED_HYDRATION */, ["value", "onChange"]),
|
|
6004
|
+
_createElementVNode("input", {
|
|
6005
|
+
type: "text",
|
|
6006
|
+
class: "form-input project-path-manual",
|
|
6007
|
+
placeholder: _ctx.t('prompts.project.manualPlaceholder'),
|
|
6008
|
+
value: _ctx.projectClaudeMdPath,
|
|
6009
|
+
onChange: $event => (_ctx.setProjectClaudeMdPathManual($event.target.value))
|
|
6010
|
+
}, null, 40 /* PROPS, NEED_HYDRATION */, ["placeholder", "value", "onChange"])
|
|
6011
|
+
]),
|
|
6012
|
+
(_ctx.projectClaudeMdPath)
|
|
6013
|
+
? (_openBlock(), _createElementBlock("div", {
|
|
6014
|
+
key: 0,
|
|
6015
|
+
class: "form-hint project-path-detected"
|
|
6016
|
+
}, _toDisplayString(_ctx.t('prompts.project.detected', { path: _ctx.projectClaudeMdPath })), 1 /* TEXT */))
|
|
6017
|
+
: _createCommentVNode("v-if", true)
|
|
6018
|
+
]))
|
|
6019
|
+
: _createCommentVNode("v-if", true),
|
|
5984
6020
|
_createElementVNode("div", { class: "prompts-editor" }, [
|
|
5985
6021
|
_createElementVNode("div", { class: "prompts-editor-toolbar" }, [
|
|
5986
6022
|
_createElementVNode("div", { class: "form-hint" }, [
|
|
@@ -6099,7 +6135,7 @@ return function render(_ctx, _cache) {
|
|
|
6099
6135
|
spellcheck: "false",
|
|
6100
6136
|
readonly: _ctx.agentsLoading || _ctx.agentsSaving || _ctx.agentsDiffVisible,
|
|
6101
6137
|
onInput: _ctx.onAgentsContentInput,
|
|
6102
|
-
placeholder: _ctx.t(_ctx.promptsSubTab === 'claude-
|
|
6138
|
+
placeholder: _ctx.t(_ctx.promptsSubTab === 'claude-project' ? 'modal.agents.placeholder.claudeProject' : 'modal.agents.placeholder')
|
|
6103
6139
|
}, null, 40 /* PROPS, NEED_HYDRATION */, ["onUpdate:modelValue", "readonly", "onInput", "placeholder"]), [
|
|
6104
6140
|
[_vModelText, _ctx.agentsContent]
|
|
6105
6141
|
])
|
|
@@ -7970,7 +8006,7 @@ return function render(_ctx, _cache) {
|
|
|
7970
8006
|
])
|
|
7971
8007
|
]),
|
|
7972
8008
|
_createElementVNode("div", { class: "form-group" }, [
|
|
7973
|
-
_createElementVNode("label", { class: "form-label" }, _toDisplayString(_ctx.t(_ctx.agentsContext === 'claude-
|
|
8009
|
+
_createElementVNode("label", { class: "form-label" }, _toDisplayString(_ctx.t(_ctx.agentsContext === 'claude-project' ? 'modal.agents.contentLabel.claudeProject' : 'modal.agents.contentLabel')), 1 /* TEXT */),
|
|
7974
8010
|
(!_ctx.agentsLoading && (_ctx.hasAgentsContentChanged() || _ctx.agentsDiffVisible))
|
|
7975
8011
|
? (_openBlock(), _createElementBlock("div", {
|
|
7976
8012
|
key: 0,
|
|
@@ -8030,7 +8066,7 @@ return function render(_ctx, _cache) {
|
|
|
8030
8066
|
spellcheck: "false",
|
|
8031
8067
|
readonly: _ctx.agentsLoading || _ctx.agentsSaving || _ctx.agentsDiffVisible,
|
|
8032
8068
|
onInput: _ctx.onAgentsContentInput,
|
|
8033
|
-
placeholder: _ctx.t(_ctx.agentsContext === 'claude-
|
|
8069
|
+
placeholder: _ctx.t(_ctx.agentsContext === 'claude-project' ? 'modal.agents.placeholder.claudeProject' : 'modal.agents.placeholder')
|
|
8034
8070
|
}, null, 40 /* PROPS, NEED_HYDRATION */, ["onUpdate:modelValue", "readonly", "onInput", "placeholder"]), [
|
|
8035
8071
|
[_vModelText, _ctx.agentsContent]
|
|
8036
8072
|
]),
|
|
@@ -580,6 +580,39 @@
|
|
|
580
580
|
border-left: 1px solid var(--color-border-soft);
|
|
581
581
|
}
|
|
582
582
|
|
|
583
|
+
.project-path-selector {
|
|
584
|
+
margin-top: 8px;
|
|
585
|
+
margin-bottom: 4px;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
.project-path-label {
|
|
589
|
+
display: block;
|
|
590
|
+
font-size: 0.85em;
|
|
591
|
+
color: var(--color-text-secondary);
|
|
592
|
+
margin-bottom: 4px;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
.project-path-row {
|
|
596
|
+
display: flex;
|
|
597
|
+
gap: 8px;
|
|
598
|
+
align-items: center;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
.project-path-select {
|
|
602
|
+
flex: 1;
|
|
603
|
+
min-width: 0;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
.project-path-manual {
|
|
607
|
+
flex: 1;
|
|
608
|
+
min-width: 0;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
.project-path-detected {
|
|
612
|
+
margin-top: 4px;
|
|
613
|
+
font-size: 0.82em;
|
|
614
|
+
}
|
|
615
|
+
|
|
583
616
|
.editor-frame {
|
|
584
617
|
position: relative;
|
|
585
618
|
border-radius: var(--radius-md);
|
|
@@ -55,14 +55,14 @@
|
|
|
55
55
|
color: var(--color-text-secondary);
|
|
56
56
|
cursor: pointer;
|
|
57
57
|
border-radius: var(--radius-sm);
|
|
58
|
-
transition: color var(--transition-fast) var(--ease-smooth), background-color var(--transition-fast) var(--ease-smooth);
|
|
59
58
|
position: relative;
|
|
60
59
|
z-index: 2;
|
|
61
60
|
letter-spacing: 0;
|
|
62
61
|
}
|
|
63
62
|
|
|
64
|
-
.segment:hover {
|
|
63
|
+
.segment:not(.active):hover {
|
|
65
64
|
color: var(--color-text-primary);
|
|
65
|
+
transition: color var(--transition-fast) var(--ease-smooth), background-color var(--transition-fast) var(--ease-smooth);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
.segment.active {
|