codexmate 0.1.27 → 0.1.29

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.
Files changed (48) hide show
  1. package/README.md +53 -44
  2. package/README.vi.md +45 -36
  3. package/README.zh.md +51 -42
  4. package/cli/config-bootstrap.js +2 -9
  5. package/cli/session-usage.js +2 -2
  6. package/cli.js +407 -40
  7. package/package.json +1 -1
  8. package/web-ui/app.js +7 -0
  9. package/web-ui/index.html +12 -0
  10. package/web-ui/logic.sessions.mjs +6 -4
  11. package/web-ui/modules/app.computed.session.mjs +52 -33
  12. package/web-ui/modules/app.methods.agents.mjs +36 -0
  13. package/web-ui/modules/app.methods.codex-config.mjs +3 -1
  14. package/web-ui/modules/app.methods.index.mjs +2 -0
  15. package/web-ui/modules/app.methods.providers.mjs +12 -4
  16. package/web-ui/modules/app.methods.session-actions.mjs +10 -8
  17. package/web-ui/modules/app.methods.session-browser.mjs +3 -1
  18. package/web-ui/modules/app.methods.session-trash.mjs +16 -16
  19. package/web-ui/modules/app.methods.theme.mjs +39 -0
  20. package/web-ui/modules/app.methods.web-ui-preferences.mjs +9 -0
  21. package/web-ui/modules/i18n/locales/en.mjs +80 -2
  22. package/web-ui/modules/i18n/locales/ja.mjs +80 -2
  23. package/web-ui/modules/i18n/locales/vi.mjs +80 -2
  24. package/web-ui/modules/i18n/locales/zh-tw.mjs +80 -2
  25. package/web-ui/modules/i18n/locales/zh.mjs +80 -2
  26. package/web-ui/modules/i18n.mjs +7 -0
  27. package/web-ui/partials/index/modal-config-template-agents.html +1 -1
  28. package/web-ui/partials/index/modal-health-check.html +1 -1
  29. package/web-ui/partials/index/modal-openclaw-config.html +50 -50
  30. package/web-ui/partials/index/panel-dashboard.html +1 -1
  31. package/web-ui/partials/index/panel-prompts.html +2 -2
  32. package/web-ui/partials/index/panel-sessions.html +47 -30
  33. package/web-ui/partials/index/panel-settings.html +30 -0
  34. package/web-ui/res/web-ui-render.precompiled.js +244 -157
  35. package/web-ui/session-helpers.mjs +3 -0
  36. package/web-ui/styles/base-theme.css +3 -2
  37. package/web-ui/styles/bridge-pool.css +1 -1
  38. package/web-ui/styles/controls-forms.css +1 -1
  39. package/web-ui/styles/layout-shell.css +0 -1
  40. package/web-ui/styles/sessions-preview.css +77 -0
  41. package/web-ui/styles/sessions-toolbar-trash.css +1 -1
  42. package/web-ui/styles/sessions-usage.css +1 -1
  43. package/web-ui/styles/settings-panel.css +2 -2
  44. package/web-ui/styles/theme-dark-tokens.css +83 -0
  45. package/web-ui/styles/theme-dark.css +1355 -0
  46. package/web-ui/styles/theme-ocean-tokens.css +88 -0
  47. package/web-ui/styles/theme-ocean.css +920 -0
  48. package/web-ui/styles.css +2 -0
@@ -1,7 +1,7 @@
1
1
  <!-- 会话浏览模式 -->
2
2
  <div
3
3
  v-show="mainTab === 'sessions'"
4
- class="mode-content"
4
+ class="mode-content session-browser-refined"
5
5
  id="panel-sessions"
6
6
  role="tabpanel"
7
7
  :aria-labelledby="'tab-sessions'">
@@ -105,8 +105,8 @@
105
105
  <span>{{ t('sessions.batch.select') }}</span>
106
106
  </button>
107
107
  <template v-else>
108
- <button class="btn-tool btn-tool-compact" type="button" @click="toggleSelectAllVisibleForBatch" :disabled="sessionsLoading" :title="isAllVisibleBatchSelected() ? t('sessions.batch.unselectAll') : t('sessions.batch.selectAll')">
109
- {{ isAllVisibleBatchSelected() ? t('sessions.batch.unselectAll') : t('sessions.batch.selectAll') }}
108
+ <button class="btn-tool btn-tool-compact" type="button" @click="toggleSelectAllVisibleForBatch" :disabled="sessionsLoading" :title="isAllVisibleBatchSelected() ? t('sessions.batch.unselectAll') : t('sessions.batch.selectAllVisibleN', { count: getVisibleBatchSelectableCount() })">
109
+ {{ isAllVisibleBatchSelected() ? t('sessions.batch.unselectAll') : t('sessions.batch.selectAllVisibleN', { count: getVisibleBatchSelectableCount() }) }}
110
110
  </button>
