codexmate 0.0.20 → 0.0.21

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 (102) hide show
  1. package/README.en.md +349 -259
  2. package/README.md +284 -252
  3. package/cli/agents-files.js +162 -0
  4. package/cli/archive-helpers.js +446 -0
  5. package/cli/auth-profiles.js +359 -0
  6. package/cli/builtin-proxy.js +580 -0
  7. package/cli/claude-proxy.js +998 -0
  8. package/cli/config-bootstrap.js +384 -0
  9. package/cli/config-health.js +338 -338
  10. package/cli/openclaw-config.js +629 -0
  11. package/cli/skills.js +1141 -0
  12. package/cli/zip-commands.js +510 -0
  13. package/cli.js +13101 -13497
  14. package/lib/cli-file-utils.js +151 -151
  15. package/lib/cli-models-utils.js +419 -311
  16. package/lib/cli-network-utils.js +164 -164
  17. package/lib/cli-path-utils.js +69 -0
  18. package/lib/cli-session-utils.js +121 -121
  19. package/lib/cli-sessions.js +386 -0
  20. package/lib/cli-utils.js +155 -155
  21. package/lib/download-artifacts.js +77 -0
  22. package/lib/mcp-stdio.js +440 -440
  23. package/lib/task-orchestrator.js +869 -0
  24. package/lib/text-diff.js +303 -303
  25. package/lib/workflow-engine.js +340 -340
  26. package/package.json +74 -70
  27. package/res/json5.min.js +1 -1
  28. package/res/vue.global.prod.js +13 -0
  29. package/web-ui/app.js +530 -397
  30. package/web-ui/index.html +33 -30
  31. package/web-ui/logic.agents-diff.mjs +386 -386
  32. package/web-ui/logic.claude.mjs +168 -108
  33. package/web-ui/logic.mjs +5 -5
  34. package/web-ui/logic.runtime.mjs +124 -124
  35. package/web-ui/logic.sessions.mjs +581 -263
  36. package/web-ui/modules/api.mjs +90 -69
  37. package/web-ui/modules/app.computed.dashboard.mjs +113 -113
  38. package/web-ui/modules/app.computed.index.mjs +15 -13
  39. package/web-ui/modules/app.computed.main-tabs.mjs +195 -0
  40. package/web-ui/modules/app.computed.session.mjs +507 -141
  41. package/web-ui/modules/app.constants.mjs +15 -15
  42. package/web-ui/modules/app.methods.agents.mjs +493 -493
  43. package/web-ui/modules/app.methods.claude-config.mjs +174 -174
  44. package/web-ui/modules/app.methods.codex-config.mjs +640 -640
  45. package/web-ui/modules/app.methods.index.mjs +88 -86
  46. package/web-ui/modules/app.methods.install.mjs +149 -157
  47. package/web-ui/modules/app.methods.navigation.mjs +619 -478
  48. package/web-ui/modules/app.methods.openclaw-core.mjs +814 -514
  49. package/web-ui/modules/app.methods.openclaw-editing.mjs +372 -337
  50. package/web-ui/modules/app.methods.openclaw-persist.mjs +369 -251
  51. package/web-ui/modules/app.methods.providers.mjs +363 -265
  52. package/web-ui/modules/app.methods.runtime.mjs +323 -323
  53. package/web-ui/modules/app.methods.session-actions.mjs +520 -457
  54. package/web-ui/modules/app.methods.session-browser.mjs +626 -435
  55. package/web-ui/modules/app.methods.session-timeline.mjs +448 -441
  56. package/web-ui/modules/app.methods.session-trash.mjs +422 -419
  57. package/web-ui/modules/app.methods.startup-claude.mjs +412 -406
  58. package/web-ui/modules/app.methods.task-orchestration.mjs +471 -0
  59. package/web-ui/modules/config-mode.computed.mjs +126 -124
  60. package/web-ui/modules/skills.computed.mjs +107 -107
  61. package/web-ui/modules/skills.methods.mjs +481 -481
  62. package/web-ui/partials/index/layout-footer.html +13 -69
  63. package/web-ui/partials/index/layout-header.html +402 -337
  64. package/web-ui/partials/index/modal-config-template-agents.html +125 -125
  65. package/web-ui/partials/index/modal-confirm-toast.html +32 -32
  66. package/web-ui/partials/index/modal-health-check.html +72 -72
  67. package/web-ui/partials/index/modal-openclaw-config.html +280 -275
  68. package/web-ui/partials/index/modal-skills.html +184 -184
  69. package/web-ui/partials/index/modals-basic.html +156 -196
  70. package/web-ui/partials/index/panel-config-claude.html +126 -100
  71. package/web-ui/partials/index/panel-config-codex.html +237 -237
  72. package/web-ui/partials/index/panel-config-openclaw.html +78 -84
  73. package/web-ui/partials/index/panel-docs.html +130 -0
  74. package/web-ui/partials/index/panel-market.html +174 -174
  75. package/web-ui/partials/index/panel-orchestration.html +397 -0
  76. package/web-ui/partials/index/panel-sessions.html +292 -387
  77. package/web-ui/partials/index/panel-settings.html +190 -166
  78. package/web-ui/partials/index/panel-usage.html +213 -0
  79. package/web-ui/session-helpers.mjs +559 -362
  80. package/web-ui/source-bundle.cjs +233 -233
  81. package/web-ui/styles/base-theme.css +271 -373
  82. package/web-ui/styles/controls-forms.css +360 -354
  83. package/web-ui/styles/docs-panel.css +182 -0
  84. package/web-ui/styles/feedback.css +108 -108
  85. package/web-ui/styles/health-check-dialog.css +144 -144
  86. package/web-ui/styles/layout-shell.css +376 -330
  87. package/web-ui/styles/modals-core.css +464 -449
  88. package/web-ui/styles/navigation-panels.css +348 -381
  89. package/web-ui/styles/openclaw-structured.css +266 -266
  90. package/web-ui/styles/responsive.css +450 -416
  91. package/web-ui/styles/sessions-list.css +400 -414
  92. package/web-ui/styles/sessions-preview.css +411 -405
  93. package/web-ui/styles/sessions-toolbar-trash.css +243 -243
  94. package/web-ui/styles/sessions-usage.css +628 -276
  95. package/web-ui/styles/skills-list.css +296 -298
  96. package/web-ui/styles/skills-market.css +335 -335
  97. package/web-ui/styles/task-orchestration.css +776 -0
  98. package/web-ui/styles/titles-cards.css +408 -407
  99. package/web-ui/styles.css +18 -16
  100. package/web-ui.html +17 -17
  101. package/res/screenshot.png +0 -0
  102. package/res/vue.global.js +0 -18552
