codexmate 0.0.48 → 0.0.50

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.
@@ -37,11 +37,16 @@ export function createAgentsMethods(options = {}) {
37
37
 
38
38
  return {
39
39
  async openClaudeMdEditor() {
40
- this.setAgentsModalContext('claude-md');
40
+ this.setAgentsModalContext('claude-project');
41
41
  const requestToken = issueLatestRequestToken(this, '_agentsOpenRequestToken');
42
42
  this.agentsLoading = true;
43
43
  try {
44
- const res = await api('get-claude-md-file');
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-md') {
186
- this.agentsContext = 'claude-md';
190
+ if (context === 'claude-project') {
191
+ var projectPath = (options.projectPath || this.projectClaudeMdPath || '').trim();
192
+ this.agentsContext = 'claude-project';
187
193
  this.agentsWorkspaceFileName = '';
188
- this.agentsModalTitle = tr('modal.agents.title.claudeMd', 'CLAUDE.md 编辑器');
189
- this.agentsModalHint = tr('modal.agents.hint.claudeMd', '保存后会写入 ~/.claude/CLAUDE.md。');
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-md') {
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-md'
640
- ? this.t('toast.agents.saved.claudeMd')
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-md' ? 'claude-md' : 'codex';
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 isClaude = this.promptsSubTab === 'claude-md';
670
- const action = isClaude ? 'get-claude-md-file' : 'get-agents-file';
671
- const res = await api(action);
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 = isClaude ? 'claude-md' : 'codex';
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.claude': 'CLAUDE.md (Claude)',
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.claudeMd': 'CLAUDE.md 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.hint.claudeMd': 'Saved content will be written to ~/.claude/CLAUDE.md.',
879
- 'modal.agents.contentLabel.claudeMd': 'CLAUDE.md content',
880
- 'modal.agents.placeholder.claudeMd': 'Edit CLAUDE.md here',
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.claude': 'CLAUDE.md (Claude)',
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.claudeMd': 'CLAUDE.md 保存しました',
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.hint.claudeMd': '保存すると ~/.claude/CLAUDE.md に書き込まれます。',
868
- 'modal.agents.contentLabel.claudeMd': 'CLAUDE.md 内容',
869
- 'modal.agents.placeholder.claudeMd': 'ここに CLAUDE.md の内容を編集してください',
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.claude': 'CLAUDE.md (Claude)',
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.claudeMd': 'CLAUDE.md đã lưu',
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.claude': 'CLAUDE.md (Claude)',
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.claudeMd': 'CLAUDE.md 已保存',
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.hint.claudeMd': '保存後會寫入 ~/.claude/CLAUDE.md',
878
- 'modal.agents.contentLabel.claudeMd': 'CLAUDE.md 內容',
879
- 'modal.agents.placeholder.claudeMd': '在這裡編輯 CLAUDE.md 內容',
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.claude': 'CLAUDE.md (Claude)',
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.claudeMd': 'CLAUDE.md 已保存',
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.hint.claudeMd': '保存后会写入 ~/.claude/CLAUDE.md',
878
- 'modal.agents.contentLabel.claudeMd': 'CLAUDE.md 内容',
879
- 'modal.agents.placeholder.claudeMd': '在这里编辑 CLAUDE.md 内容',
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-claude"
258
+ id="side-tab-prompts-project"
259
259
  data-main-tab="prompts"
260
- data-prompts-sub-tab="claude-md"
261
- :aria-current="mainTab === 'prompts' && promptsSubTab === 'claude-md' ? 'page' : null"
262
- :class="['side-item', { active: isMainTabNavActive('prompts') && promptsSubTab === 'claude-md' }]"
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-md'); onMainTabClick('prompts')">
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-md' ? 'modal.agents.contentLabel.claudeMd' : 'modal.agents.contentLabel') }}</label>
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-md' ? 'modal.agents.placeholder.claudeMd' : 'modal.agents.placeholder')"></textarea>
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-md' }]" @click="switchPromptsSubTab('claude-md')">{{ t('prompts.subTab.claude') }}</button>
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-md' ? 'modal.agents.placeholder.claudeMd' : 'modal.agents.placeholder')"></textarea>
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-claude",
354
+ id: "side-tab-prompts-project",
355
355
  "data-main-tab": "prompts",
356
- "data-prompts-sub-tab": "claude-md",
357
- "aria-current": _ctx.mainTab === 'prompts' && _ctx.promptsSubTab === 'claude-md' ? 'page' : null,
358
- class: _normalizeClass(['side-item', { active: _ctx.isMainTabNavActive('prompts') && _ctx.promptsSubTab === 'claude-md' }]),
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-md'); _ctx.onMainTabClick('prompts')}
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-md' }]),
5981
- onClick: $event => (_ctx.switchPromptsSubTab('claude-md'))
5982
- }, _toDisplayString(_ctx.t('prompts.subTab.claude')), 11 /* TEXT, CLASS, PROPS */, ["onClick"])
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-md' ? 'modal.agents.placeholder.claudeMd' : 'modal.agents.placeholder')
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-md' ? 'modal.agents.contentLabel.claudeMd' : 'modal.agents.contentLabel')), 1 /* TEXT */),
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-md' ? 'modal.agents.placeholder.claudeMd' : 'modal.agents.placeholder')
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
  ]),
@@ -546,6 +546,7 @@
546
546
 
547
547
  .prompts-editor-toolbar .form-hint {
548
548
  margin-top: 0;
549
+ font-size: 9px;
549
550
  }
550
551
 
551
552
  .prompts-editor-actions {
@@ -580,6 +581,39 @@
580
581
  border-left: 1px solid var(--color-border-soft);
581
582
  }
582
583
 
584
+ .project-path-selector {
585
+ margin-top: 8px;
586
+ margin-bottom: 4px;
587
+ }
588
+
589
+ .project-path-label {
590
+ display: block;
591
+ font-size: 0.85em;
592
+ color: var(--color-text-secondary);
593
+ margin-bottom: 4px;
594
+ }
595
+
596
+ .project-path-row {
597
+ display: flex;
598
+ gap: 8px;
599
+ align-items: center;
600
+ }
601
+
602
+ .project-path-select {
603
+ flex: 1;
604
+ min-width: 0;
605
+ }
606
+
607
+ .project-path-manual {
608
+ flex: 1;
609
+ min-width: 0;
610
+ }
611
+
612
+ .project-path-detected {
613
+ margin-top: 4px;
614
+ font-size: 0.82em;
615
+ }
616
+
583
617
  .editor-frame {
584
618
  position: relative;
585
619
  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 {