111
111
  <button class="btn-tool btn-tool-compact btn-tool-batch-delete" type="button" @click="deleteSelectedSessions" :disabled="sessionsLoading || sessionDeletingSelected || getSelectedBatchCount() === 0" :title="getSelectedBatchCount() > 0 ? t('sessions.batch.deleteSelectedN', { count: getSelectedBatchCount() }) : t('sessions.batch.emptySelection')">
112
112
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M7 6V4a2 2 0 012-2h6a2 2 0 012 2v2M10 11v6M14 11v6"/><path d="M5 6l1 14a2 2 0 002 2h8a2 2 0 002-2l1-14"/></svg>
@@ -133,12 +133,19 @@
133
133
  </div>
134
134
  </div>
135
135
 
136
+ <div v-if="sessionSearchInfo && !sessionsLoading" class="session-search-status" role="status">
137
+ <span class="session-search-count">{{ t('sessions.search.coverage', { scanned: sessionSearchInfo.scanned, candidates: sessionSearchInfo.candidates }) }}</span>
138
+ <span v-if="!sessionSearchInfo.complete" class="session-search-partial">{{ t('sessions.search.partial') }}</span>
139
+ <small class="session-search-scope">{{ t('sessions.search.scopeHint') }}</small>
140
+ </div>
141
+
136
142
  <div v-if="sessionsLoading && sessionsList.length === 0" class="state-message">
137
143
  {{ t('sessions.loadingList') }}
138
144
  </div>
139
145
 
140
- <div v-else-if="!sessionsLoading && sessionsList.length === 0" class="session-empty">
141
- {{ t('sessions.empty') }}
146
+ <div v-else-if="!sessionsLoading && sessionsList.length === 0" class="session-empty session-empty-refined">
147
+ <p>{{ t(hasActiveSessionFilters() ? 'sessions.empty.filtered' : 'sessions.empty.source') }}</p>
148
+ <button v-if="hasActiveSessionFilters()" class="btn-tool btn-tool-compact" type="button" @click="clearSessionFilters">{{ t('sessions.empty.clearFilters') }}</button>
142
149
  </div>
143
150
 
144
151
  <div v-else class="session-layout">
@@ -244,24 +251,13 @@
244
251
  <span class="session-preview-meta-item">{{ activeSession.cwd }}</span>
245
252
  </div>
246
253
  </div>
247
- <div class="session-actions">
248
- <button class="btn-session-refresh has-label" @click="loadActiveSessionDetail" :disabled="sessionDetailLoading || !activeSession"
249
- :title="sessionDetailLoading ? t('sessions.preview.loading') : t('sessions.preview.refresh')"
250
- :aria-label="sessionDetailLoading ? t('sessions.preview.loading') : t('sessions.preview.refresh')">
251
- <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M2.5 8a5.5 5.5 0 0 1 9.4-3.8"/><path d="M13.5 8a5.5 5.5 0 0 1-9.4 3.8"/><polyline points="2.5 2 2.5 5 5.5 5"/><polyline points="13.5 14 13.5 11 10.5 11"/></svg>
252
- <span class="session-action-label">{{ t('sessions.preview.refresh') }}</span>
253
- </button>
254
- <button
255
- v-if="isDeleteAvailable(activeSession)"
256
- class="btn-session-delete has-label"
257
- @click="deleteSession(activeSession)"
258
- :disabled="!activeSession || sessionsLoading || sessionDeleting[getSessionExportKey(activeSession)]"
259
- :title="(activeSession && sessionDeleting[getSessionExportKey(activeSession)]) ? (sessionTrashEnabled === false ? t('sessions.preview.deleting') : t('sessions.preview.moving')) : (sessionTrashEnabled === false ? t('sessions.preview.deleteHard') : t('sessions.preview.moveToTrash'))"
260
- :aria-label="(activeSession && sessionDeleting[getSessionExportKey(activeSession)]) ? (sessionTrashEnabled === false ? t('sessions.preview.deleting') : t('sessions.preview.moving')) : (sessionTrashEnabled === false ? t('sessions.preview.deleteHard') : t('sessions.preview.moveToTrash'))">
261
- <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 4 4 4 13 4"/><path d="M5.5 4V2.5a1 1 0 0 1 1-1h3a1 1 0 0 1 1 1V4"/><path d="M12 4v9.5a1.5 1.5 0 0 1-1.5 1.5h-5A1.5 1.5 0 0 1 4 13.5V4"/></svg>
262
- <span class="session-action-label">{{ (activeSession && sessionDeleting[getSessionExportKey(activeSession)]) ? (sessionTrashEnabled === false ? t('sessions.preview.deleting') : t('sessions.preview.moving')) : (sessionTrashEnabled === false ? t('sessions.preview.deleteHard') : t('sessions.preview.moveToTrash')) }}</span>
263
- </button>
264
- <button
254
+ <div class="session-export-control">
255
+ <label class="session-export-label" for="session-export-range">{{ t('sessions.export.range') }}</label>
256
+ <select id="session-export-range" v-model="sessionExportRange" :disabled="sessionExporting[getSessionExportKey(activeSession)]" aria-describedby="session-export-scope">
257
+ <option value="default">{{ t('sessions.export.default') }}</option>
258
+ <option value="all">{{ t('sessions.export.all') }}</option>
259
+ </select>
260
+ <button
265
261
  class="btn-session-export has-label"
