codexmate 0.1.3 → 0.1.4

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/cli.js CHANGED
@@ -909,8 +909,8 @@ function isPlainObject(value) {
909
909
  return !!value && typeof value === 'object' && !Array.isArray(value);
910
910
  }
911
911
 
912
- const TOOL_CONFIG_PERMISSION_TARGETS = new Set(['codex', 'claude', 'opencode', 'kilocode']);
913
- const TOOL_CONFIG_PERMISSION_DEFAULTS = Object.freeze({ codex: false, claude: false, opencode: false, kilocode: false });
912
+ const TOOL_CONFIG_PERMISSION_TARGETS = new Set(['codex', 'claude', 'opencode', 'kilocode', 'openclaw']);
913
+ const TOOL_CONFIG_PERMISSION_DEFAULTS = Object.freeze({ codex: false, claude: false, opencode: false, kilocode: false, openclaw: false });
914
914
  let toolConfigWriteGuardDepth = 0;
915
915
 
916
916
  function enterToolConfigWriteGuard() {
@@ -938,7 +938,8 @@ function normalizeToolConfigPermissions(value) {
938
938
  codex: source.codex === true,
939
939
  claude: source.claude === true,
940
940
  opencode: source.opencode === true,
941
- kilocode: source.kilocode === true
941
+ kilocode: source.kilocode === true,
942
+ openclaw: source.openclaw === true
942
943
  };
943
944
  }
944
945
 
@@ -1197,10 +1198,16 @@ function getApiToolConfigWriteTarget(action) {
1197
1198
  'apply-kilocode-config',
1198
1199
  'start-kilocode'
1199
1200
  ]);
1201
+ const openclawWriteActions = new Set([
1202
+ 'apply-openclaw-config',
1203
+ 'apply-openclaw-agents-file',
1204
+ 'apply-openclaw-workspace-file'
1205
+ ]);
1200
1206
  if (codexWriteActions.has(name)) return 'codex';
1201
1207
  if (claudeWriteActions.has(name)) return 'claude';
1202
1208
  if (opencodeWriteActions.has(name)) return 'opencode';
1203
1209
  if (kilocodeWriteActions.has(name)) return 'kilocode';
1210
+ if (openclawWriteActions.has(name)) return 'openclaw';
1204
1211
  return '';
1205
1212
  }
1206
1213
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codexmate",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Codex/Claude Code/OpenClaw 配置、会话与任务编排 CLI + Web 工具",
5
5
  "main": "cli.js",
6
6
  "bin": {
package/web-ui/app.js CHANGED
@@ -396,8 +396,8 @@ document.addEventListener('DOMContentLoaded', () => {
396
396
  providerCacheError: '',
397
397
  providerCacheRequestSeq: 0,
398
398
  settingsTab: 'general',
399
- toolConfigPermissions: { codex: false, claude: false, opencode: false, kilocode: false },
400
- toolConfigPermissionSaving: { codex: false, claude: false, opencode: false, kilocode: false },
399
+ toolConfigPermissions: { codex: false, claude: false, opencode: false, kilocode: false, openclaw: false },
400
+ toolConfigPermissionSaving: { codex: false, claude: false, opencode: false, kilocode: false, openclaw: false },
401
401
  sessionTrashEnabled: true,
402
402
  sessionTrashItems: [],
403
403
  sessionTrashVisibleCount: SESSION_TRASH_PAGE_SIZE,
@@ -174,10 +174,6 @@ export function createDashboardComputed() {
174
174
  };
175
175
  });
176
176
  },
177
- currentInstalledCommandCards() {
178
- const targets = Array.isArray(this.installTargetCards) ? this.installTargetCards : [];
179
- return targets.filter((target) => target && target.installed === true);
180
- },
181
177
  installRegistryPreview() {
182
178
  return this.resolveInstallRegistryUrl(this.installRegistryPreset, this.installRegistryCustom);
183
179
  },
@@ -144,7 +144,8 @@ export function createStartupClaudeMethods(options = {}) {
144
144
  codex: statusRes.toolConfigPermissions.codex === true,
145
145
  claude: statusRes.toolConfigPermissions.claude === true,
146
146
  opencode: statusRes.toolConfigPermissions.opencode === true,
147
- kilocode: statusRes.toolConfigPermissions.kilocode === true
147
+ kilocode: statusRes.toolConfigPermissions.kilocode === true,
148
+ openclaw: statusRes.toolConfigPermissions.openclaw === true
148
149
  };
149
150
  }
150
151
  this.providersList = listRes.providers;
@@ -3,7 +3,7 @@ export function createToolConfigPermissionMethods(options = {}) {
3
3
 
4
4
  function normalizeTarget(value) {
5
5
  const target = typeof value === 'string' ? value.trim().toLowerCase() : '';
6
- return target === 'codex' || target === 'claude' || target === 'opencode' || target === 'kilocode' ? target : '';
6
+ return target === 'codex' || target === 'claude' || target === 'opencode' || target === 'kilocode' || target === 'openclaw' ? target : '';
7
7
  }
8
8
 
9
9
  function normalizePermissions(value) {
@@ -12,7 +12,8 @@ export function createToolConfigPermissionMethods(options = {}) {
12
12
  codex: source.codex === true,
13
13
  claude: source.claude === true,
14
14
  opencode: source.opencode === true,
15
- kilocode: source.kilocode === true
15
+ kilocode: source.kilocode === true,
16
+ openclaw: source.openclaw === true
16
17
  };
17
18
  }
18
19
 
@@ -439,7 +439,8 @@ export function createWebUiPreferencesMethods(options = {}) {
439
439
  codex: source.toolConfigPermissions.codex === true,
440
440
  claude: source.toolConfigPermissions.claude === true,
441
441
  opencode: source.toolConfigPermissions.opencode === true,
442
- kilocode: source.toolConfigPermissions.kilocode === true
442
+ kilocode: source.toolConfigPermissions.kilocode === true,
443
+ openclaw: source.toolConfigPermissions.openclaw === true
443
444
  };
444
445
  }