@@ -1,69 +1,90 @@
1
- const browserLocation = typeof location !== 'undefined' ? location : null;
2
-
3
- export const API_BASE = (browserLocation && browserLocation.origin && browserLocation.origin !== 'null')
4
- ? browserLocation.origin
5
- : 'http://localhost:3737';
6
-
7
- async function postApi(action, params = {}) {
8
- return await fetch(`${API_BASE}/api`, {
9
- method: 'POST',
10
- headers: { 'Content-Type': 'application/json' },
11
- body: JSON.stringify({ action, params })
12
- });
13
- }
14
-
15
- function buildApiResponseContext(action, res, contentType) {
16
- return `${action} (${res.status} ${res.statusText}, content-type: ${contentType || 'unknown'})`;
17
- }
18
-
19
- function withPayloadTooLargeErrorCode(res, payload) {
20
- if (res.status !== 413 || (payload && typeof payload === 'object' && payload.errorCode)) {
21
- return payload;
22
- }
23
- return { ...payload, errorCode: 'payload-too-large' };
24
- }
25
-
26
- export async function api(action, params = {}) {
27
- const res = await postApi(action, params);
28
- const contentType = String(res.headers.get('content-type') || '').toLowerCase();
29
- if (contentType && !contentType.includes('application/json')) {
30
- const body = await res.text();
31
- const errorDetails = buildApiResponseContext(action, res, contentType);
32
- const bodyDetails = body ? `: ${body}` : '';
33
- throw new Error(`Unexpected non-JSON API response for ${errorDetails}${bodyDetails}`);
34
- }
35
- try {
36
- return await res.json();
37
- } catch (error) {
38
- const errorDetails = buildApiResponseContext(action, res, contentType);
39
- throw new Error(`Failed to parse API response for ${errorDetails}: ${error.message}`);
40
- }
41
- }
42
-
43
- export async function apiWithMeta(action, params = {}) {
44
- const res = await postApi(action, params);
45
- const contentType = String(res.headers.get('content-type') || '').toLowerCase();
46
- if (contentType.includes('application/json')) {
47
- try {
48
- const payload = await res.json();
49
- if (payload && typeof payload === 'object' && !Array.isArray(payload)) {
50
- return { ...withPayloadTooLargeErrorCode(res, payload), ok: res.ok, status: res.status };
51
- }
52
- return res.status === 413
53
- ? { ok: res.ok, status: res.status, data: payload, errorCode: 'payload-too-large' }
54
- : { ok: res.ok, status: res.status, data: payload };
55
- } catch (error) {
56
- if (res.status === 413) {
57
- return { ok: false, status: 413, errorCode: 'payload-too-large' };
58
- }
59
- throw error;
60
- }
61
- }
62
- const error = await res.text();
63
- return {
64
- ok: res.ok,
65
- status: res.status,
66
- error,
67
- errorCode: res.status === 413 ? 'payload-too-large' : ''
68
- };
69
- }
1
+ const browserLocation = typeof location !== 'undefined' ? location : null;
2
+
3
+ export const API_BASE = (browserLocation && browserLocation.origin && browserLocation.origin !== 'null')
4
+ ? browserLocation.origin
5
+ : 'http://localhost:3737';
6
+
7
+ async function postApi(action, params = {}) {
8
+ return await fetch(`${API_BASE}/api`, {
9
+ method: 'POST',
10
+ headers: { 'Content-Type': 'application/json' },
11
+ body: JSON.stringify({ action, params })
12
+ });
13
+ }
14
+
15
+ function buildApiResponseContext(action, res, contentType) {
16
+ return `${action} (${res.status} ${res.statusText}, content-type: ${contentType || 'unknown'})`;
17
+ }
18
+
19
+ function formatUnexpectedApiBodySnippet(body, contentType) {
20
+ const raw = typeof body === 'string' ? body.trim() : '';
21
+ if (!raw) {
22
+ return '';
23
+ }
24
+ const normalizedContentType = String(contentType || '').toLowerCase();
25
+ const looksLikeHtml = normalizedContentType.includes('text/html')
26
+ || /<!doctype\s+html|<html[\s>]|<head[\s>]|<body[\s>]/i.test(raw);
27
+ if (looksLikeHtml) {
28
+ return '';
29
+ }
30
+ const singleLine = raw.replace(/\s+/g, ' ').trim();
31
+ if (!singleLine) {
32
+ return '';
33
+ }
34
+ return singleLine.length > 200
35
+ ? `${singleLine.slice(0, 197)}...`
36
+ : singleLine;
37
+ }
38
+
39
+ function withPayloadTooLargeErrorCode(res, payload) {
40
+ if (res.status !== 413 || (payload && typeof payload === 'object' && payload.errorCode)) {
41
+ return payload;
42
+ }
43
+ return { ...payload, errorCode: 'payload-too-large' };
44
+ }
45
+
46
+ export async function api(action, params = {}) {
47
+ const res = await postApi(action, params);
48
+ const contentType = String(res.headers.get('content-type') || '').toLowerCase();
49
+ if (contentType && !contentType.includes('application/json')) {
50
+ const body = await res.text();
51
+ const errorDetails = buildApiResponseContext(action, res, contentType);
52
+ const bodySnippet = formatUnexpectedApiBodySnippet(body, contentType);
53
+ const bodyDetails = bodySnippet ? `: ${bodySnippet}` : '';
54
+ throw new Error(`Unexpected non-JSON API response for ${errorDetails}${bodyDetails}`);
55
+ }
56
+ try {
57
+ return await res.json();
58
+ } catch (error) {
59
+ const errorDetails = buildApiResponseContext(action, res, contentType);
60
+ throw new Error(`Failed to parse API response for ${errorDetails}: ${error.message}`);
61
+ }
62
+ }
63
+
64
+ export async function apiWithMeta(action, params = {}) {
65
+ const res = await postApi(action, params);
66
+ const contentType = String(res.headers.get('content-type') || '').toLowerCase();
67
+ if (contentType.includes('application/json')) {
68
+ try {
69
+ const payload = await res.json();
70
+ if (payload && typeof payload === 'object' && !Array.isArray(payload)) {
71
+ return { ...withPayloadTooLargeErrorCode(res, payload), ok: res.ok, status: res.status };
72
+ }
73
+ return res.status === 413
74
+ ? { ok: res.ok, status: res.status, data: payload, errorCode: 'payload-too-large' }
75
+ : { ok: res.ok, status: res.status, data: payload };
76
+ } catch (error) {
77
+ if (res.status === 413) {
78
+ return { ok: false, status: 413, errorCode: 'payload-too-large' };
79
+ }
80
+ throw error;
81
+ }
82
+ }
83
+ const error = await res.text();
84
+ return {
85
+ ok: res.ok,
86
+ status: res.status,
87
+ error,
88
+ errorCode: res.status === 413 ? 'payload-too-large' : ''
89
+ };
90
+ }
@@ -1,113 +1,113 @@
1
- export function createDashboardComputed() {
2
- return {
3
- agentsDiffHasChanges() {
4
- if (this.agentsDiffTruncated) {
5
- return !!this.agentsDiffHasChangesValue;
6
- }
7
- const stats = this.agentsDiffStats || {};
8
- const added = Number(stats.added || 0);
9
- const removed = Number(stats.removed || 0);
10
- return added > 0 || removed > 0;
11
- },
12
- claudeModelHasList() {
13
- return this.claudeModelOptions.length > 0;
14
- },
15
- claudeModelOptions() {
16
- const list = Array.isArray(this.claudeModels) ? [...this.claudeModels] : [];
17
- const current = (this.currentClaudeModel || '').trim();
18
- if (current && !list.includes(current)) {
19
- list.unshift(current);
20
- }
21
- return list;
22
- },
23
- hasLocalAndProxy() {
24
- return false;
25
- },
26
- displayCurrentProvider() {
27
- const switching = String(this.providerSwitchDisplayTarget || '').trim();
28
- if (switching) return switching;
29
- const current = String(this.currentProvider || '').trim();
30
- return current;
31
- },
32
- displayProvidersList() {
33
- const list = Array.isArray(this.providersList) ? this.providersList : [];
34
- return list.filter((item) => String(item && item.name ? item.name : '').trim().toLowerCase() !== 'codexmate-proxy');
35
- },
36
- installTargetCards() {
37
- const targets = Array.isArray(this.installStatusTargets) ? this.installStatusTargets : [];
38
- const action = this.normalizeInstallAction(this.installCommandAction);
39
- return targets.map((target) => {
40
- const id = target && typeof target.id === 'string' ? target.id : '';
41
- return {
42
- ...target,
43
- command: this.getInstallCommand(id, action)
44
- };
45
- });
46
- },
47
- installRegistryPreview() {
48
- return this.resolveInstallRegistryUrl(this.installRegistryPreset, this.installRegistryCustom);
49
- },
50
- inspectorBusyStatus() {
51
- const tasks = [];
52
- if (this.loading) tasks.push('初始化');
53
- if (this.sessionsLoading) tasks.push('会话加载');
54
- if (this.codexModelsLoading || this.claudeModelsLoading) tasks.push('模型加载');
55
- if (this.codexApplying || this.configTemplateApplying || this.openclawApplying) tasks.push('配置应用');
56
- if (this.agentsSaving) tasks.push('AGENTS 保存');
57
- if (this.skillsLoading || this.skillsDeleting || this.skillsScanningImports || this.skillsImporting || this.skillsZipImporting || this.skillsExporting) tasks.push('Skills 管理');
58
- return tasks.length ? tasks.join(' / ') : '空闲';
59
- },
60
- inspectorMessageSummary() {
61
- const value = typeof this.message === 'string' ? this.message.trim() : '';
62
- return value || '暂无提示';
63
- },
64
- inspectorSessionSourceLabel() {
65
- if (this.sessionFilterSource === 'codex') return 'Codex';
66
- if (this.sessionFilterSource === 'claude') return 'Claude Code';
67
- return '全部';
68
- },
69
- inspectorSessionPathLabel() {
70
- const value = typeof this.sessionPathFilter === 'string' ? this.sessionPathFilter.trim() : '';
71
- return value || '全部路径';
72
- },
73
- inspectorSessionQueryLabel() {
74
- if (!this.isSessionQueryEnabled) return '当前来源不支持';
75
- const value = typeof this.sessionQuery === 'string' ? this.sessionQuery.trim() : '';
76
- return value || '未设置';
77
- },
78
- inspectorHealthStatus() {
79
- if (this.initError) return '读取失败';
80
- if (this.loading) return '初始化中';
81
- return '正常';
82
- },
83
- inspectorHealthTone() {
84
- if (this.initError) return 'error';
85
- if (this.loading) return 'warn';
86
- return 'ok';
87
- },
88
- inspectorModelLoadStatus() {
89
- if (this.codexModelsLoading || this.claudeModelsLoading) {
90
- return '加载中';
91
- }
92
- if (this.modelsSource === 'error' || this.claudeModelsSource === 'error') {
93
- return '加载异常';
94
- }
95
- return '正常';
96
- },
97
- installTroubleshootingTips() {
98
- const platform = this.resolveInstallPlatform();
99
- if (platform === 'win32') {
100
- return [
101
- 'PowerShell 报权限不足(EACCES/EPERM)时,请以管理员身份执行安装命令。',
102
- '安装后若仍提示找不到命令,重开终端并执行:where codex / where claude。',
103
- '公司网络受限时,可先切换镜像源快捷项(npmmirror / 腾讯云 / 自定义)。'
104
- ];
105
- }
106
- return [
107
- '出现 EACCES 权限错误时,优先修复 Node 全局目录权限,不建议直接 sudo npm。',
108
- '安装后若命令未生效,重开终端并执行:which codex / which claude。',
109
- '公司网络受限时,可先切换镜像源快捷项(npmmirror / 腾讯云 / 自定义)。'
110
- ];
111
- }
112
- };
113
- }
1
+ export function createDashboardComputed() {
2
+ return {
3
+ agentsDiffHasChanges() {
4
+ if (this.agentsDiffTruncated) {
5
+ return !!this.agentsDiffHasChangesValue;
6
+ }
7
+ const stats = this.agentsDiffStats || {};
8
+ const added = Number(stats.added || 0);
9
+ const removed = Number(stats.removed || 0);
10
+ return added > 0 || removed > 0;
11
+ },
12
+ claudeModelHasList() {
13
+ return this.claudeModelOptions.length > 0;
14
+ },
15
+ claudeModelOptions() {
16
+ const list = Array.isArray(this.claudeModels) ? [...this.claudeModels] : [];
17
+ const current = (this.currentClaudeModel || '').trim();
18
+ if (current && !list.includes(current)) {
19
+ list.unshift(current);
20
+ }
21
+ return list;
22
+ },
23
+ displayCurrentProvider() {
24
+ const switching = String(this.providerSwitchDisplayTarget || '').trim();
25
+ if (switching) return switching;
26
+ const current = String(this.currentProvider || '').trim();
27
+ return current;
28
+ },
29
+ displayProvidersList() {
30
+ const list = Array.isArray(this.providersList) ? this.providersList : [];
31
+ return list.filter((item) => String(item && item.name ? item.name : '').trim().toLowerCase() !== 'codexmate-proxy');
32
+ },
33
+ installTargetCards() {
34
+ const targets = Array.isArray(this.installStatusTargets) ? this.installStatusTargets : [];
35
+ const action = this.normalizeInstallAction(this.installCommandAction);
36
+ return targets.map((target) => {
37
+ const id = target && typeof target.id === 'string' ? target.id : '';
38
+ return {
39
+ ...target,
40
+ command: this.getInstallCommand(id, action)
41
+ };
42
+ });
43
+ },
44
+ installRegistryPreview() {
45
+ return this.resolveInstallRegistryUrl(this.installRegistryPreset, this.installRegistryCustom);
46
+ },
47
+ inspectorBusyStatus() {
48
+ const tasks = [];
49
+ if (this.loading) tasks.push('初始化');
50
+ if (this.sessionsLoading) tasks.push('会话加载');
51
+ if (this.codexModelsLoading || this.claudeModelsLoading) tasks.push('模型加载');
52
+ if (this.codexApplying || this.configTemplateApplying || this.openclawApplying) tasks.push('配置应用');
53
+ if (this.agentsSaving) tasks.push('AGENTS 保存');
54
+ if (this.skillsLoading || this.skillsDeleting || this.skillsScanningImports || this.skillsImporting || this.skillsZipImporting || this.skillsExporting) tasks.push('Skills 管理');
55
+ if (this.taskOrchestration && (this.taskOrchestration.loading || this.taskOrchestration.planning || this.taskOrchestration.running || this.taskOrchestration.queueAdding || this.taskOrchestration.queueStarting || this.taskOrchestration.retrying || this.taskOrchestration.selectedRunLoading)) {
56
+ tasks.push('任务编排');
57
+ }
58
+ return tasks.length ? tasks.join(' / ') : '空闲';
59
+ },
60
+ inspectorMessageSummary() {
61
+ const value = typeof this.message === 'string' ? this.message.trim() : '';
62
+ return value || '暂无提示';
63
+ },
64
+ inspectorSessionSourceLabel() {
65
+ if (this.sessionFilterSource === 'codex') return 'Codex';
66
+ if (this.sessionFilterSource === 'claude') return 'Claude Code';
67
+ return '全部';
68
+ },
69
+ inspectorSessionPathLabel() {
70
+ const value = typeof this.sessionPathFilter === 'string' ? this.sessionPathFilter.trim() : '';
71
+ return value || '全部路径';
72
+ },
73
+ inspectorSessionQueryLabel() {
74
+ if (!this.isSessionQueryEnabled) return '当前来源不支持';
75
+ const value = typeof this.sessionQuery === 'string' ? this.sessionQuery.trim() : '';
76
+ return value || '未设置';
77
+ },
78
+ inspectorHealthStatus() {
79
+ if (this.initError) return '读取失败';
80
+ if (this.loading) return '初始化中';
81
+ return '正常';
82
+ },
83
+ inspectorHealthTone() {
84
+ if (this.initError) return 'error';
85
+ if (this.loading) return 'warn';
86
+ return 'ok';
87
+ },
88
+ inspectorModelLoadStatus() {
89
+ if (this.codexModelsLoading || this.claudeModelsLoading) {
90
+ return '加载中';
91
+ }
92
+ if (this.modelsSource === 'error' || this.claudeModelsSource === 'error') {
93
+ return '加载异常';
94
+ }
95
+ return '正常';
96
+ },
97
+ installTroubleshootingTips() {
98
+ const platform = this.resolveInstallPlatform();
99
+ if (platform === 'win32') {
100
+ return [
101
+ 'PowerShell 报权限不足(EACCES/EPERM)时,请以管理员身份执行安装命令。',
102
+ '安装后若仍提示找不到命令,重开终端并执行:where codex / where claude。',
103
+ '公司网络受限时,可先切换镜像源快捷项(npmmirror / 腾讯云 / 自定义)。'
104
+ ];
105
+ }
106
+ return [
107
+ '出现 EACCES 权限错误时,优先修复 Node 全局目录权限,不建议直接 sudo npm。',
108
+ '安装后若命令未生效,重开终端并执行:which codex / which claude。',
109
+ '公司网络受限时,可先切换镜像源快捷项(npmmirror / 腾讯云 / 自定义)。'
110
+ ];
111
+ }
112
+ };
113
+ }
@@ -1,13 +1,15 @@
1
- import { createDashboardComputed } from './app.computed.dashboard.mjs';
2
- import { createSessionComputed } from './app.computed.session.mjs';
3
- import { createConfigModeComputed } from './config-mode.computed.mjs';
4
- import { createSkillsComputed } from './skills.computed.mjs';
5
-
6
- export function createAppComputed() {
7
- return {
8
- ...createSessionComputed(),
9
- ...createDashboardComputed(),
10
- ...createSkillsComputed(),
11
- ...createConfigModeComputed()
12
- };
13
- }
1
+ import { createDashboardComputed } from './app.computed.dashboard.mjs';
2
+ import { createMainTabsComputed } from './app.computed.main-tabs.mjs';
3
+ import { createSessionComputed } from './app.computed.session.mjs';
4
+ import { createConfigModeComputed } from './config-mode.computed.mjs';
5
+ import { createSkillsComputed } from './skills.computed.mjs';
6
+
7
+ export function createAppComputed() {
8
+ return {
9
+ ...createSessionComputed(),
10
+ ...createDashboardComputed(),
11
+ ...createMainTabsComputed(),
12
+ ...createSkillsComputed(),
13
+ ...createConfigModeComputed()
14
+ };
15
+ }
@@ -0,0 +1,195 @@
1
+ function normalizeTaskDraftLines(text) {
2
+ return String(text || '')
3
+ .split(/\r?\n/g)
4
+ .map((item) => item.trim())
5
+ .filter(Boolean);
6
+ }
7
+
8
+ function readTaskOrchestrationDraftMetrics(taskOrchestration) {
9
+ const state = taskOrchestration && typeof taskOrchestration === 'object' ? taskOrchestration : {};
10
+ const target = String(state.target || '').trim();
11
+ const notes = String(state.notes || '').trim();
12
+ const title = String(state.title || '').trim();
13
+ const workflowIds = normalizeTaskDraftLines(state.workflowIdsText);
14
+ const followUps = normalizeTaskDraftLines(state.followUpsText);
15
+ const engine = String(state.selectedEngine || 'codex').trim().toLowerCase() === 'workflow' ? 'workflow' : 'codex';
16
+ const plan = state.plan && typeof state.plan === 'object' ? state.plan : null;
17
+ const planNodes = Array.isArray(plan && plan.nodes) ? plan.nodes : [];
18
+ const planIssues = Array.isArray(state.planIssues) ? state.planIssues : [];
19
+ const planWarnings = Array.isArray(state.planWarnings) ? state.planWarnings : [];
20
+ return {
21
+ engine,
22
+ title,
23
+ target,
24
+ notes,
25
+ workflowIds,
26
+ followUps,
27
+ hasTarget: target.length > 0,
28
+ hasNotes: notes.length > 0,
29
+ hasTitle: title.length > 0,
30
+ hasPlan: !!plan,
31
+ planNodes,
32
+ planIssues,
33
+ planWarnings,
34
+ workflowCount: workflowIds.length,
35
+ followUpCount: followUps.length,
36
+ planNodeCount: planNodes.length,
37
+ allowWrite: state.allowWrite === true,
38
+ dryRun: state.dryRun === true
39
+ };
40
+ }
41
+
42
+ function createTaskDraftChecklist(metrics) {
43
+ const workflowReady = metrics.engine !== 'workflow' || metrics.workflowCount > 0;
44
+ const scopeReady = metrics.hasNotes || !metrics.allowWrite;
45
+ const previewReady = metrics.hasPlan && metrics.planIssues.length === 0;
46
+ return [
47
+ {
48
+ key: 'target',
49
+ label: '目标',
50
+ done: metrics.hasTarget,
51
+ detail: metrics.hasTarget ? '已写目标' : '还没写目标'
52
+ },
53
+ {
54
+ key: 'engine',
55
+ label: metrics.engine === 'workflow' ? 'Workflow' : '执行策略',
56
+ done: workflowReady,
57
+ detail: metrics.engine === 'workflow'
58
+ ? (metrics.workflowCount > 0 ? `已选 ${metrics.workflowCount} 个 Workflow` : '还没选 Workflow ID')
59
+ : '使用 Codex 规划节点'
60
+ },
61
+ {
62
+ key: 'scope',
63
+ label: '边界',
64
+ done: scopeReady,
65
+ detail: metrics.hasNotes
66
+ ? '已补充说明'
67
+ : (metrics.allowWrite ? '建议补说明后再写入' : '当前是只读,可直接试')
68
+ },
69
+ {
70
+ key: 'preview',
71
+ label: '预览',
72
+ done: previewReady,
73
+ detail: !metrics.hasPlan
74
+ ? '还没生成计划'
75
+ : (metrics.planIssues.length > 0 ? `有 ${metrics.planIssues.length} 个阻塞项` : `计划可用,${metrics.planNodeCount} 个节点`)
76
+ }
77
+ ];
78
+ }
79
+
80
+ function createTaskDraftReadiness(metrics) {
81
+ if (!metrics.hasTarget) {
82
+ return {
83
+ tone: 'neutral',
84
+ title: '先写目标',
85
+ summary: '先把想完成的结果写清楚,再让编排器拆节点。'
86
+ };
87
+ }
88
+ if (metrics.engine === 'workflow' && metrics.workflowCount === 0) {
89
+ return {
90
+ tone: 'warn',
91
+ title: '缺少 Workflow',
92
+ summary: '你已经选了 Workflow 模式,但还没指定可复用流程。'
93
+ };
94
+ }
95
+ if (!metrics.hasPlan) {
96
+ return {
97
+ tone: 'warn',
98
+ title: '建议先预览',
99
+ summary: '草稿已成形,先生成一次计划,确认节点和依赖再执行。'
100
+ };
101
+ }
102
+ if (metrics.planIssues.length > 0) {
103
+ return {
104
+ tone: 'error',
105
+ title: '预览有阻塞',
106
+ summary: `当前计划里还有 ${metrics.planIssues.length} 个阻塞项,先处理它们。`
107
+ };
108
+ }
109
+ if (metrics.planWarnings.length > 0) {
110
+ return {
111
+ tone: 'warn',
112
+ title: '可以执行,但有提醒',
113
+ summary: `计划已生成,但还有 ${metrics.planWarnings.length} 条提醒值得先看一眼。`
114
+ };
115
+ }
116
+ if (metrics.dryRun) {
117
+ return {
118
+ tone: 'success',
119
+ title: '适合先预演',
120
+ summary: '现在可以安全地跑一次仅预演,先看结果再决定是否真实执行。'
121
+ };
122
+ }
123
+ return {
124
+ tone: 'success',
125
+ title: '可以执行',
126
+ summary: metrics.followUpCount > 0
127
+ ? `主目标和收尾动作都已具备,可以直接执行或入队。`
128
+ : '主目标已经够清楚了,可以直接执行或入队。'
129
+ };
130
+ }
131
+
132
+ export function createMainTabsComputed() {
133
+ return {
134
+ mainTabKicker() {
135
+ if (this.mainTab === 'config') return 'Configuration';
136
+ if (this.mainTab === 'sessions') return 'Sessions';
137
+ if (this.mainTab === 'usage') return 'Usage';
138
+ if (this.mainTab === 'orchestration') return 'Tasks';
139
+ if (this.mainTab === 'market') return 'Skills';
140
+ if (this.mainTab === 'docs') return 'Docs';
141
+ return 'Settings';
142
+ },
143
+ mainTabTitle() {
144
+ if (this.mainTab === 'config') return '本地配置控制台';
145
+ if (this.mainTab === 'sessions') return '会话与导出';
146
+ if (this.mainTab === 'usage') return '本地用量与趋势';
147
+ if (this.mainTab === 'orchestration') return '任务编排';
148
+ if (this.mainTab === 'market') return 'Skills 安装与同步';
149
+ if (this.mainTab === 'docs') return 'CLI 安装与文档';
150
+ return '系统与数据设置';
151
+ },
152
+ mainTabSubtitle() {
153
+ if (this.mainTab === 'config') return '管理本地配置与模型。';
154
+ if (this.mainTab === 'sessions') return '浏览与导出会话。';
155
+ if (this.mainTab === 'usage') return '查看近 7 / 30 天用量。';
156
+ if (this.mainTab === 'orchestration') return '规划、排队、执行与回看本地任务。';
157
+ if (this.mainTab === 'market') return '管理本地 Skills。';
158
+ if (this.mainTab === 'docs') return '查看 CLI 安装命令与排障。';
159
+ return '管理下载、目录与回收站。';
160
+ },
161
+ taskOrchestrationSelectedRun() {
162
+ return this.taskOrchestration && this.taskOrchestration.selectedRunDetail
163
+ ? this.taskOrchestration.selectedRunDetail
164
+ : null;
165
+ },
166
+ taskOrchestrationSelectedRunNodes() {
167
+ const detail = this.taskOrchestrationSelectedRun;
168
+ const run = detail && detail.run && typeof detail.run === 'object' ? detail.run : {};
169
+ if (detail && Array.isArray(detail.nodes)) return detail.nodes;
170
+ return Array.isArray(run.nodes) ? run.nodes : [];
171
+ },
172
+ taskOrchestrationQueueStats() {
173
+ const queue = this.taskOrchestration && Array.isArray(this.taskOrchestration.queue)
174
+ ? this.taskOrchestration.queue
175
+ : [];
176
+ const stats = { queued: 0, running: 0, failed: 0 };
177
+ for (const item of queue) {
178
+ const status = String(item && item.status || '').trim().toLowerCase();
179
+ if (status === 'queued') stats.queued += 1;
180
+ else if (status === 'running') stats.running += 1;
181
+ else if (status === 'failed') stats.failed += 1;
182
+ }
183
+ return stats;
184
+ },
185
+ taskOrchestrationDraftMetrics() {
186
+ return readTaskOrchestrationDraftMetrics(this.taskOrchestration);
187
+ },
188
+ taskOrchestrationDraftChecklist() {
189
+ return createTaskDraftChecklist(this.taskOrchestrationDraftMetrics);
190
+ },
191
+ taskOrchestrationDraftReadiness() {
192
+ return createTaskDraftReadiness(this.taskOrchestrationDraftMetrics);
193
+ }
194
+ };
195
+ }