codexmate 0.1.14 → 0.1.15

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.1.14",
3
+ "version": "0.1.15",
4
4
  "description": "Codex/Claude Code/OpenClaw 配置、会话与任务编排 CLI + Web 工具",
5
5
  "main": "cli.js",
6
6
  "bin": {
package/web-ui/app.js CHANGED
@@ -819,10 +819,7 @@ document.addEventListener('DOMContentLoaded', () => {
819
819
  if (typeof this.persistWebUiPreferences === 'function') {
820
820
  this.persistWebUiPreferences({ sysPromptMode: newVal });
821
821
  }
822
- }
823
- },
824
-
825
- watch: {
822
+ },
826
823
  configMode(newMode) {
827
824
  if (newMode === 'pi' && typeof this.loadPiSources === 'function') {
828
825
  this.loadPiSources();
@@ -471,6 +471,18 @@ export function createAgentsMethods(options = {}) {
471
471
  .filter(Boolean)
472
472
  .filter(function (v, i, a) { return a.indexOf(v) === i; });
473
473
  }
474
+ if (this.promptsSubTab === 'claude-project'
475
+ && this.mainTab === 'prompts'
476
+ && Array.isArray(this.projectPathOptions)
477
+ && this.projectPathOptions.length) {
478
+ const currentPath = (this.projectClaudeMdPath || '').trim();
479
+ if (currentPath && this.projectPathOptions.indexOf(currentPath) !== -1) {
480
+ this.projectClaudeMdPath = currentPath;
481
+ } else {
482
+ this.projectClaudeMdPath = this.projectPathOptions[0];
483
+ }
484
+ if (typeof this.loadPromptsContent === 'function') this.loadPromptsContent();
485
+ }
474
486
  } catch (_) {
475
487
  // silent
476
488
  } finally {
@@ -1015,7 +1027,11 @@ export function createAgentsMethods(options = {}) {
1015
1027
  if (!this.projectPathOptions.length && !this.projectPathOptionsLoading && typeof this.loadProjectPathOptions === 'function') {
1016
1028
  this.loadProjectPathOptions();
1017
1029
  }
1018
- const projectPath = (this.projectClaudeMdPath || '').trim();
1030
+ let projectPath = (this.projectClaudeMdPath || '').trim();
1031
+ if (!projectPath && Array.isArray(this.projectPathOptions) && this.projectPathOptions.length) {
1032
+ this.projectClaudeMdPath = this.projectPathOptions[0];
1033
+ projectPath = this.projectClaudeMdPath.trim();
1034
+ }
1019
1035
  if (projectPath) {
1020
1036
  rpcParams.baseDir = projectPath;
1021
1037
  }
@@ -81,24 +81,13 @@ export function createPiConfigMethods({ api: apiClient }) {
81
81
  this.piSaving = true;
82
82
  try {
83
83
  const providerId = this.editingPiProvider.id;
84
- const values = this.editingPiProvider.form;
85
- const extras = this.editingPiProvider.extras || {};
86
- const provider = this.piProviders[providerId] || {};
87
-
88
- const merged = {
89
- ...extras,
90
- baseUrl: values.baseUrl,
91
- api: values.api,
92
- apiKey: values.apiKey || '',
93
- models: (Array.isArray(values.models) ? values.models : []).map((model) => ({
94
- ...model,
95
- id: model.id || '',
96
- name: model.id || ''
97
- }))
98
- };
99
- if (isPiPlainObject(provider.headers)) merged.headers = provider.headers;
100
- if (typeof provider.title === 'string') merged.title = provider.title;
101
- else if (typeof provider.name === 'string') merged.name = provider.name;
84
+ const { merged, ok, error } = this.piBuildMergedEditorRecord();
85
+ if (!ok || !merged) {
86
+ this.piEditorJsonError = error || '配置 JSON 不合法';
87
+ this.message = this.piEditorJsonError;
88
+ this.messageType = 'error';
89
+ return;
90
+ }
102
91
 
103
92
  await this.persistPiProvider(providerId, merged);
104
93
  this.piProviders = { ...this.piProviders, [providerId]: merged };
@@ -232,6 +221,7 @@ export function createPiConfigMethods({ api: apiClient }) {
232
221
  this.piRemoteModels = [];
233
222
  this.piRemoteModelError = '';
234
223
  this.piModelSearch = '';
224
+ this.piEditorJsonError = '';
235
225
  const provider = this.piProviders[providerId] || {};
236
226
  const knownKeys = ['id', 'name', 'title', 'baseUrl', 'api', 'apiKey', 'models', 'headers', 'configJson'];
237
227
  const extras = {};
@@ -269,6 +259,7 @@ export function createPiConfigMethods({ api: apiClient }) {
269
259
  this.piRemoteModels = [];
270
260
  this.piRemoteModelError = '';
271
261
  this.piModelSearch = '';
262
+ this.piEditorJsonError = '';
272
263
  },
273
264
  removePiProviderModel(index) {
274
265
  if (!this.editingPiProvider) return;
@@ -350,5 +341,57 @@ export function createPiConfigMethods({ api: apiClient }) {
350
341
  const api = provider.api || '';
351
342
  return [baseUrl, api].filter(Boolean).join(' • ') || 'Piper provider';
352
343
  }
344
+ ,
345
+ piParseEditorJsonDraft() {
346
+ const provider = this.editingPiProvider;
347
+ const draft = provider && provider.form ? String(provider.form.configJsonDraft || '').trim() : '';
348
+ if (!draft) return { ok: true, extras: {} };
349
+ try {
350
+ const parsed = JSON.parse(draft);
351
+ if (parsed === null || Array.isArray(parsed) || typeof parsed !== 'object') {
352
+ return { ok: false, extras: {}, error: '配置 JSON 必须是对象' };
353
+ }
354
+ return { ok: true, extras: parsed };
355
+ } catch (e) {
356
+ return { ok: false, extras: {}, error: e && e.message ? '配置 JSON 解析失败:' + e.message : '配置 JSON 解析失败' };
357
+ }
358
+ },
359
+ piBuildMergedEditorRecord() {
360
+ const provider = this.editingPiProvider;
361
+ if (!provider || !provider.form) return { merged: null, ok: false, error: '未在编辑供应商', extras: {} };
362
+ const draft = this.piParseEditorJsonDraft();
363
+ if (!draft.ok) return { merged: null, ok: false, error: draft.error, extras: {} };
364
+ const values = provider.form || {};
365
+ const extras = draft.extras || {};
366
+ const orig = this.piProviders[provider.id] || {};
367
+ const mapModels = (xs) => (Array.isArray(xs) ? xs : []).map((model) => ({
368
+ ...model,
369
+ id: (model && model.id) || '',
370
+ name: (model && (model.name || model.id)) || ''
371
+ }));
372
+ const merged = { ...extras };
373
+ if (merged.baseUrl === undefined) merged.baseUrl = values.baseUrl || '';
374
+ if (merged.api === undefined) merged.api = values.api || '';
375
+ if (merged.apiKey === undefined) merged.apiKey = values.apiKey || '';
376
+ if (merged.models === undefined) merged.models = mapModels(values.models);
377
+ if (isPiPlainObject(orig.headers)) merged.headers = orig.headers;
378
+ if (typeof orig.title === 'string') merged.title = orig.title;
379
+ else if (typeof orig.name === 'string') merged.name = orig.name;
380
+ if (isPiPlainObject(orig.configJson)) merged.configJson = orig.configJson;
381
+ return { merged, ok: true, error: '', extras };
382
+ },
383
+ piProviderPreviewJson() {
384
+ const { merged, ok } = this.piBuildMergedEditorRecord();
385
+ if (!ok || !merged) return '{}';
386
+ try {
387
+ return JSON.stringify(merged, null, 2);
388
+ } catch (_) {
389
+ return '{}';
390
+ }
391
+ },
392
+ piEditorJsonDraftInput() {
393
+ const draft = this.piParseEditorJsonDraft();
394
+ this.piEditorJsonError = draft.ok ? '' : draft.error;
395
+ }
353
396
  };
354
397
  }
@@ -1346,6 +1346,10 @@ const en = Object.freeze({
1346
1346
  'pi.providers.fields.apiKey': 'API Key',
1347
1347
  'pi.providers.fields.models': 'Models',
1348
1348
  'pi.providers.fields.configJson': 'Config JSON',
1349
+ 'pi.providers.json.title': 'Config JSON',
1350
+ 'pi.providers.json.desc': 'Live preview of the final provider record merged from form changes and extras; edits are merged into models.json on save.',
1351
+ 'pi.providers.json.previewTitle': 'Preview',
1352
+ 'pi.providers.json.editTitle': 'Edit JSON',
1349
1353
  'pi.providers.models.remove': 'Remove',
1350
1354
  'pi.providers.models.search': 'Search available models…',
1351
1355
  'pi.providers.models.remoteCount': '{count} models available, click to add',
@@ -1347,6 +1347,10 @@ const ja = Object.freeze({
1347
1347
  'pi.providers.fields.apiKey': 'API Key',
1348
1348
  'pi.providers.fields.models': 'モデル',
1349
1349
  'pi.providers.fields.configJson': '設定 JSON',
1350
+ 'pi.providers.json.title': '設定 JSON',
1351
+ 'pi.providers.json.desc': 'フォーム変更と拡張フィールドを統合した最終レコードをリアルタイムにプレビュー。保存時に models.json へ統合します。',
1352
+ 'pi.providers.json.previewTitle': 'プレビュー',
1353
+ 'pi.providers.json.editTitle': 'JSON を編集',
1350
1354
  'pi.providers.models.remove': '削除',
1351
1355
  'pi.providers.models.search': '利用可能なモデルを検索…',
1352
1356
  'pi.providers.models.remoteCount': '{count} 個のモデルを取得しました。クリックで追加',
@@ -1315,6 +1315,10 @@ const vi = Object.freeze({
1315
1315
  'pi.providers.fields.apiKey': 'API Key',
1316
1316
  'pi.providers.fields.models': 'Mô hình',
1317
1317
  'pi.providers.fields.configJson': 'Cấu hình JSON',
1318
+ 'pi.providers.json.title': 'Cấu hình JSON',
1319
+ 'pi.providers.json.desc': 'Xem trước bản ghi cuối từ thay đổi biểu mẫu; các chỉnh sửa được gộp vào models.json khi lưu.',
1320
+ 'pi.providers.json.previewTitle': 'Xem trước',
1321
+ 'pi.providers.json.editTitle': 'Chỉnh sửa JSON',
1318
1322
  'pi.providers.models.remove': 'Xóa',
1319
1323
  'pi.providers.models.search': 'Tìm kiếm mô hình khả dụng…',
1320
1324
  'pi.providers.models.remoteCount': 'Đã lấy {count} mô hình, bấm để thêm',
@@ -1344,6 +1344,10 @@ const zhTw = Object.freeze({
1344
1344
  'pi.providers.fields.apiKey': 'API Key',
1345
1345
  'pi.providers.fields.models': '模型',
1346
1346
  'pi.providers.fields.configJson': '組態 JSON',
1347
+ 'pi.providers.json.title': '設定 JSON',
1348
+ 'pi.providers.json.desc': '即時預覽表單異動合併後的最終紀錄;儲存時併入 models.json。',
1349
+ 'pi.providers.json.previewTitle': '預覽',
1350
+ 'pi.providers.json.editTitle': '編輯 JSON',
1347
1351
  'pi.providers.models.remove': '刪除',
1348
1352
  'pi.providers.models.search': '搜尋可用模型…',
1349
1353
  'pi.providers.models.remoteCount': '已取得 {count} 個可用模型,點擊新增',
@@ -1344,6 +1344,10 @@ const zh = Object.freeze({
1344
1344
  'pi.providers.fields.apiKey': 'API Key',
1345
1345
  'pi.providers.fields.models': '模型',
1346
1346
  'pi.providers.fields.configJson': '配置 JSON',
1347
+ 'pi.providers.json.title': '配置 JSON',
1348
+ 'pi.providers.json.desc': '实时预览表单改动合并后的最终记录;保存时并入 models.json。',
1349
+ 'pi.providers.json.previewTitle': '预览',
1350
+ 'pi.providers.json.editTitle': '编辑 JSON',
1347
1351
  'pi.providers.models.remove': '删除',
1348
1352
  'pi.providers.models.search': '搜索可用模型…',
1349
1353
  'pi.providers.models.remoteCount': '已拉取 {count} 个可用模型,点击添加',
@@ -117,6 +117,25 @@
117
117
  <div class="settings-tab-actions">
118
118
  <button type="button" class="btn-tool" @click="confirmDeletePiProvider" :disabled="!isToolConfigWriteAllowed('pi') || piSaving">{{ t('pi.providers.delete') }}</button>
119
119
  </div>
120
+
121
+ <section class="selector-section">
122
+ <div class="selector-header">
123
+ <span class="selector-title">{{ t('pi.providers.json.title') }}</span>
124
+ </div>
125
+ <p class="config-template-hint">{{ t('pi.providers.json.desc') }}</p>
126
+ <label class="form-label">{{ t('pi.providers.json.previewTitle') }}</label>
127
+ <pre class="config-json-preview">{{ piProviderPreviewJson() }}</pre>
128
+ <label class="form-label">{{ t('pi.providers.json.editTitle') }}</label>
129
+ <textarea
130
+ class="template-textarea config-json-editor"
131
+ v-model="editingPiProvider.form.configJsonDraft"
132
+ spellcheck="false"
133
+ autocomplete="off"
134
+ :disabled="!isToolConfigWriteAllowed('pi')"
135
+ @input="piEditorJsonDraftInput"
136
+ placeholder="{}"></textarea>
137
+ <p v-if="piEditorJsonError" class="config-template-hint error-text">{{ piEditorJsonError }}</p>
138
+ </section>
120
139
  </section>
121
140
 
122
141
  <section class="selector-section" v-if="showAddPiProviderModal">
@@ -3458,6 +3458,32 @@ return function render(_ctx, _cache) {
3458
3458
  onClick: _ctx.confirmDeletePiProvider,
3459
3459
  disabled: !_ctx.isToolConfigWriteAllowed('pi') || _ctx.piSaving
3460
3460
  }, _toDisplayString(_ctx.t('pi.providers.delete')), 9 /* TEXT, PROPS */, ["onClick", "disabled"])
3461
+ ]),
3462
+ _createElementVNode("section", { class: "selector-section" }, [
3463
+ _createElementVNode("div", { class: "selector-header" }, [
3464
+ _createElementVNode("span", { class: "selector-title" }, _toDisplayString(_ctx.t('pi.providers.json.title')), 1 /* TEXT */)
3465
+ ]),
3466
+ _createElementVNode("p", { class: "config-template-hint" }, _toDisplayString(_ctx.t('pi.providers.json.desc')), 1 /* TEXT */),
3467
+ _createElementVNode("label", { class: "form-label" }, _toDisplayString(_ctx.t('pi.providers.json.previewTitle')), 1 /* TEXT */),
3468
+ _createElementVNode("pre", { class: "config-json-preview" }, _toDisplayString(_ctx.piProviderPreviewJson()), 1 /* TEXT */),
3469
+ _createElementVNode("label", { class: "form-label" }, _toDisplayString(_ctx.t('pi.providers.json.editTitle')), 1 /* TEXT */),
3470
+ _withDirectives(_createElementVNode("textarea", {
3471
+ class: "template-textarea config-json-editor",
3472
+ "onUpdate:modelValue": $event => ((_ctx.editingPiProvider.form.configJsonDraft) = $event),
3473
+ spellcheck: "false",
3474
+ autocomplete: "off",
3475
+ disabled: !_ctx.isToolConfigWriteAllowed('pi'),
3476
+ onInput: _ctx.piEditorJsonDraftInput,
3477
+ placeholder: "{}"
3478
+ }, null, 40 /* PROPS, NEED_HYDRATION */, ["onUpdate:modelValue", "disabled", "onInput"]), [
3479
+ [_vModelText, _ctx.editingPiProvider.form.configJsonDraft]
3480
+ ]),
3481
+ (_ctx.piEditorJsonError)
3482
+ ? (_openBlock(), _createElementBlock("p", {
3483
+ key: 0,
3484
+ class: "config-template-hint error-text"
3485
+ }, _toDisplayString(_ctx.piEditorJsonError), 1 /* TEXT */))
3486
+ : _createCommentVNode("v-if", true)
3461
3487
  ])
3462
3488
  ]))
3463
3489
  : _createCommentVNode("v-if", true),
@@ -352,6 +352,28 @@
352
352
  margin-top: 2px;
353
353
  }
354
354
 
355
+ .config-json-preview {
356
+ width: 100%;
357
+ max-height: 240px;
358
+ overflow: auto;
359
+ margin: 0 0 10px;
360
+ padding: 12px;
361
+ border: 1px solid var(--color-border);
362
+ border-radius: var(--radius-md);
363
+ background: rgba(0, 0, 0, 0.04);
364
+ color: var(--color-text-secondary);
365
+ font-family: var(--font-mono);
366
+ font-size: 12px;
367
+ line-height: 1.55;
368
+ white-space: pre;
369
+ box-shadow: var(--shadow-subtle);
370
+ }
371
+
372
+ .config-json-editor {
373
+ min-height: 180px;
374
+ margin-bottom: 8px;
375
+ }
376
+
355
377
  /* ============================================
356
378
  按钮
357
379
  ============================================ */