codexmate 0.0.22 → 0.0.24

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 (66) hide show
  1. package/README.md +5 -3
  2. package/README.zh.md +8 -5
  3. package/cli/auth-profiles.js +23 -7
  4. package/cli/doctor-core.js +903 -0
  5. package/cli/import-skills-url.js +334 -0
  6. package/cli.js +304 -208
  7. package/lib/cli-models-utils.js +0 -40
  8. package/lib/cli-network-utils.js +28 -2
  9. package/package.json +5 -2
  10. package/plugins/README.md +20 -0
  11. package/plugins/README.zh-CN.md +20 -0
  12. package/plugins/prompt-templates/comment-polish/index.mjs +25 -0
  13. package/plugins/prompt-templates/computed.mjs +253 -0
  14. package/plugins/prompt-templates/index.mjs +8 -0
  15. package/plugins/prompt-templates/manifest.mjs +15 -0
  16. package/plugins/prompt-templates/methods.mjs +619 -0
  17. package/plugins/prompt-templates/overview.mjs +90 -0
  18. package/plugins/prompt-templates/ownership.mjs +19 -0
  19. package/plugins/prompt-templates/rule-ack/index.mjs +21 -0
  20. package/plugins/prompt-templates/storage.mjs +64 -0
  21. package/plugins/registry.mjs +16 -0
  22. package/res/logo-pack.webp +0 -0
  23. package/web-ui/app.js +68 -34
  24. package/web-ui/index.html +4 -3
  25. package/web-ui/modules/app.computed.dashboard.mjs +22 -22
  26. package/web-ui/modules/app.computed.main-tabs.mjs +9 -2
  27. package/web-ui/modules/app.methods.agents.mjs +91 -3
  28. package/web-ui/modules/app.methods.codex-config.mjs +153 -164
  29. package/web-ui/modules/app.methods.install.mjs +16 -0
  30. package/web-ui/modules/app.methods.navigation.mjs +76 -0
  31. package/web-ui/modules/app.methods.runtime.mjs +24 -2
  32. package/web-ui/modules/app.methods.session-browser.mjs +73 -1
  33. package/web-ui/modules/app.methods.startup-claude.mjs +12 -0
  34. package/web-ui/modules/app.methods.task-orchestration.mjs +96 -11
  35. package/web-ui/modules/config-mode.computed.mjs +1 -3
  36. package/web-ui/modules/i18n.dict.mjs +2039 -0
  37. package/web-ui/modules/i18n.mjs +2 -1555
  38. package/web-ui/modules/plugins.computed.mjs +2 -219
  39. package/web-ui/modules/plugins.methods.mjs +2 -619
  40. package/web-ui/modules/plugins.storage.mjs +11 -37
  41. package/web-ui/modules/sessions-filters-url.mjs +85 -0
  42. package/web-ui/partials/index/layout-header.html +38 -34
  43. package/web-ui/partials/index/modal-config-template-agents.html +3 -4
  44. package/web-ui/partials/index/modal-health-check.html +33 -60
  45. package/web-ui/partials/index/panel-config-claude.html +56 -15
  46. package/web-ui/partials/index/panel-config-codex.html +68 -19
  47. package/web-ui/partials/index/panel-config-openclaw.html +8 -3
  48. package/web-ui/partials/index/panel-dashboard.html +186 -0
  49. package/web-ui/partials/index/panel-docs.html +1 -1
  50. package/web-ui/partials/index/panel-market.html +3 -0
  51. package/web-ui/partials/index/panel-orchestration.html +105 -111
  52. package/web-ui/partials/index/panel-plugins.html +48 -12
  53. package/web-ui/partials/index/panel-sessions.html +12 -3
  54. package/web-ui/partials/index/panel-settings.html +1 -1
  55. package/web-ui/partials/index/panel-usage.html +7 -6
  56. package/web-ui/styles/controls-forms.css +16 -2
  57. package/web-ui/styles/dashboard.css +274 -0
  58. package/web-ui/styles/layout-shell.css +11 -5
  59. package/web-ui/styles/navigation-panels.css +8 -0
  60. package/web-ui/styles/plugins-panel.css +5 -0
  61. package/web-ui/styles/sessions-list.css +3 -3
  62. package/web-ui/styles/sessions-usage.css +37 -0
  63. package/web-ui/styles/skills-market.css +12 -2
  64. package/web-ui/styles/task-orchestration.css +57 -11
  65. package/web-ui/styles.css +1 -0
  66. package/res/logo.png +0 -0