445
446
  if (Array.isArray(source.deletedClaudeSettingsImports)) {
@@ -619,14 +619,8 @@ const en = Object.freeze({
619
619
 
620
620
  // Docs panel
621
621
  'docs.title': 'CLI Install',
622
- 'docs.subtitle': 'Install commands for Claude Code / Gemini CLI / CodeBuddy Code / Codex CLI / KiloCode CLI.',
623
622
  'docs.section.commands': 'Commands',
624
- 'docs.section.commandsNote': 'Copy and run directly.',
625
- 'docs.installed.title': 'Currently installed commands',
626
- 'docs.installed.count': '{count} installed',
627
- 'docs.installed.empty': 'No installed commands detected',
628
623
  'docs.section.faq': 'FAQ',
629
- 'docs.section.faqNote': 'Common issues and tips.',
630
624
  'docs.command.aria': '{name} command',
631
625
  'docs.registryHintPrefix': 'Command will append:',
632
626
  'docs.registryHintCustom': 'Enter a full URL (http/https) to append as registry.',
@@ -634,8 +628,6 @@ const en = Object.freeze({
634
628
  'docs.meta.bin': 'bin: {bin}',
635
629
  'docs.termuxLabel': 'Termux',
636
630
  'docs.termuxAria': 'Termux Codex CLI command',
637
- 'docs.rule.1': 'Commands depend on package manager, registry and action.',
638
- 'docs.rule.2': 'Custom registry is used for install/update only.',
639
631
  'docs.tip.win.1': 'If PowerShell reports permission errors (EACCES/EPERM), run the install command as Administrator.',
640
632
  'docs.tip.win.2': 'If the command is still not found after install, reopen the terminal and run: where codex / where claude / where gemini / where codebuddy.',
641
633
  'docs.tip.win.3': 'If your network blocks npm, try switching registry presets (npmmirror / Tencent / Custom).',
@@ -1544,6 +1536,11 @@ const en = Object.freeze({
1544
1536
  'toolConfig.kilocode.lockedTitle': 'Read-only mode',
1545
1537
  'toolConfig.kilocode.lockedDesc': 'Enable write access to auto-sync config or launch KiloCode.',
1546
1538
  'toolConfig.kilocode.confirmMessage': 'When enabled, actions in the KiloCode tab can write ~/.config/kilo/kilo.jsonc or an existing kilo.json, and can launch local KiloCode.',
1539
+ 'toolConfig.openclaw.title': 'OpenClaw config writes',
1540
+ 'toolConfig.openclaw.desc': 'Read-only by default; enable to apply OpenClaw configs and write AGENTS.md and other workspace files.',
1541
+ 'toolConfig.openclaw.confirmMessage': 'When enabled, actions in the OpenClaw tab can write openclaw.json and OpenClaw workspace files (AGENTS.md, SOUL.md, etc.).',
1542
+ 'toolConfig.openclaw.lockedTitle': 'OpenClaw is read-only',
1543
+ 'toolConfig.openclaw.lockedDesc': 'OpenClaw config is not written here. To apply configs or edit workspace files, enable write access on this tab first.',
1547
1544
  'kilocode.providerModel.title': 'KiloCode provider / model',
1548
1545
  'kilocode.connection.title': 'KiloCode connection',
1549
1546
  'kilocode.targetFile': 'Active KiloCode config: {path} · {status}',
@@ -621,14 +621,8 @@ const ja = Object.freeze({
621
621
 
622
622
  // Docs panel
623
623
  'docs.title': 'CLI インストールドキュメント',
624
- 'docs.subtitle': 'Claude Code / Gemini CLI / CodeBuddy Code / Codex CLI / KiloCode CLI コマンドを表示。',
625
624
  'docs.section.commands': 'インストールコマンド',
626
- 'docs.section.commandsNote': 'コマンドは直接コピーできます。',
627
- 'docs.installed.title': '現在インストール済みのコマンド',
628
- 'docs.installed.count': '{count} 個インストール済み',
629
- 'docs.installed.empty': 'インストール済みコマンドは検出されていません',
630
625
  'docs.section.faq': 'よくある質問',
631
- 'docs.section.faqNote': 'よくある質問は以下をご覧ください。',
632
626
  'docs.command.aria': '{name} コマンド',
633
627
  'docs.registryHintPrefix': 'コマンドに付加:',
634
628
  'docs.registryHintCustom': '完全な URL(http/https 含む)を入力してください。コマンドに自動付加されます。',
@@ -636,8 +630,6 @@ const ja = Object.freeze({
636
630
  'docs.meta.bin': 'bin: {bin}',
637
631
  'docs.termuxLabel': 'Termux',
638
632
  'docs.termuxAria': 'Termux Codex CLI command',
639
- 'docs.rule.1': 'コマンドは現在のパッケージマネージャー、ミラー、操作に基づいて生成されます。',
640
- 'docs.rule.2': 'カスタムミラーはインストールとアップグレードにのみ使用されます。',
641
633
  'docs.tip.win.1': 'PowerShell で権限不足(EACCES/EPERM)エラーが発生した場合は、管理者としてインストールコマンドを実行してください。',
642
634
  'docs.tip.win.2': 'インストール後にコマンドが見つからない場合は、ターミナルを再起動して実行:where codex / where claude / where gemini / where codebuddy。',
643
635
  'docs.tip.win.3': '企業ネットワークで制限がある場合は、ミラーソース(npmmirror / Tencent Cloud / カスタム)を切り替えてください。',
@@ -1531,6 +1523,11 @@ const ja = Object.freeze({
1531
1523
  'toolConfig.kilocode.lockedTitle': '読み取り専用モード',
1532
1524
  'toolConfig.kilocode.lockedDesc': '書き込み権限を有効化すると、設定の自動同期または KiloCode の起動ができます。',
1533
1525
  'toolConfig.kilocode.confirmMessage': '有効化すると、KiloCode タブ内の操作が ~/.config/kilo/kilo.jsonc または既存の kilo.json に書き込み、ローカル KiloCode を起動できます。',
1526
+ 'toolConfig.openclaw.title': 'OpenClaw 設定の書き込み',
1527
+ 'toolConfig.openclaw.desc': '既定は読み取り専用。有効化すると OpenClaw 設定を適用し、AGENTS.md などのワークスペースファイルを書き込みできます。',
1528
+ 'toolConfig.openclaw.confirmMessage': '有効化すると、OpenClaw タブ内の操作が openclaw.json およびワークスペースファイル(AGENTS.md、SOUL.md など)に書き込みできます。',
1529
+ 'toolConfig.openclaw.lockedTitle': 'OpenClaw は読み取り専用です',
1530
+ 'toolConfig.openclaw.lockedDesc': 'ここでは OpenClaw 設定を書き込みません。設定を適用またはワークスペースファイルを編集するには、このタブの書き込みスイッチを有効化してください。',
1534
1531
  'kilocode.providerModel.title': 'KiloCode プロバイダー / モデル',
1535
1532
  'kilocode.connection.title': 'KiloCode 接続',
1536
1533
  'kilocode.targetFile': '有効な KiloCode 設定:{path} · {status}',
@@ -826,14 +826,8 @@ const vi = Object.freeze({
826
826
  'modal.openclaw.quick.optionsHint': 'Khi tắt ghi đè, chỉ điền các trường còn thiếu.',
827
827
  'modal.openclaw.quick.writeToEditor': 'Ghi vào editor',
828
828
  'docs.title': 'Cài CLI',
829
- 'docs.subtitle': 'Lệnh cài đặt cho Claude Code / Gemini CLI / CodeBuddy Code / Codex CLI / KiloCode CLI.',
830
829
  'docs.section.commands': 'Lệnh',
831
- 'docs.section.commandsNote': 'Sao chép và chạy trực tiếp.',
832
- 'docs.installed.title': 'Lệnh hiện đã cài đặt',
833
- 'docs.installed.count': 'Đã cài {count}',
834
- 'docs.installed.empty': 'Chưa phát hiện lệnh đã cài',
835
830
  'docs.section.faq': 'FAQ',
836
- 'docs.section.faqNote': 'Vấn đề phổ biến và mẹo.',
837
831
  'docs.command.aria': 'Lệnh {name}',
838
832
  'docs.registryHintPrefix': 'Lệnh sẽ thêm:',
839
833
  'docs.registryHintCustom': 'Nhập URL đầy đủ (http/https) để thêm làm registry.',
@@ -841,8 +835,6 @@ const vi = Object.freeze({
841
835
  'docs.meta.bin': 'bin: {bin}',
842
836
  'docs.termuxLabel': 'Termux',
843
837
  'docs.termuxAria': 'Lệnh Codex CLI cho Termux',
844
- 'docs.rule.1': 'Lệnh phụ thuộc vào trình quản lý gói, registry và hành động.',
845
- 'docs.rule.2': 'Registry tùy chỉnh chỉ dùng cho cài đặt/cập nhật.',
846
838
  'docs.tip.win.1': 'Nếu PowerShell báo lỗi quyền (EACCES/EPERM), chạy lệnh cài đặt với quyền Administrator.',
847
839
  'docs.tip.win.2': 'Nếu lệnh không tìm thấy sau cài đặt, mở lại terminal và chạy: where codex / where claude.',
848
840
  'docs.tip.win.3': 'Nếu mạng chặn npm, thử chuyển registry (npmmirror / Tencent / Tùy chỉnh).',
@@ -1516,6 +1508,11 @@ const vi = Object.freeze({
1516
1508
  'toolConfig.kilocode.lockedTitle': 'Chế độ chỉ đọc',
1517
1509
  'toolConfig.kilocode.lockedDesc': 'Bật quyền ghi để tự động đồng bộ cấu hình hoặc khởi chạy KiloCode.',
1518
1510
  'toolConfig.kilocode.confirmMessage': 'Khi bật, các thao tác trong tab KiloCode có thể ghi ~/.config/kilo/kilo.jsonc hoặc kilo.json hiện có, và có thể khởi chạy KiloCode cục bộ.',
1511
+ 'toolConfig.openclaw.title': 'Ghi cấu hình OpenClaw',
1512
+ 'toolConfig.openclaw.desc': 'Mặc định chỉ đọc; bật để áp dụng cấu hình OpenClaw và ghi AGENTS.md cùng các tệp workspace khác.',
1513
+ 'toolConfig.openclaw.confirmMessage': 'Khi bật, các thao tác trong tab OpenClaw có thể ghi openclaw.json và các tệp workspace (AGENTS.md, SOUL.md, v.v.).',
1514
+ 'toolConfig.openclaw.lockedTitle': 'OpenClaw đang ở chế độ chỉ đọc',
1515
+ 'toolConfig.openclaw.lockedDesc': 'Không ghi cấu hình OpenClaw ở đây. Để áp dụng cấu hình hoặc sửa tệp workspace, hãy bật quyền ghi trên tab này trước.',
1519
1516
  'kilocode.providerModel.title': 'Nhà cung cấp / mô hình KiloCode',
1520
1517
  'kilocode.connection.title': 'Kết nối KiloCode',
1521
1518
  'kilocode.targetFile': 'Cấu hình KiloCode đang dùng: {path} · {status}',
@@ -619,14 +619,8 @@ const zhTw = Object.freeze({
619
619
 
620
620
  // Docs panel
621
621
  'docs.title': 'CLI 安裝文檔',
622
- 'docs.subtitle': '查看 Claude Code / Gemini CLI / CodeBuddy Code / Codex CLI / KiloCode CLI 命令。',
623
622
  'docs.section.commands': '安裝命令',
624
- 'docs.section.commandsNote': '命令可直接複製。',
625
- 'docs.installed.title': '目前已安裝命令',
626
- 'docs.installed.count': '已安裝 {count} 個',
627
- 'docs.installed.empty': '未偵測到已安裝命令',
628
623
  'docs.section.faq': '常見問題',
629
- 'docs.section.faqNote': '常見問題見下。',
630
624
  'docs.command.aria': '{name} 命令',
631
625
  'docs.registryHintPrefix': '命令將附加:',
632
626
  'docs.registryHintCustom': '請輸入完整 URL(含 http/https),將自動附加到命令。',
@@ -634,8 +628,6 @@ const zhTw = Object.freeze({
634
628
  'docs.meta.bin': 'bin: {bin}',
635
629
  'docs.termuxLabel': 'Termux',
636
630
  'docs.termuxAria': 'Termux Codex CLI command',
637
- 'docs.rule.1': '命令按目前包管理器、鏡像與操作生成。',
638
- 'docs.rule.2': '自訂鏡像僅用於安裝與升級。',
639
631
  'docs.tip.win.1': 'PowerShell 報權限不足(EACCES/EPERM)時,請以管理員身份執行安裝命令。',
640
632
  'docs.tip.win.2': '安裝後若仍提示找不到命令,重開終端並執行:where codex / where claude / where gemini / where codebuddy。',
641
633
  'docs.tip.win.3': '公司網路受限時,可先切換鏡像源快捷項(npmmirror / 騰訊雲 / 自訂)。',
@@ -1544,6 +1536,11 @@ const zhTw = Object.freeze({
1544
1536
  'toolConfig.kilocode.lockedTitle': '唯讀模式',
1545
1537
  'toolConfig.kilocode.lockedDesc': '啟用寫入權限後可自動同步設定或啟動 KiloCode。',
1546
1538
  'toolConfig.kilocode.confirmMessage': '開啟後,KiloCode tab 內的操作會寫入 ~/.config/kilo/kilo.jsonc 或既有的 kilo.json,並可啟動本機 KiloCode。',
1539
+ 'toolConfig.openclaw.title': 'OpenClaw 設定寫入',
1540
+ 'toolConfig.openclaw.desc': '預設唯讀;啟用後可套用 OpenClaw 設定並寫入 AGENTS.md 與其他工作區檔案。',
1541
+ 'toolConfig.openclaw.confirmMessage': '開啟後,OpenClaw tab 內的操作會寫入 openclaw.json 及 OpenClaw 工作區檔案(AGENTS.md、SOUL.md 等)。',
1542
+ 'toolConfig.openclaw.lockedTitle': 'OpenClaw 目前為唯讀',
1543
+ 'toolConfig.openclaw.lockedDesc': '這裡不會寫入 OpenClaw 設定。要套用設定或編輯工作區檔案,請先開啟本 tab 的寫入開關。',
1547
1544
  'kilocode.providerModel.title': 'KiloCode provider / 模型',
1548
1545
  'kilocode.connection.title': 'KiloCode 連線',
1549
1546
  'kilocode.targetFile': 'KiloCode 生效設定:{path} · {status}',
@@ -619,14 +619,8 @@ const zh = Object.freeze({
619
619
 
620
620
  // Docs panel
621
621
  'docs.title': 'CLI 安装文档',
622
- 'docs.subtitle': '查看 Claude Code / Gemini CLI / CodeBuddy Code / Codex CLI / KiloCode CLI 命令。',
623
622
  'docs.section.commands': '安装命令',
624
- 'docs.section.commandsNote': '命令可直接复制。',
625
- 'docs.installed.title': '当前已安装命令',
626
- 'docs.installed.count': '已安装 {count} 个',
627
- 'docs.installed.empty': '未检测到已安装命令',
628
623
  'docs.section.faq': '常见问题',
629
- 'docs.section.faqNote': '常见问题见下。',
630
624
  'docs.command.aria': '{name} 命令',
631
625
  'docs.registryHintPrefix': '命令将附加:',
632
626
  'docs.registryHintCustom': '请输入完整 URL(含 http/https),将自动附加到命令。',
@@ -634,8 +628,6 @@ const zh = Object.freeze({
634
628
  'docs.meta.bin': 'bin: {bin}',
635
629
  'docs.termuxLabel': 'Termux',
636
630
  'docs.termuxAria': 'Termux Codex CLI command',
637
- 'docs.rule.1': '命令按当前包管理器、镜像与操作生成。',
638
- 'docs.rule.2': '自定义镜像仅用于安装与升级。',
639
631
  'docs.tip.win.1': 'PowerShell 报权限不足(EACCES/EPERM)时,请以管理员身份执行安装命令。',
640
632
  'docs.tip.win.2': '安装后若仍提示找不到命令,重开终端并执行:where codex / where claude / where gemini / where codebuddy。',
641
633
  'docs.tip.win.3': '公司网络受限时,可先切换镜像源快捷项(npmmirror / 腾讯云 / 自定义)。',
@@ -1544,6 +1536,11 @@ const zh = Object.freeze({
1544
1536
  'toolConfig.kilocode.lockedTitle': '只读模式',
1545
1537
  'toolConfig.kilocode.lockedDesc': '开启写入权限后可保存配置或启动 KiloCode。',
1546
1538
  'toolConfig.kilocode.confirmMessage': '打开后,KiloCode tab 内的操作会写入 ~/.config/kilo/kilo.jsonc 或已存在的 kilo.json,并可启动本机 KiloCode。',
1539
+ 'toolConfig.openclaw.title': 'OpenClaw 配置写入',
1540
+ 'toolConfig.openclaw.desc': '默认只读;开启后可应用 OpenClaw 配置、写入 AGENTS.md 与其他工作区文件。',
1541
+ 'toolConfig.openclaw.confirmMessage': '打开后,OpenClaw tab 内的操作会写入 openclaw.json 及 OpenClaw 工作区文件(AGENTS.md、SOUL.md 等)。',
1542
+ 'toolConfig.openclaw.lockedTitle': 'OpenClaw 当前为只读',
1543
+ 'toolConfig.openclaw.lockedDesc': '这里不会写入 OpenClaw 配置。要应用配置或编辑工作区文件,请先打开本 tab 的写入开关。',
1547
1544
  'kilocode.providerModel.title': 'KiloCode provider / model',
1548
1545
  'kilocode.connection.title': 'KiloCode 连接',
1549
1546
  'kilocode.targetFile': 'KiloCode 生效配置:{path} · {status}',
@@ -11,6 +11,23 @@
11
11
  <button type="button" :class="['segment', { active: configMode === 'openclaw' }]" @click="switchConfigMode('openclaw')">{{ t('tab.config.openclaw') }}</button>
12
12
  </div>
13
13
  <div class="openclaw-layout">
14
+ <section class="tool-config-write-card" :aria-label="t('toolConfig.openclaw.title')">
15
+ <div class="tool-config-write-copy">
16
+ <div class="tool-config-write-title">{{ t('toolConfig.openclaw.title') }}</div>
17
+ <p class="tool-config-write-desc">{{ t('toolConfig.openclaw.desc') }}</p>
18
+ </div>
19
+ <label class="settings-toggle-row tool-config-write-toggle">
20
+ <input
21
+ type="checkbox"
22
+ autocomplete="off"
23
+ :checked="isToolConfigWriteAllowed('openclaw')"
24
+ :disabled="toolConfigPermissionSaving.openclaw"
25
+ @change="setToolConfigPermission('openclaw', $event.target.checked)">
26
+ <span class="toggle-track"><span class="toggle-thumb"></span></span>
27
+ <span>{{ toolConfigPermissionStatusLabel('openclaw') }}</span>
28
+ </label>
29
+ </section>
30
+
14
31
  <section class="settings-card settings-card--wide openclaw-summary-card" aria-label="OpenClaw 当前摘要">
15
32
  <div class="settings-card-body">
16
33
  <div class="openclaw-summary-header">
@@ -32,10 +49,12 @@
32
49
  </div>
33
50
  </section>
34
51
 
52
+ <div class="tool-config-write-scope" :class="{ locked: !isToolConfigWriteAllowed('openclaw') }">
53
+ <div class="tool-config-write-body">
35
54
  <section class="settings-card settings-card--wide openclaw-workspace-card">
36
55
  <div class="settings-card-body">
37
56
  <div class="openclaw-tools-grid">
38
- <button class="openclaw-tool-btn" @click="openOpenclawAgentsEditor" :disabled="loading || !!initError || agentsLoading">
57
+ <button class="openclaw-tool-btn" @click="openOpenclawAgentsEditor" :disabled="loading || !!initError || agentsLoading || !isToolConfigWriteAllowed('openclaw')">
39
58
  <div class="tool-icon">📄</div>
40
59
  <div class="tool-content">
41
60
  <div class="tool-title">AGENTS.md</div>
@@ -52,7 +71,7 @@
52
71
  type="button"
53
72
  class="openclaw-tool-btn"
54
73
  @click="openOpenclawQuickWorkspaceFile(fileName)"
55
- :disabled="loading || !!initError || agentsLoading">
74
+ :disabled="loading || !!initError || agentsLoading || !isToolConfigWriteAllowed('openclaw')">
56
75
  <div class="tool-icon">📄</div>
57
76
  <div class="tool-content">
58
77
  <div class="tool-title">{{ fileName }}</div>
@@ -70,13 +89,14 @@
70
89
  <div class="settings-card-body">
71
90
  <div class="card-list openclaw-card-list">
72
91
  <div v-for="(config, name) in openclawConfigs" :key="name"
73
- :class="['card', { active: currentOpenclawConfig === name }]"
74
- @click="applyOpenclawConfig(name)"
75
- @keydown.enter.self.prevent="applyOpenclawConfig(name)"
76
- @keydown.space.self.prevent="applyOpenclawConfig(name)"
77
- tabindex="0"
92
+ :class="['card', { active: currentOpenclawConfig === name, disabled: !isToolConfigWriteAllowed('openclaw') }]"
93
+ @click="isToolConfigWriteAllowed('openclaw') && applyOpenclawConfig(name)"
94
+ @keydown.enter.self.prevent="isToolConfigWriteAllowed('openclaw') && applyOpenclawConfig(name)"
95
+ @keydown.space.self.prevent="isToolConfigWriteAllowed('openclaw') && applyOpenclawConfig(name)"
96
+ :tabindex="isToolConfigWriteAllowed('openclaw') ? 0 : -1"
78
97
  role="button"
79
98
  :aria-label="t('openclaw.action.applyAria', { name })"
99
+ :aria-disabled="!isToolConfigWriteAllowed('openclaw') ? 'true' : null"
80
100
  :aria-current="currentOpenclawConfig === name ? 'true' : null">
81
101
  <div class="card-leading">
82
102
  <div class="card-icon">{{ name.charAt(0).toUpperCase() }}</div>
@@ -95,7 +115,7 @@
95
115
  {{ openclawHasContent(config) ? t('openclaw.configured') : t('openclaw.notConfigured') }}
96
116
  </span>
97
117
  <div class="card-actions" @click.stop>
98
- <button class="card-action-btn" @click="openOpenclawEditModal(name)" :aria-label="t('openclaw.action.editAria', { name })" :title="t('openclaw.action.edit')">
118
+ <button class="card-action-btn" @click="openOpenclawEditModal(name)" :disabled="!isToolConfigWriteAllowed('openclaw')" :aria-label="t('openclaw.action.editAria', { name })" :title="t('openclaw.action.edit')">
99
119
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
100
120
  <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
101
121
  <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
@@ -113,5 +133,14 @@
113
133
  </div>
114
134
  </div>
115
135
  </section>
136
+ <div v-if="!isToolConfigWriteAllowed('openclaw')" class="tool-config-write-overlay">
137
+ <div class="tool-config-write-overlay-card">
138
+ <div class="tool-config-write-overlay-title">{{ t('toolConfig.openclaw.lockedTitle') }}</div>
139
+ <p>{{ t('toolConfig.openclaw.lockedDesc') }}</p>
140
+ <button type="button" class="btn-tool" @click="setToolConfigPermission('openclaw', true)" :disabled="toolConfigPermissionSaving.openclaw">{{ t('toolConfig.enableWrite') }}</button>
141
+ </div>
142
+ </div>
143
+ </div>
144
+ </div>
116
145
  </div>
117
146
  </div>
@@ -7,7 +7,6 @@
7
7
  <div class="selector-section">
8
8
  <div class="selector-header">
9
9
  <span class="selector-title">{{ t('docs.title') }}</span>
10
- <div class="skills-panel-note docs-section-note">{{ t('docs.subtitle') }}</div>
11
10
  </div>
12
11
 
13
12
  <div class="docs-toolbar-grid">
@@ -54,28 +53,11 @@
54
53
  <strong class="docs-summary-value">{{ installRegistryPreview || 'npmmirror' }}</strong>
55
54
  </div>
56
55
  </div>
57
-
58
- <div class="docs-installed-card">
59
- <div class="docs-installed-head">
60
- <span class="docs-installed-title">{{ t('docs.installed.title') }}</span>
61
- <span class="docs-installed-count">{{ currentInstalledCommandCards.length ? t('docs.installed.count', { count: currentInstalledCommandCards.length }) : t('docs.installed.empty') }}</span>
62
- </div>
63
- <div v-if="currentInstalledCommandCards.length" class="docs-installed-list">
64
- <div v-for="target in currentInstalledCommandCards" :key="'docs-installed-' + target.id" class="docs-installed-item">
65
- <div class="docs-installed-main">
66
- <span class="docs-installed-name">{{ target.name }}</span>
67
- <span class="docs-installed-version">{{ target.version || '—' }}</span>
68
- </div>
69
- <code class="docs-installed-command">{{ target.commandPath || target.bin }}</code>
70
- </div>
71
- </div>
72
- </div>
73
56
  </div>
74
57
 
75
58
  <div class="selector-section">
76
59
  <div class="selector-header">
77
60
  <span class="selector-title">{{ t('docs.section.commands') }}</span>
78
- <div class="skills-panel-note docs-section-note">{{ t('docs.section.commandsNote') }}</div>
79
61
  </div>
80
62
 
81
63
  <div class="install-list docs-install-list">
@@ -108,7 +90,6 @@
108
90
  <div class="selector-section">
109
91
  <div class="selector-header">
110
92
  <span class="selector-title">{{ t('docs.section.faq') }}</span>
111
- <div class="skills-panel-note docs-section-note">{{ t('docs.section.faqNote') }}</div>
112
93
  </div>
113
94
 
114
95
  <div class="docs-help-grid">
@@ -118,13 +99,6 @@
118
99
  <li v-for="tip in installTroubleshootingTips" :key="tip">{{ tip }}</li>
119
100
  </ul>
120
101
  </div>
121
- <div class="docs-note-card">
122
- <div class="docs-note-title">{{ t('common.rules') }}</div>
123
- <ul class="docs-static-list">
124
- <li>{{ t('docs.rule.1') }}</li>
125
- <li>{{ t('docs.rule.2') }}</li>
126
- </ul>
127
- </div>
128
102
  </div>
129
103
  </div>
130
104
  </div>
@@ -2249,6 +2249,28 @@ return function render(_ctx, _cache) {
2249
2249
  ]))
2250
2250
  : _createCommentVNode("v-if", true),
2251
2251
  _createElementVNode("div", { class: "openclaw-layout" }, [
2252
+ _createElementVNode("section", {
2253
+ class: "tool-config-write-card",
2254
+ "aria-label": _ctx.t('toolConfig.openclaw.title')
2255
+ }, [
2256
+ _createElementVNode("div", { class: "tool-config-write-copy" }, [
2257
+ _createElementVNode("div", { class: "tool-config-write-title" }, _toDisplayString(_ctx.t('toolConfig.openclaw.title')), 1 /* TEXT */),
2258
+ _createElementVNode("p", { class: "tool-config-write-desc" }, _toDisplayString(_ctx.t('toolConfig.openclaw.desc')), 1 /* TEXT */)
2259
+ ]),
2260
+ _createElementVNode("label", { class: "settings-toggle-row tool-config-write-toggle" }, [
2261
+ _createElementVNode("input", {
2262
+ type: "checkbox",
2263
+ autocomplete: "off",
2264
+ checked: _ctx.isToolConfigWriteAllowed('openclaw'),
2265
+ disabled: _ctx.toolConfigPermissionSaving.openclaw,
2266
+ onChange: $event => (_ctx.setToolConfigPermission('openclaw', $event.target.checked))
2267
+ }, null, 40 /* PROPS, NEED_HYDRATION */, ["checked", "disabled", "onChange"]),
2268
+ _createElementVNode("span", { class: "toggle-track" }, [
2269
+ _createElementVNode("span", { class: "toggle-thumb" })
2270
+ ]),
2271
+ _createElementVNode("span", null, _toDisplayString(_ctx.toolConfigPermissionStatusLabel('openclaw')), 1 /* TEXT */)
2272
+ ])
2273
+ ], 8 /* PROPS */, ["aria-label"]),
2252
2274
  _createElementVNode("section", {
2253
2275
  class: "settings-card settings-card--wide openclaw-summary-card",
2254
2276
  "aria-label": "OpenClaw 当前摘要"
@@ -2275,126 +2297,114 @@ return function render(_ctx, _cache) {
2275
2297
  _createElementVNode("div", { class: "openclaw-diagnostic-note" }, " 本页仅管理配置与工作区文件。 ")
2276
2298
  ])
2277
2299
  ]),
2278
- _createElementVNode("section", { class: "settings-card settings-card--wide openclaw-workspace-card" }, [
2279
- _createElementVNode("div", { class: "settings-card-body" }, [
2280
- _createElementVNode("div", { class: "openclaw-tools-grid" }, [
2281
- _createElementVNode("button", {
2282
- class: "openclaw-tool-btn",
2283
- onClick: _ctx.openOpenclawAgentsEditor,
2284
- disabled: _ctx.loading || !!_ctx.initError || _ctx.agentsLoading
2285
- }, [
2286
- _createElementVNode("div", { class: "tool-icon" }, "📄"),
2287
- _createElementVNode("div", { class: "tool-content" }, [
2288
- _createElementVNode("div", { class: "tool-title" }, "AGENTS.md"),
2289
- _createElementVNode("div", { class: "tool-meta" }, _toDisplayString(_ctx.agentsLoading ? _ctx.t('config.modelLoading') : 'Workspace file'), 1 /* TEXT */)
2290
- ]),
2291
- (_openBlock(), _createElementBlock("svg", {
2292
- class: "tool-chevron",
2293
- viewBox: "0 0 24 24",
2294
- fill: "none",
2295
- stroke: "currentColor",
2296
- "stroke-width": "2"
2297
- }, [
2298
- _createElementVNode("path", { d: "M9 18l6-6-6-6" })
2299
- ]))
2300
- ], 8 /* PROPS */, ["onClick", "disabled"]),
2301
- (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.getOpenclawQuickWorkspaceFiles(), (fileName) => {
2302
- return (_openBlock(), _createElementBlock("button", {
2303
- key: fileName,
2304
- type: "button",
2305
- class: "openclaw-tool-btn",
2306
- onClick: $event => (_ctx.openOpenclawQuickWorkspaceFile(fileName)),
2307
- disabled: _ctx.loading || !!_ctx.initError || _ctx.agentsLoading
2308
- }, [
2309
- _createElementVNode("div", { class: "tool-icon" }, "📄"),
2310
- _createElementVNode("div", { class: "tool-content" }, [
2311
- _createElementVNode("div", { class: "tool-title" }, _toDisplayString(fileName), 1 /* TEXT */),
2312
- _createElementVNode("div", { class: "tool-meta" }, "Workspace file")
2313
- ]),
2314
- (_openBlock(), _createElementBlock("svg", {
2315
- class: "tool-chevron",
2316
- viewBox: "0 0 24 24",
2317
- fill: "none",
2318
- stroke: "currentColor",
2319
- "stroke-width": "2"
2320
- }, [
2321
- _createElementVNode("path", { d: "M9 18l6-6-6-6" })
2322
- ]))
2323
- ], 8 /* PROPS */, ["onClick", "disabled"]))
2324
- }), 128 /* KEYED_FRAGMENT */))
2325
- ])
2326
- ])
2327
- ]),
2328
- _createElementVNode("section", {
2329
- class: "settings-card settings-card--wide openclaw-configs-card",
2330
- "aria-labelledby": "openclaw-configs-title"
2300
+ _createElementVNode("div", {
2301
+ class: _normalizeClass(["tool-config-write-scope", { locked: !_ctx.isToolConfigWriteAllowed('openclaw') }])
2331
2302
  }, [
2332
- _createElementVNode("div", { class: "settings-card-body" }, [
2333
- _createElementVNode("div", { class: "card-list openclaw-card-list" }, [
2334
- (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.openclawConfigs, (config, name) => {
2335
- return (_openBlock(), _createElementBlock("div", {
2336
- key: name,
2337
- class: _normalizeClass(['card', { active: _ctx.currentOpenclawConfig === name }]),
2338
- onClick: $event => (_ctx.applyOpenclawConfig(name)),
2339
- onKeydown: [
2340
- _withKeys(_withModifiers($event => (_ctx.applyOpenclawConfig(name)), ["self","prevent"]), ["enter"]),
2341
- _withKeys(_withModifiers($event => (_ctx.applyOpenclawConfig(name)), ["self","prevent"]), ["space"])
2342
- ],
2343
- tabindex: "0",
2344
- role: "button",
2345
- "aria-label": _ctx.t('openclaw.action.applyAria', { name }),
2346
- "aria-current": _ctx.currentOpenclawConfig === name ? 'true' : null
2347
- }, [
2348
- _createElementVNode("div", { class: "card-leading" }, [
2349
- _createElementVNode("div", { class: "card-icon" }, _toDisplayString(name.charAt(0).toUpperCase()), 1 /* TEXT */),
2350
- _createElementVNode("div", { class: "card-content" }, [
2351
- _createElementVNode("div", { class: "card-title" }, _toDisplayString(name), 1 /* TEXT */),
2352
- _createElementVNode("div", { class: "card-subtitle" }, _toDisplayString(_ctx.openclawSubtitle(config)), 1 /* TEXT */),
2353
- (_ctx.openclawHasContent(config))
2354
- ? (_openBlock(), _createElementBlock("div", {
2355
- key: 0,
2356
- class: "openclaw-config-summary-mini"
2357
- }, [
2358
- (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.getOpenclawConfigSummary(config).slice(0, 3), (item) => {
2359
- return (_openBlock(), _createElementBlock("span", {
2360
- key: item.key
2361
- }, _toDisplayString(item.label) + ": " + _toDisplayString(item.value), 1 /* TEXT */))
2362
- }), 128 /* KEYED_FRAGMENT */))
2363
- ]))
2364
- : _createCommentVNode("v-if", true)
2365
- ])
2366
- ]),
2367
- _createElementVNode("div", { class: "card-trailing" }, [
2368
- _createElementVNode("span", {
2369
- class: _normalizeClass(['pill', _ctx.openclawHasContent(config) ? 'configured' : 'empty'])
2370
- }, _toDisplayString(_ctx.openclawHasContent(config) ? _ctx.t('openclaw.configured') : _ctx.t('openclaw.notConfigured')), 3 /* TEXT, CLASS */),
2371
- _createElementVNode("div", {
2372
- class: "card-actions",
2373
- onClick: _withModifiers(() => {}, ["stop"])
2303
+ _createElementVNode("div", { class: "tool-config-write-body" }, [
2304
+ _createElementVNode("section", { class: "settings-card settings-card--wide openclaw-workspace-card" }, [
2305
+ _createElementVNode("div", { class: "settings-card-body" }, [
2306
+ _createElementVNode("div", { class: "openclaw-tools-grid" }, [
2307
+ _createElementVNode("button", {
2308
+ class: "openclaw-tool-btn",
2309
+ onClick: _ctx.openOpenclawAgentsEditor,
2310
+ disabled: _ctx.loading || !!_ctx.initError || _ctx.agentsLoading || !_ctx.isToolConfigWriteAllowed('openclaw')
2311
+ }, [
2312
+ _createElementVNode("div", { class: "tool-icon" }, "📄"),
2313
+ _createElementVNode("div", { class: "tool-content" }, [
2314
+ _createElementVNode("div", { class: "tool-title" }, "AGENTS.md"),
2315
+ _createElementVNode("div", { class: "tool-meta" }, _toDisplayString(_ctx.agentsLoading ? _ctx.t('config.modelLoading') : 'Workspace file'), 1 /* TEXT */)
2316
+ ]),
2317
+ (_openBlock(), _createElementBlock("svg", {
2318
+ class: "tool-chevron",
2319
+ viewBox: "0 0 24 24",
2320
+ fill: "none",
2321
+ stroke: "currentColor",
2322
+ "stroke-width": "2"
2374
2323
  }, [
2375
- _createElementVNode("button", {
2376
- class: "card-action-btn",
2377
- onClick: $event => (_ctx.openOpenclawEditModal(name)),
2378
- "aria-label": _ctx.t('openclaw.action.editAria', { name }),
2379
- title: _ctx.t('openclaw.action.edit')
2324
+ _createElementVNode("path", { d: "M9 18l6-6-6-6" })
2325
+ ]))
2326
+ ], 8 /* PROPS */, ["onClick", "disabled"]),
2327
+ (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.getOpenclawQuickWorkspaceFiles(), (fileName) => {
2328
+ return (_openBlock(), _createElementBlock("button", {
2329
+ key: fileName,
2330
+ type: "button",
2331
+ class: "openclaw-tool-btn",
2332
+ onClick: $event => (_ctx.openOpenclawQuickWorkspaceFile(fileName)),
2333
+ disabled: _ctx.loading || !!_ctx.initError || _ctx.agentsLoading || !_ctx.isToolConfigWriteAllowed('openclaw')
2334
+ }, [
2335
+ _createElementVNode("div", { class: "tool-icon" }, "📄"),
2336
+ _createElementVNode("div", { class: "tool-content" }, [
2337
+ _createElementVNode("div", { class: "tool-title" }, _toDisplayString(fileName), 1 /* TEXT */),
2338
+ _createElementVNode("div", { class: "tool-meta" }, "Workspace file")
2339
+ ]),
2340
+ (_openBlock(), _createElementBlock("svg", {
2341
+ class: "tool-chevron",
2342
+ viewBox: "0 0 24 24",
2343
+ fill: "none",
2344
+ stroke: "currentColor",
2345
+ "stroke-width": "2"
2380
2346
  }, [
2381
- (_openBlock(), _createElementBlock("svg", {
2382
- viewBox: "0 0 24 24",
2383
- fill: "none",
2384
- stroke: "currentColor",
2385
- "stroke-width": "2"
2347
+ _createElementVNode("path", { d: "M9 18l6-6-6-6" })
2348
+ ]))
2349
+ ], 8 /* PROPS */, ["onClick", "disabled"]))
2350
+ }), 128 /* KEYED_FRAGMENT */))
2351
+ ])
2352
+ ])
2353
+ ]),
2354
+ _createElementVNode("section", {
2355
+ class: "settings-card settings-card--wide openclaw-configs-card",
2356
+ "aria-labelledby": "openclaw-configs-title"
2357
+ }, [
2358
+ _createElementVNode("div", { class: "settings-card-body" }, [
2359
+ _createElementVNode("div", { class: "card-list openclaw-card-list" }, [
2360
+ (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.openclawConfigs, (config, name) => {
2361
+ return (_openBlock(), _createElementBlock("div", {
2362
+ key: name,
2363
+ class: _normalizeClass(['card', { active: _ctx.currentOpenclawConfig === name, disabled: !_ctx.isToolConfigWriteAllowed('openclaw') }]),
2364
+ onClick: $event => (_ctx.isToolConfigWriteAllowed('openclaw') && _ctx.applyOpenclawConfig(name)),
2365
+ onKeydown: [
2366
+ _withKeys(_withModifiers($event => (_ctx.isToolConfigWriteAllowed('openclaw') && _ctx.applyOpenclawConfig(name)), ["self","prevent"]), ["enter"]),
2367
+ _withKeys(_withModifiers($event => (_ctx.isToolConfigWriteAllowed('openclaw') && _ctx.applyOpenclawConfig(name)), ["self","prevent"]), ["space"])
2368
+ ],
2369
+ tabindex: _ctx.isToolConfigWriteAllowed('openclaw') ? 0 : -1,
2370
+ role: "button",
2371
+ "aria-label": _ctx.t('openclaw.action.applyAria', { name }),
2372
+ "aria-disabled": !_ctx.isToolConfigWriteAllowed('openclaw') ? 'true' : null,
2373
+ "aria-current": _ctx.currentOpenclawConfig === name ? 'true' : null
2374
+ }, [
2375
+ _createElementVNode("div", { class: "card-leading" }, [
2376
+ _createElementVNode("div", { class: "card-icon" }, _toDisplayString(name.charAt(0).toUpperCase()), 1 /* TEXT */),
2377
+ _createElementVNode("div", { class: "card-content" }, [
2378
+ _createElementVNode("div", { class: "card-title" }, _toDisplayString(name), 1 /* TEXT */),
2379
+ _createElementVNode("div", { class: "card-subtitle" }, _toDisplayString(_ctx.openclawSubtitle(config)), 1 /* TEXT */),
2380
+ (_ctx.openclawHasContent(config))
2381
+ ? (_openBlock(), _createElementBlock("div", {
2382
+ key: 0,
2383
+ class: "openclaw-config-summary-mini"
2384
+ }, [
2385
+ (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.getOpenclawConfigSummary(config).slice(0, 3), (item) => {
2386
+ return (_openBlock(), _createElementBlock("span", {
2387
+ key: item.key
2388
+ }, _toDisplayString(item.label) + ": " + _toDisplayString(item.value), 1 /* TEXT */))
2389
+ }), 128 /* KEYED_FRAGMENT */))
2390
+ ]))
2391
+ : _createCommentVNode("v-if", true)
2392
+ ])
2393
+ ]),
2394
+ _createElementVNode("div", { class: "card-trailing" }, [
2395
+ _createElementVNode("span", {
2396
+ class: _normalizeClass(['pill', _ctx.openclawHasContent(config) ? 'configured' : 'empty'])
2397
+ }, _toDisplayString(_ctx.openclawHasContent(config) ? _ctx.t('openclaw.configured') : _ctx.t('openclaw.notConfigured')), 3 /* TEXT, CLASS */),
2398
+ _createElementVNode("div", {
2399
+ class: "card-actions",
2400
+ onClick: _withModifiers(() => {}, ["stop"])
2386
2401
  }, [
2387
- _createElementVNode("path", { d: "M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" }),
2388
- _createElementVNode("path", { d: "M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" })
2389
- ]))
2390
- ], 8 /* PROPS */, ["onClick", "aria-label", "title"]),
2391
- (!_ctx.isDefaultOpenclawConfig(name, config))
2392
- ? (_openBlock(), _createElementBlock("button", {
2393
- key: 0,
2394
- class: "card-action-btn delete",
2395
- onClick: $event => (_ctx.deleteOpenclawConfig(name)),
2396
- "aria-label": _ctx.t('openclaw.action.deleteAria', { name }),
2397
- title: _ctx.t('openclaw.action.delete')
2402
+ _createElementVNode("button", {
2403
+ class: "card-action-btn",
2404
+ onClick: $event => (_ctx.openOpenclawEditModal(name)),
2405
+ disabled: !_ctx.isToolConfigWriteAllowed('openclaw'),
2406
+ "aria-label": _ctx.t('openclaw.action.editAria', { name }),
2407
+ title: _ctx.t('openclaw.action.edit')
2398
2408
  }, [
2399
2409
  (_openBlock(), _createElementBlock("svg", {
2400
2410
  viewBox: "0 0 24 24",
@@ -2402,18 +2412,55 @@ return function render(_ctx, _cache) {
2402
2412
  stroke: "currentColor",
2403
2413
  "stroke-width": "2"
2404
2414
  }, [
2405
- _createElementVNode("path", { d: "M3 6h18" }),
2406
- _createElementVNode("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })
2415
+ _createElementVNode("path", { d: "M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" }),
2416
+ _createElementVNode("path", { d: "M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" })
2407
2417
  ]))
2408
- ], 8 /* PROPS */, ["onClick", "aria-label", "title"]))
2409
- : _createCommentVNode("v-if", true)
2410
- ], 8 /* PROPS */, ["onClick"])
2418
+ ], 8 /* PROPS */, ["onClick", "disabled", "aria-label", "title"]),
2419
+ (!_ctx.isDefaultOpenclawConfig(name, config))
2420
+ ? (_openBlock(), _createElementBlock("button", {
2421
+ key: 0,
2422
+ class: "card-action-btn delete",
2423
+ onClick: $event => (_ctx.deleteOpenclawConfig(name)),
2424
+ "aria-label": _ctx.t('openclaw.action.deleteAria', { name }),
2425
+ title: _ctx.t('openclaw.action.delete')
2426
+ }, [
2427
+ (_openBlock(), _createElementBlock("svg", {
2428
+ viewBox: "0 0 24 24",
2429
+ fill: "none",
2430
+ stroke: "currentColor",
2431
+ "stroke-width": "2"
2432
+ }, [
2433
+ _createElementVNode("path", { d: "M3 6h18" }),
2434
+ _createElementVNode("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })
2435
+ ]))
2436
+ ], 8 /* PROPS */, ["onClick", "aria-label", "title"]))
2437
+ : _createCommentVNode("v-if", true)
2438
+ ], 8 /* PROPS */, ["onClick"])
2439
+ ])
2440
+ ], 42 /* CLASS, PROPS, NEED_HYDRATION */, ["onClick", "onKeydown", "tabindex", "aria-label", "aria-disabled", "aria-current"]))
2441
+ }), 128 /* KEYED_FRAGMENT */))
2442
+ ])
2443
+ ])
2444
+ ]),
2445
+ (!_ctx.isToolConfigWriteAllowed('openclaw'))
2446
+ ? (_openBlock(), _createElementBlock("div", {
2447
+ key: 0,
2448
+ class: "tool-config-write-overlay"
2449
+ }, [
2450
+ _createElementVNode("div", { class: "tool-config-write-overlay-card" }, [
2451
+ _createElementVNode("div", { class: "tool-config-write-overlay-title" }, _toDisplayString(_ctx.t('toolConfig.openclaw.lockedTitle')), 1 /* TEXT */),
2452
+ _createElementVNode("p", null, _toDisplayString(_ctx.t('toolConfig.openclaw.lockedDesc')), 1 /* TEXT */),
2453
+ _createElementVNode("button", {
2454
+ type: "button",
2455
+ class: "btn-tool",
2456
+ onClick: $event => (_ctx.setToolConfigPermission('openclaw', true)),
2457
+ disabled: _ctx.toolConfigPermissionSaving.openclaw
2458
+ }, _toDisplayString(_ctx.t('toolConfig.enableWrite')), 9 /* TEXT, PROPS */, ["onClick", "disabled"])
2411
2459
  ])
2412
- ], 42 /* CLASS, PROPS, NEED_HYDRATION */, ["onClick", "onKeydown", "aria-label", "aria-current"]))
2413
- }), 128 /* KEYED_FRAGMENT */))
2414
- ])
2460
+ ]))
2461
+ : _createCommentVNode("v-if", true)
2415
2462
  ])
2416
- ])
2463
+ ], 2 /* CLASS */)
2417
2464
  ])
2418
2465
  ], 8 /* PROPS */, ["aria-labelledby"]), [
2419
2466
  [_vShow, _ctx.mainTab === 'config' && _ctx.configMode === 'openclaw']
@@ -5418,8 +5465,7 @@ return function render(_ctx, _cache) {
5418
5465
  }, [
5419
5466
  _createElementVNode("div", { class: "selector-section" }, [
5420
5467
  _createElementVNode("div", { class: "selector-header" }, [
5421
- _createElementVNode("span", { class: "selector-title" }, _toDisplayString(_ctx.t('docs.title')), 1 /* TEXT */),
5422
- _createElementVNode("div", { class: "skills-panel-note docs-section-note" }, _toDisplayString(_ctx.t('docs.subtitle')), 1 /* TEXT */)
5468
+ _createElementVNode("span", { class: "selector-title" }, _toDisplayString(_ctx.t('docs.title')), 1 /* TEXT */)
5423
5469
  ]),
5424
5470
  _createElementVNode("div", { class: "docs-toolbar-grid" }, [
5425
5471
  _createElementVNode("div", { class: "docs-toolbar-card" }, [
@@ -5514,37 +5560,11 @@ return function render(_ctx, _cache) {
5514
5560
  _createElementVNode("span", { class: "docs-summary-label" }, _toDisplayString(_ctx.t('common.registry')), 1 /* TEXT */),
5515
5561
  _createElementVNode("strong", { class: "docs-summary-value" }, _toDisplayString(_ctx.installRegistryPreview || 'npmmirror'), 1 /* TEXT */)
5516
5562
  ])
5517
- ]),
5518
- _createElementVNode("div", { class: "docs-installed-card" }, [
5519
- _createElementVNode("div", { class: "docs-installed-head" }, [
5520
- _createElementVNode("span", { class: "docs-installed-title" }, _toDisplayString(_ctx.t('docs.installed.title')), 1 /* TEXT */),
5521
- _createElementVNode("span", { class: "docs-installed-count" }, _toDisplayString(_ctx.currentInstalledCommandCards.length ? _ctx.t('docs.installed.count', { count: _ctx.currentInstalledCommandCards.length }) : _ctx.t('docs.installed.empty')), 1 /* TEXT */)
5522
- ]),
5523
- (_ctx.currentInstalledCommandCards.length)
5524
- ? (_openBlock(), _createElementBlock("div", {
5525
- key: 0,
5526
- class: "docs-installed-list"
5527
- }, [
5528
- (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.currentInstalledCommandCards, (target) => {
5529
- return (_openBlock(), _createElementBlock("div", {
5530
- key: 'docs-installed-' + target.id,
5531
- class: "docs-installed-item"
5532
- }, [
5533
- _createElementVNode("div", { class: "docs-installed-main" }, [
5534
- _createElementVNode("span", { class: "docs-installed-name" }, _toDisplayString(target.name), 1 /* TEXT */),
5535
- _createElementVNode("span", { class: "docs-installed-version" }, _toDisplayString(target.version || '—'), 1 /* TEXT */)
5536
- ]),
5537
- _createElementVNode("code", { class: "docs-installed-command" }, _toDisplayString(target.commandPath || target.bin), 1 /* TEXT */)
5538
- ]))
5539
- }), 128 /* KEYED_FRAGMENT */))
5540
- ]))
5541
- : _createCommentVNode("v-if", true)
5542
5563
  ])
5543
5564
  ]),
5544
5565
  _createElementVNode("div", { class: "selector-section" }, [
5545
5566
  _createElementVNode("div", { class: "selector-header" }, [
5546
- _createElementVNode("span", { class: "selector-title" }, _toDisplayString(_ctx.t('docs.section.commands')), 1 /* TEXT */),
5547
- _createElementVNode("div", { class: "skills-panel-note docs-section-note" }, _toDisplayString(_ctx.t('docs.section.commandsNote')), 1 /* TEXT */)
5567
+ _createElementVNode("span", { class: "selector-title" }, _toDisplayString(_ctx.t('docs.section.commands')), 1 /* TEXT */)
5548
5568
  ]),
5549
5569
  _createElementVNode("div", { class: "install-list docs-install-list" }, [
5550
5570
  (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.installTargetCards, (target) => {
@@ -5604,8 +5624,7 @@ return function render(_ctx, _cache) {
5604
5624
  ]),
5605
5625
  _createElementVNode("div", { class: "selector-section" }, [
5606
5626
  _createElementVNode("div", { class: "selector-header" }, [
5607
- _createElementVNode("span", { class: "selector-title" }, _toDisplayString(_ctx.t('docs.section.faq')), 1 /* TEXT */),
5608
- _createElementVNode("div", { class: "skills-panel-note docs-section-note" }, _toDisplayString(_ctx.t('docs.section.faqNote')), 1 /* TEXT */)
5627
+ _createElementVNode("span", { class: "selector-title" }, _toDisplayString(_ctx.t('docs.section.faq')), 1 /* TEXT */)
5609
5628
  ]),
5610
5629
  _createElementVNode("div", { class: "docs-help-grid" }, [
5611
5630
  _createElementVNode("div", { class: "docs-note-card" }, [
@@ -5615,13 +5634,6 @@ return function render(_ctx, _cache) {
5615
5634
  return (_openBlock(), _createElementBlock("li", { key: tip }, _toDisplayString(tip), 1 /* TEXT */))
5616
5635
  }), 128 /* KEYED_FRAGMENT */))
5617
5636
  ])
5618
- ]),
5619
- _createElementVNode("div", { class: "docs-note-card" }, [
5620
- _createElementVNode("div", { class: "docs-note-title" }, _toDisplayString(_ctx.t('common.rules')), 1 /* TEXT */),
5621
- _createElementVNode("ul", { class: "docs-static-list" }, [
5622
- _createElementVNode("li", null, _toDisplayString(_ctx.t('docs.rule.1')), 1 /* TEXT */),
5623
- _createElementVNode("li", null, _toDisplayString(_ctx.t('docs.rule.2')), 1 /* TEXT */)
5624
- ])
5625
5637
  ])
5626
5638
  ])
5627
5639
  ])
@@ -8,15 +8,16 @@
8
8
  gap: 16px;
9
9
  }
10
10
 
11
- /* ---- Toolbar grid ---- */
11
+ /* ---- Toolbar grid ----
12
+ 三张配置卡(PM / Mirror / Action)等列宽分占,避免
13
+ 此前 span4×span8×span8 带来的重心右偏与左侧留白。 */
12
14
  .docs-toolbar-grid {
13
15
  display: grid;
14
- grid-template-columns: repeat(12, minmax(0, 1fr));
16
+ grid-template-columns: repeat(3, minmax(0, 1fr));
15
17
  gap: 10px;
16
18
  }
17
19
 
18
20
  .docs-toolbar-card {
19
- grid-column: span 4;
20
21
  display: flex;
21
22
  flex-direction: column;
22
23
  gap: 8px;
@@ -27,13 +28,48 @@
27
28
  }
28
29
 
29
30
  .docs-toolbar-card-wide {
30
- grid-column: span 8;
31
+ /* 历史遗留的宽卡类,等宽网格下不再需要额外跨度,
32
+ 保留类名以兼容模板中的引用。 */
33
+ grid-column: auto;
31
34
  }
32
35
 
33
- /* ---- Summary strip ---- */
36
+ /* Segmented control:把 install/registry 的散落 btn-mini
37
+ 收敛成带容器边框的成组按钮,弱化“一堆小按钮”观感。 */
38
+ .docs-toolbar-card .install-action-tabs {
39
+ display: inline-flex;
40
+ flex-wrap: wrap;
41
+ gap: 4px;
42
+ padding: 4px;
43
+ border: 1px solid var(--color-border-soft);
44
+ border-radius: var(--radius-sm);
45
+ background: var(--color-bg-soft);
46
+ }
47
+
48
+ .docs-toolbar-card .install-action-tabs .btn-mini {
49
+ border-color: transparent;
50
+ background: transparent;
51
+ box-shadow: none;
52
+ padding: 6px 12px;
53
+ }
54
+
55
+ .docs-toolbar-card .install-action-tabs .btn-mini:hover {
56
+ border-color: var(--color-border-soft);
57
+ background: var(--color-surface);
58
+ transform: none;
59
+ }
60
+
61
+ .docs-toolbar-card .install-action-tabs .btn-mini.active {
62
+ border-color: rgba(200, 121, 99, 0.22);
63
+ background: var(--color-surface);
64
+ box-shadow: var(--shadow-subtle);
65
+ }
66
+
67
+ /* ---- Summary strip ----
68
+ 原为 4 列网格但仅有 3 个 item,末列长期空置。改为
69
+ 3 列等宽,composition 直接对齐内容数量。 */
34
70
  .docs-summary-strip {
35
71
  display: grid;
36
- grid-template-columns: repeat(4, minmax(0, 1fr));
72
+ grid-template-columns: repeat(3, minmax(0, 1fr));
37
73
  gap: 10px;
38
74
  margin-top: 2px;
39
75
  }
@@ -48,8 +84,9 @@
48
84
  background: var(--color-surface);
49
85
  }
50
86
 
87
+ /* 三列等宽后不再需要额外跨度,保留类名兼容模板引用。 */
51
88
  .docs-summary-item-wide {
52
- grid-column: span 2;
89
+ grid-column: auto;
53
90
  }
54
91
 
55
92
  .docs-summary-label {
@@ -69,57 +106,6 @@
69
106
  word-break: break-word;
70
107
  }
71
108
 
72
- .docs-installed-card {
73
- margin-top: 12px;
74
- padding: 12px;
75
- border: 1px solid var(--color-border-soft);
76
- border-radius: var(--radius-md);
77
- background: var(--color-bg-soft);
78
- }
79
-
80
- .docs-installed-head,
81
- .docs-installed-main {
82
- display: flex;
83
- align-items: center;
84
- justify-content: space-between;
85
- gap: 10px;
86
- }
87
-
88
- .docs-installed-title,
89
- .docs-installed-name {
90
- font-weight: 700;
91
- color: var(--color-text-primary);
92
- }
93
-
94
- .docs-installed-count,
95
- .docs-installed-version {
96
- font-size: 12px;
97
- color: var(--color-text-muted);
98
- }
99
-
100
- .docs-installed-list {
101
- display: grid;
102
- gap: 8px;
103
- margin-top: 10px;
104
- }
105
-
106
- .docs-installed-item {
107
- min-width: 0;
108
- padding: 10px;
109
- border-radius: var(--radius-sm);
110
- background: var(--color-bg-card);
111
- }
112
-
113
- .docs-installed-command {
114
- display: block;
115
- margin-top: 6px;
116
- overflow: hidden;
117
- text-overflow: ellipsis;
118
- white-space: nowrap;
119
- font-size: 12px;
120
- color: var(--color-text-secondary);
121
- }
122
-
123
109
  /* ---- Install rows ---- */
124
110
  .docs-install-list {
125
111
  display: flex;
@@ -155,7 +141,7 @@
155
141
  display: flex;
156
142
  align-items: center;
157
143
  gap: 10px;
158
- padding: 10px 14px;
144
+ padding: 8px 8px 8px 14px;
159
145
  border: 1px solid var(--color-border-soft);
160
146
  border-radius: var(--radius-sm);
161
147
  background: var(--color-surface-alt);
@@ -163,18 +149,21 @@
163
149
  max-width: 100%;
164
150
  }
165
151
 
152
+ /* 去框中框:box 本体已承担容器层,命令文本不再叠
153
+ 二次背景/边框,降低视觉噪音、与终端观感对齐。 */
166
154
  .docs-command-box .install-command {
167
155
  flex: 1;
168
156
  min-width: 0;
169
- padding: 8px 12px;
170
- border-radius: var(--radius-sm);
171
- background: var(--color-surface);
172
- border: 1px solid var(--color-border-soft);
157
+ padding: 0;
158
+ border-radius: 0;
159
+ background: transparent;
160
+ border: 0;
173
161
  white-space: normal;
174
162
  word-break: break-all;
175
163
  overflow-wrap: break-word;
176
164
  font-size: 13px;
177
165
  line-height: 1.5;
166
+ color: var(--color-text-primary);
178
167
  font-family: var(--font-family-mono);
179
168
  user-select: all;
180
169
  }
@@ -226,9 +215,17 @@
226
215
  display: grid;
227
216
  grid-template-columns: repeat(2, minmax(0, 1fr));
228
217
  gap: 12px;
218
+ align-items: stretch;
219
+ }
220
+
221
+ /* 仅剩 troubleshooting 卡时,单卡占满整行,避免右侧空置。 */
222
+ .docs-help-grid > .docs-note-card:only-child {
223
+ grid-column: 1 / -1;
229
224
  }
230
225
 
231
226
  .docs-note-card {
227
+ display: flex;
228
+ flex-direction: column;
232
229
  padding: 16px;
233
230
  border: 1px solid var(--color-border-soft);
234
231
  border-radius: var(--radius-md);
@@ -246,46 +243,34 @@
246
243
  margin: 0;
247
244
  }
248
245
 
249
- .docs-static-list {
250
- margin: 0;
251
- padding-left: 18px;
252
- color: var(--color-text-secondary);
253
- font-size: 13px;
254
- line-height: 1.6;
255
- }
256
-
257
- .docs-static-list li + li {
258
- margin-top: 8px;
259
- }
260
-
261
- .docs-section-note {
262
- margin-top: 4px;
263
- }
264
-
265
246
  /* ---- Responsive ---- */
266
247
  @media (max-width: 1100px) {
267
- .docs-toolbar-card,
268
- .docs-toolbar-card-wide {
269
- grid-column: span 12;
270
- }
271
-
272
- .docs-summary-strip {
248
+ .docs-toolbar-grid {
249
+ /* PM 单占一行,mirror/action 并排占第二行,避免三卡齐挤窄列。 */
273
250
  grid-template-columns: repeat(2, minmax(0, 1fr));
274
251
  }
275
252
 
276
- .docs-summary-item-wide {
253
+ .docs-toolbar-grid > .docs-toolbar-card:first-child {
277
254
  grid-column: span 2;
278
255
  }
256
+
257
+ .docs-summary-strip {
258
+ grid-template-columns: repeat(3, minmax(0, 1fr));
259
+ }
279
260
  }
280
261
 
281
262
  @media (max-width: 720px) {
282
- .docs-summary-strip,
283
- .docs-help-grid {
263
+ .docs-toolbar-grid {
284
264
  grid-template-columns: 1fr;
285
265
  }
286
266
 
287
- .docs-summary-item-wide {
288
- grid-column: span 1;
267
+ .docs-toolbar-grid > .docs-toolbar-card:first-child {
268
+ grid-column: auto;
269
+ }
270
+
271
+ .docs-summary-strip,
272
+ .docs-help-grid {
273
+ grid-template-columns: 1fr;
289
274
  }
290
275
 
291
276
  .docs-install-row,