266
262
  @click="exportSession(activeSession)"
267
263
  :disabled="!activeSession || sessionExporting[getSessionExportKey(activeSession)]"
@@ -270,25 +266,31 @@
270
266
  <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M8 2v8"/><polyline points="4 7 8 10.5 12 7"/><path d="M2.5 12v1.5a1 1 0 0 0 1 1h9a1 1 0 0 0 1-1V12"/></svg>
271
267
  <span class="session-action-label">{{ (activeSession && sessionExporting[getSessionExportKey(activeSession)]) ? t('sessions.preview.exporting') : t('sessions.preview.export') }}</span>
272
268
  </button>
273
- <div class="session-link-group">
274
- <button
269
+ </div>
270
+ <div class="session-actions session-preview-actions">
271
+ <div class="session-secondary-actions">
272
+ <button class="btn-session-refresh has-label" @click="loadActiveSessionDetail" :disabled="sessionDetailLoading || !activeSession"
273
+ :title="sessionDetailLoading ? t('sessions.preview.loading') : t('sessions.preview.refresh')"
274
+ :aria-label="sessionDetailLoading ? t('sessions.preview.loading') : t('sessions.preview.refresh')">
275
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M2.5 8a5.5 5.5 0 0 1 9.4-3.8"/><path d="M13.5 8a5.5 5.5 0 0 1-9.4 3.8"/><polyline points="2.5 2 2.5 5 5.5 5"/><polyline points="13.5 14 13.5 11 10.5 11"/></svg>
276
+ <span class="session-action-label">{{ t('sessions.preview.refresh') }}</span>
277
+ </button>
278
+ <div class="session-link-group"><button
275
279
  class="btn-session-open"
276
280
  @click="copySessionLink(activeSession)"
277
281
  :disabled="!activeSession || !canBuildStandaloneUrl(activeSession)"
278
282
  :title="t('sessions.preview.copyLink')"
279
283
  :aria-label="t('sessions.preview.copyLink')">
280
284
  <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6.5 9.5a3.5 3.5 0 0 0 5 0l2-2a3.5 3.5 0 0 0-5-5l-1 1"/><path d="M9.5 6.5a3.5 3.5 0 0 0-5 0l-2 2a3.5 3.5 0 0 0 5 5l1-1"/></svg>
281
- </button>
282
- <button
285
+ </button> <button
283
286
  class="btn-session-open"
284
287
  @click="openSessionLink(activeSession)"
285
288
  :disabled="!activeSession || !canBuildStandaloneUrl(activeSession)"
286
289
  :title="t('sessions.preview.openLink')"
287
290
  :aria-label="t('sessions.preview.openLink')">
288
291
  <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2h-8.5A1.5 1.5 0 0 0 2 3.5v8A1.5 1.5 0 0 0 3.5 13h8a1.5 1.5 0 0 0 1.5-1.5v-3"/><path d="M13 2v4h-4"/><path d="M13 2L7 8"/></svg>