@@ -4,6 +4,14 @@ import {
4
4
  normalizeSessionMessageRole,
5
5
  normalizeSessionPathFilter
6
6
  } from '../logic.mjs';
7
+ import {
8
+ applySessionsFilterUrlState,
9
+ buildSessionsFilterShareUrl,
10
+ normalizeSessionRoleFilter,
11
+ normalizeSessionTimePreset,
12
+ readSessionsFilterUrlState,
13
+ syncSessionsFilterUrl
14
+ } from './sessions-filters-url.mjs';
7
15
 
8
16
  function isSessionLoadNativeDialogEnabled(vm) {
9
17
  if (vm && typeof vm.isSessionLoadNativeDialogEnabled === 'function' && vm.isSessionLoadNativeDialogEnabled !== isSessionLoadNativeDialogEnabled) {
@@ -241,11 +249,22 @@ export function createSessionBrowserMethods(options = {}) {
241
249
  },
242
250
 
243
251
  restoreSessionFilterCache() {
252
+ const urlState = readSessionsFilterUrlState();
253
+ if (urlState) {
254
+ applySessionsFilterUrlState(this, urlState);
255
+ return;
256
+ }
244
257
  const sourceCache = localStorage.getItem('codexmateSessionFilterSource');
245
258
  const pathCache = localStorage.getItem('codexmateSessionPathFilter');
246
259
  const cached = buildSessionFilterCacheState(sourceCache, pathCache);
247
260
  this.sessionFilterSource = cached.source;
248
261
  this.sessionPathFilter = cached.pathFilter;
262
+ const queryCache = localStorage.getItem('codexmateSessionQuery');
263
+ const roleCache = localStorage.getItem('codexmateSessionRoleFilter');
264
+ const timeCache = localStorage.getItem('codexmateSessionTimePreset');
265
+ this.sessionQuery = typeof queryCache === 'string' ? queryCache : '';
266
+ this.sessionRoleFilter = normalizeSessionRoleFilter(roleCache);
267
+ this.sessionTimePreset = normalizeSessionTimePreset(timeCache);
249
268
  this.refreshSessionPathOptions(this.sessionFilterSource);
250
269
  },
251
270
 
@@ -257,6 +276,13 @@ export function createSessionBrowserMethods(options = {}) {
257
276
  } else {
258
277
  localStorage.removeItem('codexmateSessionPathFilter');
259
278
  }
279
+ if (this.sessionQuery && isSessionQueryEnabled(this.sessionFilterSource)) {
280
+ localStorage.setItem('codexmateSessionQuery', this.sessionQuery);
281
+ } else {
282
+ localStorage.removeItem('codexmateSessionQuery');
283
+ }
284
+ localStorage.setItem('codexmateSessionRoleFilter', normalizeSessionRoleFilter(this.sessionRoleFilter));
285
+ localStorage.setItem('codexmateSessionTimePreset', normalizeSessionTimePreset(this.sessionTimePreset));
260
286
  },
261
287
 
262
288
  normalizeSessionPinnedMap(raw) {
@@ -389,15 +415,19 @@ export function createSessionBrowserMethods(options = {}) {
389
415
  async onSessionSourceChange() {
390
416
  this.refreshSessionPathOptions(this.sessionFilterSource);
391
417
  this.persistSessionFilterCache();
418
+ syncSessionsFilterUrl(this);
392
419
  await this.loadSessions();
393
420
  },
394
421
 
395
422
  async onSessionPathFilterChange() {
396
423
  this.persistSessionFilterCache();
424
+ syncSessionsFilterUrl(this);
397
425
  await this.loadSessions();
398
426
  },
399
427
 
400
428
  async onSessionFilterChange() {
429
+ this.persistSessionFilterCache();
430
+ syncSessionsFilterUrl(this);
401
431
  await this.loadSessions();
402
432
  },
403
433
 
@@ -408,9 +438,31 @@ export function createSessionBrowserMethods(options = {}) {
408
438
  this.sessionRoleFilter = 'all';
409
439
  this.sessionTimePreset = 'all';
410
440
  this.persistSessionFilterCache();
441
+ syncSessionsFilterUrl(this);
411
442
  await this.onSessionSourceChange();
412
443
  },
413
444
 
445
+ async copySessionsFilterShareUrl() {
446
+ const url = buildSessionsFilterShareUrl(this);
447
+ if (!url) {
448
+ this.showMessage(typeof this.t === 'function' ? this.t('sessions.filters.urlBuildFail') : 'Failed to build link', 'error');
449
+ return;
450
+ }
451
+ try {
452
+ if (navigator.clipboard && window.isSecureContext) {
453
+ await navigator.clipboard.writeText(url);
454
+ this.showMessage(typeof this.t === 'function' ? this.t('toast.copy.ok') : 'Copied', 'success');
455
+ return;
456
+ }
457
+ } catch (_) {}
458
+ const ok = typeof this.fallbackCopyText === 'function' ? this.fallbackCopyText(url) : false;
459
+ if (ok) {
460
+ this.showMessage(typeof this.t === 'function' ? this.t('toast.copy.ok') : 'Copied', 'success');
461
+ return;
462
+ }
463
+ this.showMessage(typeof this.t === 'function' ? this.t('toast.copy.fail') : 'Copy failed', 'error');
464
+ },
465
+
414
466
  normalizeSessionMessage(message) {
415
467
  const fallback = {
416
468
  role: 'assistant',
@@ -464,21 +516,40 @@ export function createSessionBrowserMethods(options = {}) {
464
516
 
465
517
  invalidateSessionsUsageData(options = {}) {
466
518
  this.sessionsUsageLoadedOnce = false;
519
+ this.sessionsUsageLoadedLimit = 0;
467
520
  this.sessionsUsageError = '';
468
521
  if (options.preserveList !== true) {
469
522
  this.sessionsUsageList = [];
470
523
  }
471
524
  },
472
525
 
526
+ setSessionsUsageTimeRange(nextRange) {
527
+ const normalized = typeof nextRange === 'string' ? nextRange.trim().toLowerCase() : '';
528
+ const range = normalized === 'all' ? 'all' : (normalized === '30d' ? '30d' : '7d');
529
+ this.sessionsUsageTimeRange = range;
530
+ void this.loadSessionsUsage({ range });
531
+ },
532
+
473
533
  async loadSessionsUsage(options = {}) {
474
534
  if (this.sessionsUsageLoading) return;
535
+ const normalizedRange = typeof options.range === 'string'
536
+ ? options.range.trim().toLowerCase()
537
+ : (typeof this.sessionsUsageTimeRange === 'string' ? this.sessionsUsageTimeRange.trim().toLowerCase() : '');
538
+ const range = normalizedRange === 'all' ? 'all' : (normalizedRange === '30d' ? '30d' : '7d');
539
+ const defaultLimit = range === 'all' ? 2000 : (range === '30d' ? 1200 : 600);
540
+ const rawLimit = Number(options.limit);
541
+ const limit = Number.isFinite(rawLimit) ? Math.max(1, Math.min(rawLimit, 2000)) : defaultLimit;
542
+ const loadedLimit = Number(this.sessionsUsageLoadedLimit || 0);
543
+ if (this.sessionsUsageLoadedOnce && !options.forceRefresh && loadedLimit >= limit) {
544
+ return;
545
+ }
475
546
  this.sessionsUsageLoading = true;
476
547
  this.sessionsUsageError = '';
477
548
  let loadSucceeded = false;
478
549
  try {
479
550
  const res = await api('list-sessions-usage', {
480
551
  source: 'all',
481
- limit: 2000,
552
+ limit,
482
553
  forceRefresh: !!options.forceRefresh
483
554
  });
484
555
  if (res.error) {
@@ -495,6 +566,7 @@ export function createSessionBrowserMethods(options = {}) {
495
566
  this.sessionsUsageLoading = false;
496
567
  if (loadSucceeded) {
497
568
  this.sessionsUsageLoadedOnce = true;
569
+ this.sessionsUsageLoadedLimit = limit;
498
570
  }
499
571
  }
500
572
  },
@@ -34,6 +34,18 @@ export function createStartupClaudeMethods(options = {}) {
34
34
  startupOk = true;
35
35
  this.currentProvider = statusRes.provider;
36
36
  this.currentModel = statusRes.model;
37
+ try {
38
+ const installRes = await api('install-status');
39
+ if (installRes && !installRes.error) {
40
+ const targets = Array.isArray(installRes.targets) ? installRes.targets : null;
41
+ if (targets) {
42
+ this.installStatusTargets = targets;
43
+ }
44
+ if (typeof installRes.packageManager === 'string' && typeof this.normalizeInstallPackageManager === 'function') {
45
+ this.installPackageManager = this.normalizeInstallPackageManager(installRes.packageManager);
46
+ }
47
+ }
48
+ } catch (_) {}
37
49
  {
38
50
  const tier = typeof statusRes.serviceTier === 'string'
39
51
  ? statusRes.serviceTier.trim().toLowerCase()
@@ -12,11 +12,11 @@ function createDefaultTaskOrchestrationState() {
12
12
  followUpsText: '',
13
13
  workflowIdsText: '',
14
14
  selectedEngine: 'codex',
15
- allowWrite: false,
16
- dryRun: false,
15
+ runMode: 'write',
17
16
  concurrency: 2,
18
17
  autoFixRounds: 1,
19
18
  plan: null,
19
+ planFingerprint: '',
20
20
  planIssues: [],
21
21
  planWarnings: [],
22
22
  overviewWarnings: [],
@@ -62,6 +62,22 @@ function isActiveStatus(status) {
62
62
  return normalized === 'running' || normalized === 'queued';
63
63
  }
64
64
 
65
+ function normalizeTaskRunMode(value) {
66
+ const normalized = String(value || '').trim().toLowerCase();
67
+ if (normalized === 'read') return 'read';
68
+ if (normalized === 'dry-run' || normalized === 'dryrun' || normalized === 'plan') return 'dry-run';
69
+ return 'write';
70
+ }
71
+
72
+ function buildRunModeFlags(runMode) {
73
+ const normalized = normalizeTaskRunMode(runMode);
74
+ return {
75
+ runMode: normalized,
76
+ allowWrite: normalized === 'write',
77
+ dryRun: normalized === 'dry-run'
78
+ };
79
+ }
80
+
65
81
  export function createTaskOrchestrationMethods(options = {}) {
66
82
  const { api } = options;
67
83
 
@@ -75,6 +91,7 @@ export function createTaskOrchestrationMethods(options = {}) {
75
91
  current[key] = value;
76
92
  }
77
93
  }
94
+ current.runMode = normalizeTaskRunMode(current.runMode);
78
95
  return current;
79
96
  }
80
97
  this.taskOrchestration = createDefaultTaskOrchestrationState();
@@ -83,6 +100,7 @@ export function createTaskOrchestrationMethods(options = {}) {
83
100
 
84
101
  buildTaskOrchestrationRequest() {
85
102
  const state = this.ensureTaskOrchestrationState();
103
+ const flags = buildRunModeFlags(state.runMode);
86
104
  return {
87
105
  title: String(state.title || '').trim(),
88
106
  target: String(state.target || '').trim(),
@@ -90,13 +108,29 @@ export function createTaskOrchestrationMethods(options = {}) {
90
108
  followUps: normalizeLines(state.followUpsText),
91
109
  workflowIds: normalizeLines(state.workflowIdsText),
92
110
  engine: String(state.selectedEngine || 'codex').trim().toLowerCase() === 'workflow' ? 'workflow' : 'codex',
93
- allowWrite: state.allowWrite === true,
94
- dryRun: state.dryRun === true,
111
+ allowWrite: flags.allowWrite,
112
+ dryRun: flags.dryRun,
95
113
  concurrency: normalizePositiveInteger(state.concurrency, 2, 1, 8),
96
114
  autoFixRounds: normalizePositiveInteger(state.autoFixRounds, 1, 0, 5)
97
115
  };
98
116
  },
99
117
 
118
+ buildTaskOrchestrationFingerprint() {
119
+ const req = this.buildTaskOrchestrationRequest();
120
+ return JSON.stringify({
121
+ title: req.title,
122
+ target: req.target,
123
+ notes: req.notes,
124
+ followUps: req.followUps,
125
+ workflowIds: req.workflowIds,
126
+ engine: req.engine,
127
+ allowWrite: req.allowWrite,
128
+ dryRun: req.dryRun,
129
+ concurrency: req.concurrency,
130
+ autoFixRounds: req.autoFixRounds
131
+ });
132
+ },
133
+
100
134
  taskRunStatusTone(status) {
101
135
  return normalizeTaskStatusTone(status);
102
136
  },
@@ -190,6 +224,7 @@ export function createTaskOrchestrationMethods(options = {}) {
190
224
  state.plan = res && res.plan ? res.plan : null;
191
225
  state.planIssues = Array.isArray(res && res.issues) ? res.issues : [];
192
226
  state.planWarnings = Array.isArray(res && res.warnings) ? res.warnings : [];
227
+ state.planFingerprint = state.plan ? this.buildTaskOrchestrationFingerprint() : '';
193
228
  if (res && res.error) {
194
229
  if (!options.silent) {
195
230
  this.showMessage(res.error, 'error');
@@ -246,7 +281,7 @@ export function createTaskOrchestrationMethods(options = {}) {
246
281
  }
247
282
  },
248
283
 
249
- async addTaskOrchestrationToQueue() {
284
+ async addTaskOrchestrationToQueue(options = {}) {
250
285
  const state = this.ensureTaskOrchestrationState();
251
286
  if (state.queueAdding) {
252
287
  return null;
@@ -255,21 +290,72 @@ export function createTaskOrchestrationMethods(options = {}) {
255
290
  try {
256
291
  const res = await api('task-queue-add', this.buildTaskOrchestrationRequest());
257
292
  if (res && res.error) {
258
- this.showMessage(res.error, 'error');
293
+ if (!options.silent) {
294
+ this.showMessage(res.error, 'error');
295
+ }
259
296
  return res;
260
297
  }
261
- await this.loadTaskOrchestrationOverview({ silent: true, includeDetail: false });
262
- this.showMessage(`已加入队列: ${res && res.task ? res.task.taskId : ''}`.trim(), 'success');
298
+ if (!options.deferRefresh) {
299
+ await this.loadTaskOrchestrationOverview({ silent: true, includeDetail: false });
300
+ }
301
+ if (!options.silent) {
302
+ this.showMessage(`已加入队列: ${res && res.task ? res.task.taskId : ''}`.trim(), 'success');
303
+ }
263
304
  return res;
264
305
  } catch (error) {
265
306
  const message = error && error.message ? error.message : '加入队列失败';
266
- this.showMessage(message, 'error');
307
+ if (!options.silent) {
308
+ this.showMessage(message, 'error');
309
+ }
267
310
  return { error: message };
268
311
  } finally {
269
312
  state.queueAdding = false;
270
313
  }
271
314
  },
272
315
 
316
+ async planAndRunTaskOrchestration() {
317
+ const state = this.ensureTaskOrchestrationState();
318
+ if (state.running || state.planning) {
319
+ return null;
320
+ }
321
+ if (!String(state.target || '').trim()) {
322
+ return null;
323
+ }
324
+ if (buildRunModeFlags(state.runMode).dryRun) {
325
+ return this.previewTaskPlan({ silent: false });
326
+ }
327
+ const fingerprint = this.buildTaskOrchestrationFingerprint();
328
+ const shouldPreview = !state.plan || state.planFingerprint !== fingerprint;
329
+ if (shouldPreview) {
330
+ const preview = await this.previewTaskPlan({ silent: true });
331
+ if (preview && preview.error) {
332
+ this.showMessage(preview.error, 'error');
333
+ return preview;
334
+ }
335
+ }
336
+ if (state.planIssues && state.planIssues.length) {
337
+ this.showMessage('计划存在问题,请先修复再执行', 'error');
338
+ return { error: 'Plan has blocking issues' };
339
+ }
340
+ return this.runTaskOrchestration();
341
+ },
342
+
343
+ async queueTaskOrchestrationAndStart() {
344
+ const state = this.ensureTaskOrchestrationState();
345
+ if (state.queueAdding || state.queueStarting || state.planning || state.running) {
346
+ return null;
347
+ }
348
+ if (!String(state.target || '').trim()) {
349
+ return null;
350
+ }
351
+ const queued = await this.addTaskOrchestrationToQueue({ silent: true, deferRefresh: true });
352
+ if (queued && queued.error) {
353
+ this.showMessage(queued.error, 'error');
354
+ return queued;
355
+ }
356
+ return this.startTaskQueueRunner();
357
+ },
358
+
273
359
  async startTaskQueueRunner() {
274
360
  const state = this.ensureTaskOrchestrationState();
275
361
  if (state.queueStarting) {
@@ -457,8 +543,7 @@ export function createTaskOrchestrationMethods(options = {}) {
457
543
  state.followUpsText = '';
458
544
  state.workflowIdsText = '';
459
545
  state.selectedEngine = 'codex';
460
- state.allowWrite = false;
461
- state.dryRun = false;
546
+ state.runMode = 'write';
462
547
  state.concurrency = 2;
463
548
  state.autoFixRounds = 1;
464
549
  state.plan = null;
@@ -47,6 +47,7 @@ export function createConfigModeComputed() {
47
47
  return `${this.activeProviderModeLabel} 当前复用 Codex Provider / Model 管理链路。`;
48
48
  },
49
49
  inspectorMainTabLabel() {
50
+ if (this.mainTab === 'dashboard') return '概览';
50
51
  if (this.mainTab === 'config') return '配置中心';
51
52
  if (this.mainTab === 'sessions') return '会话浏览';
52
53
  if (this.mainTab === 'usage') return 'Usage';
@@ -56,7 +57,6 @@ export function createConfigModeComputed() {
56
57
  return '未知';
57
58
  },
58
59
  inspectorConfigModeLabel() {
59
- if (this.mainTab !== 'config') return '--';
60
60
  const providerMeta = getProviderConfigModeMeta(this.configMode);
61
61
  if (providerMeta) return providerMeta.label;
62
62
  if (this.configMode === 'claude') return 'Claude Code';
@@ -64,7 +64,6 @@ export function createConfigModeComputed() {
64
64
  return '未选择';
65
65
  },
66
66
  inspectorCurrentConfigLabel() {
67
- if (this.mainTab !== 'config') return '--';
68
67
  if (getProviderConfigModeMeta(this.configMode)) {
69
68
  const provider = typeof this.currentProvider === 'string' ? this.currentProvider.trim() : '';
70
69
  return provider || '未选择';
@@ -80,7 +79,6 @@ export function createConfigModeComputed() {
80
79
  return '未选择';
81
80
  },
82
81
  inspectorCurrentModelLabel() {
83
- if (this.mainTab !== 'config') return '--';
84
82
  if (getProviderConfigModeMeta(this.configMode)) {
85
83
  const model = typeof this.currentModel === 'string' ? this.currentModel.trim() : '';
86
84
  return model || '未选择';