codexmate 0.0.44 → 0.0.45

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codexmate",
3
- "version": "0.0.44",
3
+ "version": "0.0.45",
4
4
  "description": "Codex/Claude Code/OpenClaw 配置、会话与任务编排 CLI + Web 工具",
5
5
  "main": "cli.js",
6
6
  "bin": {
package/web-ui/app.js CHANGED
@@ -73,6 +73,7 @@ document.addEventListener('DOMContentLoaded', () => {
73
73
  showOpenclawConfigModal: false,
74
74
  showConfigTemplateModal: false,
75
75
  showAgentsModal: false,
76
+ promptsSubTab: 'codex',
76
77
  showSkillsModal: false,
77
78
  showHealthCheckModal: false,
78
79
  showCodexBridgePoolModal: false,
@@ -486,7 +487,7 @@ document.addEventListener('DOMContentLoaded', () => {
486
487
  }
487
488
  {
488
489
  const NAV_STATE_STORAGE_KEY = 'codexmateNavState.v1';
489
- const mainTabSet = new Set(['dashboard', 'config', 'sessions', 'usage', 'orchestration', 'market', 'plugins', 'docs', 'settings', 'trash']);
490
+ const mainTabSet = new Set(['dashboard', 'config', 'sessions', 'usage', 'orchestration', 'market', 'plugins', 'docs', 'settings', 'trash', 'prompts']);
490
491
  let restored = null;
491
492
  try {
492
493
  const raw = localStorage.getItem(NAV_STATE_STORAGE_KEY) || '';
@@ -710,6 +711,19 @@ document.addEventListener('DOMContentLoaded', () => {
710
711
  this.clearSessionTimelineRefs();
711
712
  },
712
713
 
714
+ watch: {
715
+ mainTab(newTab) {
716
+ if (newTab === 'prompts' && typeof this.loadPromptsContent === 'function') {
717
+ this.loadPromptsContent();
718
+ }
719
+ },
720
+ promptsSubTab() {
721
+ if (this.mainTab === 'prompts' && typeof this.loadPromptsContent === 'function') {
722
+ this.loadPromptsContent();
723
+ }
724
+ }
725
+ },
726
+
713
727
  computed: createAppComputed(),
714
728
  methods: createAppMethods()
715
729
  };
package/web-ui/index.html CHANGED
@@ -24,6 +24,7 @@
24
24
  <!-- @include ./partials/index/panel-trash.html -->
25
25
  <!-- @include ./partials/index/panel-market.html -->
26
26
  <!-- @include ./partials/index/panel-plugins.html -->
27
+ <!-- @include ./partials/index/panel-prompts.html -->
27
28
  <!-- @include ./partials/index/layout-footer.html -->
28
29
  <!-- @include ./partials/index/modals-basic.html -->
29
30
  <!-- @include ./partials/index/modal-webhook.html -->
@@ -4,6 +4,7 @@ import { createSessionComputed } from './app.computed.session.mjs';
4
4
  import { createConfigModeComputed } from './config-mode.computed.mjs';
5
5
  import { createSkillsComputed } from './skills.computed.mjs';
6
6
  import { createPluginsComputed } from './plugins.computed.mjs';
7
+ import { createPromptsComputed } from './app.computed.prompts.mjs';
7
8
 
8
9
  export function createAppComputed() {
9
10
  return {
@@ -12,6 +13,7 @@ export function createAppComputed() {
12
13
  ...createMainTabsComputed(),
13
14
  ...createSkillsComputed(),
14
15
  ...createPluginsComputed(),
15
- ...createConfigModeComputed()
16
+ ...createConfigModeComputed(),
17
+ ...createPromptsComputed()
16
18
  };
17
19
  }
@@ -151,6 +151,7 @@ export function createMainTabsComputed() {
151
151
  if (this.mainTab === 'plugins') return this.t('kicker.plugins');
152
152
  if (this.mainTab === 'docs') return this.t('kicker.docs');
153
153
  if (this.mainTab === 'trash') return this.t('kicker.trash');
154
+ if (this.mainTab === 'prompts') return this.t('kicker.prompts');
154
155
  return this.t('kicker.settings');
155
156
  },
156
157
  mainTabTitle() {
@@ -163,6 +164,7 @@ export function createMainTabsComputed() {
163
164
  if (this.mainTab === 'plugins') return this.t('title.plugins');
164
165
  if (this.mainTab === 'docs') return this.t('title.docs');
165
166
  if (this.mainTab === 'trash') return this.t('settings.trash.title');
167
+ if (this.mainTab === 'prompts') return this.t('title.prompts');
166
168
  return this.t('title.settings');
167
169
  },
168
170
  mainTabSubtitle() {
@@ -175,6 +177,7 @@ export function createMainTabsComputed() {
175
177
  if (this.mainTab === 'plugins') return this.t('subtitle.plugins');
176
178
  if (this.mainTab === 'docs') return this.t('subtitle.docs');
177
179
  if (this.mainTab === 'trash') return this.t('settings.trash.meta');
180
+ if (this.mainTab === 'prompts') return this.t('subtitle.prompts');
178
181
  return this.t('subtitle.settings');
179
182
  },
180
183
  taskOrchestrationSelectedRun() {
@@ -0,0 +1,28 @@
1
+ export function createPromptsComputed() {
2
+ return {
3
+ promptsContextHint() {
4
+ if (!this.agentsLoading && !this.agentsDiffVisible && this.hasAgentsContentChanged()) {
5
+ return { text: this.t('modal.agents.unsaved.detectedHint'), warn: true };
6
+ }
7
+ if (this.agentsDiffVisible && (this.agentsDiffLoading || this.agentsSaving)) {
8
+ return { text: this.t('diff.hint.busy'), warn: false };
9
+ }
10
+ if (this.agentsDiffVisible && this.agentsDiffError) {
11
+ return { text: this.t('diff.hint.failedBack'), warn: false };
12
+ }
13
+ if (this.agentsDiffVisible && !this.agentsDiffHasChanges) {
14
+ return { text: this.t('diff.hint.noChangesBack'), warn: false };
15
+ }
16
+ if (this.agentsDiffVisible && this.agentsDiffTruncated) {
17
+ return { text: this.t('diff.viewHint.truncated'), warn: false };
18
+ }
19
+ if (this.agentsDiffVisible) {
20
+ return { text: this.t('diff.viewHint.preview'), warn: false };
21
+ }
22
+ if (!this.agentsLoading) {
23
+ return { text: this.t('modal.agents.hint.twoStepSave'), warn: false };
24
+ }
25
+ return null;
26
+ }
27
+ };
28
+ }
@@ -777,7 +777,7 @@ export function createSessionComputed() {
777
777
  ? this.sessionUsageDaily
778
778
  : null;
779
779
  if (!daily || !Array.isArray(daily.rows) || daily.rows.length === 0) {
780
- return { points: [], labels: [], linePath: '', areaPath: '', width: 800, maxTokens: 0 };
780
+ return { points: [], labels: [], linePath: '', areaPath: '', width: 800, maxTokens: 0, yTicks: [] };
781
781
  }
782
782
 
783
783
  const rows = daily.rows;
@@ -806,6 +806,27 @@ export function createSessionComputed() {
806
806
  const selectedKey = this.sessionsUsageSelectedDayKey;
807
807
  const selectedPoint = points.find(p => p.key === selectedKey) || points[points.length - 1] || null;
808
808
 
809
+ const yTicks = [];
810
+ if (maxTokens > 0) {
811
+ const rawStep = maxTokens / 4;
812
+ const magnitude = Math.pow(10, Math.floor(Math.log10(rawStep)));
813
+ const residual = rawStep / magnitude;
814
+ const niceStep = residual <= 1.5 ? magnitude : (residual <= 3.5 ? 2 * magnitude : 5 * magnitude);
815
+ const tickCount = Math.min(Math.ceil(maxTokens / niceStep), 8);
816
+ for (let i = 0; i <= tickCount; i++) {
817
+ const value = i * niceStep;
818
+ if (value > maxTokens + niceStep * 0.5) break;
819
+ const normalized = value / maxTokens;
820
+ const y = padding.top + chartHeight - (normalized * chartHeight);
821
+ yTicks.push({
822
+ value,
823
+ label: formatCompactUsageSummaryNumber(value),
824
+ y,
825
+ percent: (((height - y) / height) * 100).toFixed(1)
826
+ });
827
+ }
828
+ }
829
+
809
830
  return {
810
831
  points,
811
832
  labels: rows.map((row, index) => ({
@@ -817,6 +838,7 @@ export function createSessionComputed() {
817
838
  width,
818
839
  height,
819
840
  maxTokens,
841
+ yTicks,
820
842
  hoverX: selectedPoint ? selectedPoint.x : 0,
821
843
  hoverY: selectedPoint ? selectedPoint.y : 0
822
844
  };
@@ -635,17 +635,63 @@ export function createAgentsMethods(options = {}) {
635
635
  return;
636
636
  }
637
637
  const successLabel = this.agentsContext === 'openclaw-workspace'
638
- ? `工作区文件已保存${this.agentsWorkspaceFileName ? `: ${this.agentsWorkspaceFileName}` : ''}`
638
+ ? this.t('toast.agents.saved.workspace', { name: this.agentsWorkspaceFileName || '' }).replace(/:\s*$/, '')
639
639
  : (this.agentsContext === 'claude-md'
640
- ? 'CLAUDE.md 已保存'
641
- : (this.agentsContext === 'openclaw' ? 'OpenClaw AGENTS.md 已保存' : 'AGENTS.md 已保存'));
640
+ ? this.t('toast.agents.saved.claudeMd')
641
+ : (this.agentsContext === 'openclaw' ? this.t('toast.agents.saved.openclaw') : this.t('toast.agents.saved.agents')));
642
642
  this.showMessage(successLabel, 'success');
643
- this.closeAgentsModal({ force: true });
643
+ if (this.mainTab === 'prompts') {
644
+ this.loadPromptsContent();
645
+ } else {
646
+ this.closeAgentsModal({ force: true });
647
+ }
644
648
  } catch (e) {
645
649
  this.showMessage(this.t('toast.save.fail'), 'error');
646
650
  } finally {
647
651
  this.agentsSaving = false;
648
652
  }
653
+ },
654
+
655
+ switchPromptsSubTab(subTab) {
656
+ const normalized = subTab === 'claude-md' ? 'claude-md' : 'codex';
657
+ if (this.promptsSubTab === normalized) {
658
+ this.loadPromptsContent();
659
+ return;
660
+ }
661
+ this.promptsSubTab = normalized;
662
+ },
663
+
664
+ async loadPromptsContent() {
665
+ const requestToken = issueLatestRequestToken(this, '_agentsOpenRequestToken');
666
+ this.agentsLoading = true;
667
+ this.resetAgentsDiffState();
668
+ 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);
672
+ if (!isLatestRequestToken(this, '_agentsOpenRequestToken', requestToken)) {
673
+ return;
674
+ }
675
+ if (res.error) {
676
+ this.showMessage(res.error, 'error');
677
+ return;
678
+ }
679
+ this.agentsContent = res.content || '';
680
+ this.agentsOriginalContent = this.agentsContent;
681
+ this.agentsPath = res.path || '';
682
+ this.agentsExists = !!res.exists;
683
+ this.agentsLineEnding = res.lineEnding === '\r\n' ? '\r\n' : '\n';
684
+ this.agentsContext = isClaude ? 'claude-md' : 'codex';
685
+ } catch (e) {
686
+ if (!isLatestRequestToken(this, '_agentsOpenRequestToken', requestToken)) {
687
+ return;
688
+ }
689
+ this.showMessage(this.t('toast.load.fail'), 'error');
690
+ } finally {
691
+ if (isLatestRequestToken(this, '_agentsOpenRequestToken', requestToken)) {
692
+ this.agentsLoading = false;
693
+ }
694
+ }
649
695
  }
650
696
  };
651
697
  }
@@ -15,7 +15,8 @@
15
15
  'plugins',
16
16
  'docs',
17
17
  'settings',
18
- 'trash'
18
+ 'trash',
19
+ 'prompts'
19
20
  ]);
20
21
  const loadDoctorOverview = async (vm, options = {}) => {
21
22
  if (!vm || typeof vm !== 'object') return false;
@@ -90,6 +90,10 @@ export function createSessionActionMethods(options = {}) {
90
90
  this.loadSessionStandalonePlain();
91
91
  },
92
92
 
93
+ canBuildStandaloneUrl(session) {
94
+ return !!this.buildSessionStandaloneUrl(session);
95
+ },
96
+
93
97
  buildSessionStandaloneUrl(session) {
94
98
  if (!session) return '';
95
99
  const source = typeof session.source === 'string' ? session.source.trim().toLowerCase() : '';
@@ -129,6 +133,12 @@ export function createSessionActionMethods(options = {}) {
129
133
  this.showMessage(this.t('toast.copy.fail'), 'error');
130
134
  },
131
135
 
136
+ openSessionLink(session) {
137
+ const url = this.buildSessionStandaloneUrl(session);
138
+ if (!url) { this.showMessage(this.t('toast.link.fail'), 'error'); return; }
139
+ window.open(url, '_blank', 'noopener,noreferrer');
140
+ },
141
+
132
142
  getSessionFilePath(session) {
133
143
  const filePath = typeof session?.filePath === 'string' ? session.filePath.trim() : '';
134
144
  return filePath;
@@ -49,6 +49,8 @@ const en = Object.freeze({
49
49
  'common.apply': 'Apply',
50
50
  'common.applying': 'Applying...',
51
51
  'common.confirming': 'Confirming...',
52
+ 'common.preview': 'Preview',
53
+ 'common.previewing': 'Previewing...',
52
54
  'common.refreshFromText': 'Refresh from text',
53
55
  'common.backToEdit': 'Back to edit',
54
56
  'common.selectAll': 'Select all',
@@ -129,12 +131,14 @@ const en = Object.freeze({
129
131
  'tab.market': 'Skills',
130
132
  'tab.plugins': 'Plugins',
131
133
  'tab.settings': 'Settings',
134
+ 'tab.prompts': 'Prompts',
132
135
 
133
136
  // Side rail section titles
134
137
  'side.overview': 'Overview',
135
138
  'side.docs': 'Docs',
136
139
  'side.config': 'Config',
137
140
  'side.sessions': 'Sessions',
141
+ 'side.prompts': 'Prompts',
138
142
  'side.plugins': 'Plugins',
139
143
  'side.system': 'System',
140
144
  'side.orchestration': 'Tasks',
@@ -164,6 +168,10 @@ const en = Object.freeze({
164
168
  'side.config.openclaw.meta': 'JSON5 / AGENTS',
165
169
  'side.sessions.browser': 'Session Browser',
166
170
  'side.sessions.browser.meta': 'Browse / Export / Cleanup',
171
+ 'side.prompts.agents': 'AGENTS.md',
172
+ 'side.prompts.agents.meta': 'Codex prompt file',
173
+ 'side.prompts.claude': 'CLAUDE.md',
174
+ 'side.prompts.claude.meta': 'Claude prompt file',
167
175
  'side.plugins.tools': 'Prompt Tools',
168
176
  'side.plugins.tools.meta': 'Templates / Variables',
169
177
  'side.plugins.templatesCount': '{count} templates',
@@ -182,6 +190,7 @@ const en = Object.freeze({
182
190
  'kicker.docs': 'Docs',
183
191
  'kicker.trash': 'Trash',
184
192
  'kicker.settings': 'Settings',
193
+ 'kicker.prompts': 'Prompts',
185
194
 
186
195
  'title.dashboard': 'Dashboard / Doctor',
187
196
  'title.config': 'Local Configuration Console',
@@ -192,6 +201,7 @@ const en = Object.freeze({
192
201
  'title.plugins': 'Plugins & Templates',
193
202
  'title.docs': 'CLI Install & Docs',
194
203
  'title.settings': 'System & Data Settings',
204
+ 'title.prompts': 'Prompt Files Editor',
195
205
 
196
206
  'subtitle.dashboard': 'Aggregate status and diagnostics.',
197
207
  'subtitle.config': 'Manage local configs and models.',
@@ -202,6 +212,9 @@ const en = Object.freeze({
202
212
  'subtitle.plugins': 'Manage reusable prompt templates and plugins.',
203
213
  'subtitle.docs': 'CLI install commands and troubleshooting.',
204
214
  'subtitle.settings': 'Manage downloads, directories, and trash.',
215
+ 'subtitle.prompts': 'Edit AGENTS.md and CLAUDE.md.',
216
+ 'prompts.subTab.codex': 'AGENTS.md (Codex)',
217
+ 'prompts.subTab.claude': 'CLAUDE.md (Claude)',
205
218
  'dashboard.doctor.title': 'Doctor',
206
219
  'dashboard.doctor.runChecks': 'Run checks',
207
220
  'dashboard.doctor.checking': 'Checking...',
@@ -378,8 +391,13 @@ const en = Object.freeze({
378
391
  'toast.copy.empty': 'Nothing to copy',
379
392
  'toast.copy.ok': 'Copied',
380
393
  'toast.copy.fail': 'Copy failed',
394
+ 'toast.link.fail': 'Failed to generate link',
381
395
  'toast.save.ok': 'Saved',
382
396
  'toast.save.fail': 'Save failed',
397
+ 'toast.agents.saved.agents': 'AGENTS.md saved',
398
+ 'toast.agents.saved.claudeMd': 'CLAUDE.md saved',
399
+ 'toast.agents.saved.openclaw': 'OpenClaw AGENTS.md saved',
400
+ 'toast.agents.saved.workspace': 'Workspace file saved: {name}',
383
401
  'toast.delete.ok': 'Deleted',
384
402
  'toast.delete.fail': 'Delete failed',
385
403
  'toast.export.empty': 'Nothing to export',
@@ -468,7 +486,7 @@ const en = Object.freeze({
468
486
  'diff.hint.busy': 'Generating diff or applying. Actions are temporarily disabled.',
469
487
  'diff.hint.failedBack': 'Diff preview failed. Go back to edit and retry.',
470
488
  'diff.hint.noChangesBack': 'No changes detected. Go back to edit or cancel.',
471
- 'diff.hint.previewMode': 'Preview mode. Click “Apply” to write or “Back to edit” to continue.',
489
+ 'diff.hint.previewMode': 'Preview mode. Click “Save” to write or “Back to edit” to continue.',
472
490
 
473
491
  'modal.agents.export': 'Export',
474
492
  'modal.agents.copy': 'Copy',
@@ -477,13 +495,13 @@ const en = Object.freeze({
477
495
  'modal.agents.targetFile': 'Target file',
478
496
  'modal.agents.contentLabel': 'AGENTS.md content',
479
497
  'modal.agents.placeholder': 'Edit AGENTS.md here',
480
- 'modal.agents.unsaved.previewModeHint': 'Preview mode: changes are not saved until you click “Apply”.',
498
+ 'modal.agents.unsaved.previewModeHint': 'Preview mode: changes are not saved until you click “Save”.',
481
499
  'modal.agents.unsaved.detectedHint': 'Unsaved changes detected: save before closing or applying.',
482
500
  'modal.agents.hint.shortcuts': 'Shortcut: Esc (back to edit in preview, close in edit).',
483
- 'modal.agents.hint.twoStepSave': 'Two-step save: “Confirm” to preview diff, then “Apply” to save.',
501
+ 'modal.agents.hint.twoStepSave': 'Two-step save: “Preview” to review diff, then “Save” to write.',
484
502
  'diff.tooLargeSkip': 'Content too large. Line diff preview skipped.',
485
- 'diff.viewHint.preview': 'Preview mode. Click “Apply” to save or “Back to edit” to continue.',
486
- 'diff.viewHint.truncated': 'Preview skipped due to size. Click “Apply” to save or “Back to edit” to continue.',
503
+ 'diff.viewHint.preview': 'Preview mode. Click “Save” to write or “Back to edit” to continue.',
504
+ 'diff.viewHint.truncated': 'Preview skipped due to size. Click “Save” to write or “Back to edit” to continue.',
487
505
 
488
506
  // Skills modal
489
507
  'modal.skills.title': 'Skills manager',
@@ -624,6 +642,7 @@ const en = Object.freeze({
624
642
  'sessions.preview.importNative.failedWithReason': 'Import to native failed: {reason}',
625
643
  'sessions.preview.copyLink': 'Copy link',
626
644
  'sessions.preview.copyPath': 'Copy path',
645
+ 'sessions.preview.openLink': 'Open link',
627
646
  'sessions.preview.loadingBody': 'Loading session content...',
628
647
  'sessions.preview.emptyMsgs': 'No messages to display',
629
648
  'sessions.preview.rendering': 'Rendering session content...',
@@ -50,6 +50,8 @@ const ja = Object.freeze({
50
50
  'common.apply': '適用',
51
51
  'common.applying': '適用中...',
52
52
  'common.confirming': '確認中...',
53
+ 'common.preview': 'プレビュー',
54
+ 'common.previewing': 'プレビュー中...',
53
55
  'common.refreshFromText': 'テキストから更新',
54
56
  'common.backToEdit': '編集に戻る',
55
57
  'common.selectAll': 'すべて選択',
@@ -130,12 +132,14 @@ const ja = Object.freeze({
130
132
  'tab.market': 'Skills',
131
133
  'tab.plugins': 'プラグイン',
132
134
  'tab.settings': '設定',
135
+ 'tab.prompts': 'Prompts',
133
136
 
134
137
  // Side rail section titles
135
138
  'side.overview': '概要',
136
139
  'side.docs': 'ドキュメント',
137
140
  'side.config': '設定',
138
141
  'side.sessions': 'セッション',
142
+ 'side.prompts': 'Prompts',
139
143
  'side.plugins': 'プラグイン',
140
144
  'side.system': 'システム',
141
145
  'side.orchestration': 'タスク',
@@ -165,6 +169,10 @@ const ja = Object.freeze({
165
169
  'side.config.openclaw.meta': 'JSON5 / AGENTS',
166
170
  'side.sessions.browser': 'セッション閲覧',
167
171
  'side.sessions.browser.meta': '閲覧 / エクスポート / クリーンアップ',
172
+ 'side.prompts.agents': 'AGENTS.md',
173
+ 'side.prompts.agents.meta': 'Codex プロンプトファイル',
174
+ 'side.prompts.claude': 'CLAUDE.md',
175
+ 'side.prompts.claude.meta': 'Claude プロンプトファイル',
168
176
  'side.plugins.tools': 'プロンプトツール',
169
177
  'side.plugins.tools.meta': 'テンプレート / 変数',
170
178
  'side.plugins.templatesCount': '{count} 件のテンプレート',
@@ -183,6 +191,7 @@ const ja = Object.freeze({
183
191
  'kicker.docs': 'Docs',
184
192
  'kicker.trash': 'ゴミ箱',
185
193
  'kicker.settings': 'Settings',
194
+ 'kicker.prompts': 'Prompts',
186
195
 
187
196
  'title.dashboard': 'Dashboard / Doctor',
188
197
  'title.config': 'ローカル設定コンソール',
@@ -193,6 +202,7 @@ const ja = Object.freeze({
193
202
  'title.plugins': 'プラグインとテンプレート',
194
203
  'title.docs': 'CLI インストールとドキュメント',
195
204
  'title.settings': 'システムとデータ設定',
205
+ 'title.prompts': 'プロンプトファイルエディタ',
196
206
 
197
207
  'subtitle.dashboard': '集約状態と診断エントリ。',
198
208
  'subtitle.config': 'ローカル設定とモデルの管理。',
@@ -203,6 +213,9 @@ const ja = Object.freeze({
203
213
  'subtitle.plugins': 'テンプレート化されたプロンプトと再利用可能なプラグインの管理。',
204
214
  'subtitle.docs': 'CLI インストールコマンドとトラブルシューティング。',
205
215
  'subtitle.settings': 'ダウンロード・ディレクトリ・ゴミ箱の管理。',
216
+ 'subtitle.prompts': 'AGENTS.md と CLAUDE.md を編集。',
217
+ 'prompts.subTab.codex': 'AGENTS.md (Codex)',
218
+ 'prompts.subTab.claude': 'CLAUDE.md (Claude)',
206
219
 
207
220
  'dashboard.doctor.title': 'Doctor',
208
221
  'dashboard.doctor.runChecks': 'チェックを実行',
@@ -380,8 +393,13 @@ const ja = Object.freeze({
380
393
  'toast.copy.empty': 'コピーする内容がありません',
381
394
  'toast.copy.ok': 'コピーしました',
382
395
  'toast.copy.fail': 'コピーに失敗しました',
396
+ 'toast.link.fail': 'リンクの生成に失敗しました',
383
397
  'toast.save.ok': '保存しました',
384
398
  'toast.save.fail': '保存に失敗しました',
399
+ 'toast.agents.saved.agents': 'AGENTS.md 保存しました',
400
+ 'toast.agents.saved.claudeMd': 'CLAUDE.md 保存しました',
401
+ 'toast.agents.saved.openclaw': 'OpenClaw AGENTS.md 保存しました',
402
+ 'toast.agents.saved.workspace': 'ワークスペースファイル保存済み: {name}',
385
403
  'toast.delete.ok': '削除しました',
386
404
  'toast.delete.fail': '削除に失敗しました',
387
405
  'toast.export.empty': 'エクスポートする内容がありません',
@@ -470,7 +488,7 @@ const ja = Object.freeze({
470
488
  'diff.hint.busy': '差分生成中または適用中のため、操作は一時的に利用できません。',
471
489
  'diff.hint.failedBack': '差分プレビューに失敗しました。編集に戻って再試行してください。',
472
490
  'diff.hint.noChangesBack': '変更が検出されませんでした。編集に戻って修正を続けるか、キャンセルして終了してください。',
473
- 'diff.hint.previewMode': '現在プレビューモードです。「適用」をクリックして書き込むか、「編集に戻る」で修正を続けてください。',
491
+ 'diff.hint.previewMode': '現在プレビューモードです。「保存」をクリックして書き込むか、「編集に戻る」で修正を続けてください。',
474
492
 
475
493
  'modal.agents.export': 'エクスポート',
476
494
  'modal.agents.copy': 'コピー',
@@ -479,13 +497,13 @@ const ja = Object.freeze({
479
497
  'modal.agents.targetFile': '対象ファイル',
480
498
  'modal.agents.contentLabel': 'AGENTS.md 内容',
481
499
  'modal.agents.placeholder': 'ここに AGENTS.md の内容を編集してください',
482
- 'modal.agents.unsaved.previewModeHint': 'プレビューモード:現在の変更はまだ保存されていません。「適用」をクリックするとファイルに書き込まれます。',
500
+ 'modal.agents.unsaved.previewModeHint': 'プレビューモード:現在の変更はまだ保存されていません。「保存」をクリックするとファイルに書き込まれます。',
483
501
  'modal.agents.unsaved.detectedHint': '未保存の変更が検出されました:ページを閉じるか適用する前に保存してください。',
484
502
  'modal.agents.hint.shortcuts': 'ショートカット:Esc(差分プレビュー時は編集に戻る、編集時はウィンドウを閉じる)。',
485
- 'modal.agents.hint.twoStepSave': '保存は2段階:「確認」で差分をプレビューし、「適用」で保存します。',
503
+ 'modal.agents.hint.twoStepSave': '保存は2段階:「プレビュー」で差分を確認し、「保存」で書き込みます。',
486
504
  'diff.tooLargeSkip': '内容が大きすぎるため、行単位の差分プレビューをスキップしました',
487
- 'diff.viewHint.preview': '現在プレビューモードです。「適用」で保存するか、「編集に戻る」で修正を続けてください。',
488
- 'diff.viewHint.truncated': '内容が大きすぎるためプレビューをスキップしました。「適用」で保存するか、「編集に戻る」で修正を続けてください。',
505
+ 'diff.viewHint.preview': '現在プレビューモードです。「保存」で書き込むか、「編集に戻る」で修正を続けてください。',
506
+ 'diff.viewHint.truncated': '内容が大きすぎるためプレビューをスキップしました。「保存」で書き込むか、「編集に戻る」で修正を続けてください。',
489
507
 
490
508
  // Skills modal
491
509
  'modal.skills.title': 'Skills 管理',
@@ -613,6 +631,7 @@ const ja = Object.freeze({
613
631
  'sessions.preview.openStandalone': 'スタンドアロンで開く',
614
632
  'sessions.preview.copyLink': 'リンクをコピー',
615
633
  'sessions.preview.copyPath': 'パスをコピー',
634
+ 'sessions.preview.openLink': 'リンクを開く',
616
635
  'sessions.preview.loadingBody': 'メッセージ読み込み中...',
617
636
  'sessions.preview.emptyMsgs': 'メッセージがありません',
618
637
  'sessions.preview.rendering': 'レンダリング中...',
@@ -58,6 +58,8 @@ const vi = Object.freeze({
58
58
  'common.apply': 'Áp dụng',
59
59
  'common.applying': 'Đang áp dụng...',
60
60
  'common.confirming': 'Đang xác nhận...',
61
+ 'common.preview': 'Xem trước',
62
+ 'common.previewing': 'Đang xem trước...',
61
63
  'common.writeToEditor': 'Ghi vào trình soạn thảo',
62
64
  'common.refreshFromText': 'Làm mới từ văn bản',
63
65
  'common.backToEdit': 'Quay lại chỉnh sửa',
@@ -90,12 +92,14 @@ const vi = Object.freeze({
90
92
  'tab.market': 'Skills',
91
93
  'tab.plugins': 'Plugin',
92
94
  'tab.settings': 'Cài đặt',
95
+ 'tab.prompts': 'Prompts',
93
96
 
94
97
  // Side rail section titles
95
98
  'side.overview': 'Tổng quan',
96
99
  'side.docs': 'Tài liệu',
97
100
  'side.config': 'Cấu hình',
98
101
  'side.sessions': 'Phiên',
102
+ 'side.prompts': 'Prompts',
99
103
  'side.plugins': 'Plugin',
100
104
  'side.system': 'Hệ thống',
101
105
  'side.orchestration': 'Tác vụ',
@@ -125,6 +129,10 @@ const vi = Object.freeze({
125
129
  'side.config.openclaw.meta': 'JSON5 / AGENTS',
126
130
  'side.sessions.browser': 'Trình duyệt phiên',
127
131
  'side.sessions.browser.meta': 'Duyệt / Xuất / Dọn dẹp',
132
+ 'side.prompts.agents': 'AGENTS.md',
133
+ 'side.prompts.agents.meta': 'Tệp lệnh Codex',
134
+ 'side.prompts.claude': 'CLAUDE.md',
135
+ 'side.prompts.claude.meta': 'Tệp lệnh Claude',
128
136
  'side.plugins.tools': 'Công cụ prompt',
129
137
  'side.plugins.tools.meta': 'Mẫu / Biến',
130
138
  'side.system.settings': 'Cài đặt runtime',
@@ -162,6 +170,7 @@ const vi = Object.freeze({
162
170
  'kicker.plugins': 'Plugin',
163
171
  'kicker.docs': 'Tài liệu',
164
172
  'kicker.settings': 'Cài đặt',
173
+ 'kicker.prompts': 'Prompts',
165
174
  'kicker.trash': 'Thùng rác',
166
175
 
167
176
  'title.dashboard': 'Dashboard / Doctor',
@@ -173,6 +182,7 @@ const vi = Object.freeze({
173
182
  'title.plugins': 'Plugin & Mẫu',
174
183
  'title.docs': 'Cài CLI & Tài liệu',
175
184
  'title.settings': 'Hệ thống & Dữ liệu',
185
+ 'title.prompts': 'Trình chỉnh sửa tệp lệnh',
176
186
 
177
187
  'subtitle.dashboard': 'Tổng hợp trạng thái và chẩn đoán.',
178
188
  'subtitle.config': 'Quản lý cấu hình và mô hình cục bộ.',
@@ -183,6 +193,9 @@ const vi = Object.freeze({
183
193
  'subtitle.plugins': 'Quản lý plugin và mẫu tái sử dụng.',
184
194
  'subtitle.docs': 'Lệnh cài CLI và hướng dẫn.',
185
195
  'subtitle.settings': 'Quản lý tải xuống, thư mục và dữ liệu.',
196
+ 'subtitle.prompts': 'Chỉnh sửa AGENTS.md và CLAUDE.md.',
197
+ 'prompts.subTab.codex': 'AGENTS.md (Codex)',
198
+ 'prompts.subTab.claude': 'CLAUDE.md (Claude)',
186
199
 
187
200
 
188
201
  // Task orchestration readiness
@@ -261,8 +274,13 @@ const vi = Object.freeze({
261
274
  'toast.copy.empty': 'Không có gì để sao chép',
262
275
  'toast.copy.ok': 'Đã sao chép',
263
276
  'toast.copy.fail': 'Sao chép thất bại',
277
+ 'toast.link.fail': 'Không thể tạo liên kết',
264
278
  'toast.save.ok': 'Đã lưu',
265
279
  'toast.save.fail': 'Lưu thất bại',
280
+ 'toast.agents.saved.agents': 'AGENTS.md đã lưu',
281
+ 'toast.agents.saved.claudeMd': 'CLAUDE.md đã lưu',
282
+ 'toast.agents.saved.openclaw': 'OpenClaw AGENTS.md đã lưu',
283
+ 'toast.agents.saved.workspace': 'Tệp workspace đã lưu: {name}',
266
284
  'toast.delete.ok': 'Đã xóa',
267
285
  'toast.delete.fail': 'Xóa thất bại',
268
286
  'toast.operation.success': 'Thao tác thành công',
@@ -309,6 +327,19 @@ const vi = Object.freeze({
309
327
  'modal.claudeDelete.message': 'Xóa cấu hình "{name}"?',
310
328
  'modal.claudeDelete.confirm': 'Xóa',
311
329
  'modal.claudeDelete.cancel': 'Hủy',
330
+
331
+ // Sessions
332
+ 'sessions.preview.openLink': 'Mở liên kết',
333
+
334
+ // Diff / Agents hints
335
+ 'diff.hint.busy': 'Đang tạo diff hoặc áp dụng. Thao tác tạm thời bị vô hiệu hóa.',
336
+ 'diff.hint.failedBack': 'Xem trước diff thất bại. Hãy quay lại chỉnh sửa và thử lại.',
337
+ 'diff.hint.noChangesBack': 'Không phát hiện thay đổi. Quay lại chỉnh sửa hoặc hủy.',
338
+ '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.',
339
+ '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.',
340
+ 'modal.agents.hint.twoStepSave': 'Lưu hai bước: "Xem trước" để kiểm tra diff, rồi "Lưu" để ghi.',
341
+ '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.',
342
+ '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.',
312
343
  });
313
344
 
314
345
  export { vi };