289
- </button>
290
- </div>
291
- <button
292
+ </button></div>
293
+ <button
292
294
  class="btn-session-open has-label"
293
295
  @click="copySessionPath(activeSession)"
294
296
  :disabled="!activeSession || !getSessionFilePath(activeSession)"
@@ -297,8 +299,23 @@
297
299
  <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M2 5.5V12.5a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V7.5a1 1 0 0 0-1-1H8L6.5 5H3a1 1 0 0 0-1 1z"/></svg>
298
300
  <span class="session-action-label">{{ t('sessions.preview.copyPath') }}</span>
299
301
  </button>
302
+ </div>
303
+ <div class="session-danger-action"><button
304
+ v-if="isDeleteAvailable(activeSession)"
305
+ class="btn-session-delete has-label"
306
+ @click="deleteSession(activeSession)"
307
+ :disabled="!activeSession || sessionsLoading || sessionDeleting[getSessionExportKey(activeSession)]"
308
+ :title="(activeSession && sessionDeleting[getSessionExportKey(activeSession)]) ? (sessionTrashEnabled === false ? t('sessions.preview.deleting') : t('sessions.preview.moving')) : (sessionTrashEnabled === false ? t('sessions.preview.deleteHard') : t('sessions.preview.moveToTrash'))"
309
+ :aria-label="(activeSession && sessionDeleting[getSessionExportKey(activeSession)]) ? (sessionTrashEnabled === false ? t('sessions.preview.deleting') : t('sessions.preview.moving')) : (sessionTrashEnabled === false ? t('sessions.preview.deleteHard') : t('sessions.preview.moveToTrash'))">
310
+ <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 4 4 4 13 4"/><path d="M5.5 4V2.5a1 1 0 0 1 1-1h3a1 1 0 0 1 1 1V4"/><path d="M12 4v9.5a1.5 1.5 0 0 1-1.5 1.5h-5A1.5 1.5 0 0 1 4 13.5V4"/></svg>
311
+ <span class="session-action-label">{{ (activeSession && sessionDeleting[getSessionExportKey(activeSession)]) ? (sessionTrashEnabled === false ? t('sessions.preview.deleting') : t('sessions.preview.moving')) : (sessionTrashEnabled === false ? t('sessions.preview.deleteHard') : t('sessions.preview.moveToTrash')) }}</span>
312
+ </button></div>
300
313
  </div>
301
314
  </div>
315
+ <div class="session-export-feedback">
316
+ <small id="session-export-scope">{{ t('sessions.export.scopeHint') }}</small>
317
+ <p v-if="sessionExportNotice && sessionExportNotice.key === getSessionExportKey(activeSession)" class="session-export-notice" role="status">{{ t('sessions.export.truncated') }}</p>
318
+ </div>
302
319
 
303
320
  <div v-if="sessionDetailLoading && !sessionPreviewLoadingMore" class="session-preview-empty">
304
321
  {{ t('sessions.preview.loadingBody') }}
@@ -61,6 +61,36 @@
61
61
  </div>
62
62
  </section>
63
63
 
64
+ <section class="settings-card" :aria-label="t('settings.theme.title')">
65
+ <div class="settings-card-main">
66
+ <div class="settings-card-content">
67
+ <div class="settings-card-title">{{ t('settings.theme.title') }}</div>
68
+ <p class="settings-card-desc">{{ t('settings.theme.meta') }}</p>
69
+ <div class="settings-toggle-group">
70
+ <button
71
+ type="button"
72
+ :class="['toggle-btn', { active: theme === 'light' }]"
73
+ @click="setTheme('light')">
74
+ {{ t('settings.theme.light') }}
75
+ </button>
76
+ <button
77
+ type="button"
78
+ :class="['toggle-btn', { active: theme === 'dark' }]"
79
+ @click="setTheme('dark')">
80
+ {{ t('settings.theme.dark') }}
81
+ </button>
82
+ <button
83
+ type="button"
84
+ :class="['toggle-btn', { active: theme === 'ocean' }]"
85
+ @click="setTheme('ocean')">
86
+ {{ t('settings.theme.ocean') }}
87
+ </button>
88
+ </div>
89
+ <p class="settings-card-hint">{{ t('settings.theme.hint') }}</p>
90
+ </div>
91
+ </div>
92
+ </section>
93
+
64
94
  <section class="settings-card" :aria-label="t('settings.sharePrefix.title')">
65
95
  <div class="settings-card-main">
66
96
  <div class="settings-card-content">