@aiwuk/team 0.0.0-stage → 5.0.3

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 (116) hide show
  1. package/CHANGELOG.md +156 -0
  2. package/LICENSE +21 -0
  3. package/README.md +149 -2
  4. package/README.zh-CN.md +150 -0
  5. package/access.js +93 -0
  6. package/activity-summary.js +36 -0
  7. package/allocation.js +34 -0
  8. package/board-dispatch.js +141 -0
  9. package/brand.js +41 -0
  10. package/client/00-core-zh.js +284 -0
  11. package/client/01-i18n-en.js +265 -0
  12. package/client/02-styles.js +336 -0
  13. package/client/02b-stage-styles.js +65 -0
  14. package/client/03-shared.js +82 -0
  15. package/client/03b-collapsible-list.js +34 -0
  16. package/client/03c-config-panel.js +605 -0
  17. package/client/04-tool-cards.js +110 -0
  18. package/client/04a-dispatch-confirm.js +162 -0
  19. package/client/04b-more-cards.js +78 -0
  20. package/client/04c-model-picker.js +68 -0
  21. package/client/04d-confirm-dock.js +40 -0
  22. package/client/05-policy.js +217 -0
  23. package/client/06-usage.js +195 -0
  24. package/client/06b-model-source.js +67 -0
  25. package/client/07-board-parts.js +312 -0
  26. package/client/07a-role-theme.js +25 -0
  27. package/client/08-artifacts-report.js +375 -0
  28. package/client/08a-task-control.js +126 -0
  29. package/client/08b-stage-sprites.js +97 -0
  30. package/client/08c-stage-colors.js +55 -0
  31. package/client/08c-stage-scene.js +238 -0
  32. package/client/08d-stage-adapter.js +65 -0
  33. package/client/08e-stage-activity.js +83 -0
  34. package/client/09-team-board.js +181 -0
  35. package/client/09b-role-view.js +95 -0
  36. package/client/09c-model-tabs.js +20 -0
  37. package/client/10-overview.js +364 -0
  38. package/client/10b-onboarding.js +121 -0
  39. package/client/11-register.js +249 -0
  40. package/client.js +5053 -0
  41. package/config-projection.js +40 -0
  42. package/config.js +411 -0
  43. package/cordis.patch.yml +110 -0
  44. package/defaults.js +222 -0
  45. package/dispatch-confirm.js +293 -0
  46. package/dispatch-routes-store.js +31 -0
  47. package/failover.js +85 -0
  48. package/file-limits.js +119 -0
  49. package/free-worker.mjs +125 -0
  50. package/http-guard.js +14 -0
  51. package/i18n/roles.en.json +23 -0
  52. package/i18n/roles.zh.json +23 -0
  53. package/i18n/server.en.json +659 -0
  54. package/i18n/server.zh.json +659 -0
  55. package/i18n.js +34 -0
  56. package/icon.svg +7 -0
  57. package/index.js +111 -0
  58. package/integrations-config.js +301 -0
  59. package/integrations-messages.js +62 -0
  60. package/integrations.js +17 -0
  61. package/lead-route.js +30 -0
  62. package/locale/en.json +6 -0
  63. package/locale/zh.json +6 -0
  64. package/long-context.js +30 -0
  65. package/managed-config-route.js +49 -0
  66. package/managed-ref.js +38 -0
  67. package/managed-resolve.js +47 -0
  68. package/member-task-control.js +242 -0
  69. package/memory-backends.js +89 -0
  70. package/memory-embed.js +70 -0
  71. package/memory-hub.js +150 -0
  72. package/memory-openviking.js +101 -0
  73. package/memory-redact.js +34 -0
  74. package/memory-store.js +219 -0
  75. package/memory-sync-queue.js +28 -0
  76. package/model-policy.js +85 -0
  77. package/model-prefs.js +104 -0
  78. package/observability-api.js +76 -0
  79. package/observability-projection.js +141 -0
  80. package/onboarding.js +47 -0
  81. package/opencode.js +74 -0
  82. package/package.json +153 -4
  83. package/plan-gate.js +92 -0
  84. package/preset-guard.js +47 -0
  85. package/request-evidence.js +41 -0
  86. package/roles.js +69 -0
  87. package/roster-defaults.js +70 -0
  88. package/route-health.js +39 -0
  89. package/runtime-observability.js +78 -0
  90. package/runtime-view.js +21 -0
  91. package/scripts/memory-cli.mjs +138 -0
  92. package/search-engines.js +119 -0
  93. package/search.js +164 -0
  94. package/session-policy.js +59 -0
  95. package/session-rotation.js +206 -0
  96. package/settings-schema.js +40 -0
  97. package/shared/managed-config.js +84 -0
  98. package/single-model.js +44 -0
  99. package/skills/project-role-theme/SKILL.md +46 -0
  100. package/task-bridge.js +32 -0
  101. package/task-control-api.js +36 -0
  102. package/task-control-audit.js +60 -0
  103. package/team.js +101 -0
  104. package/teammate-context.js +120 -0
  105. package/teammate-wait.js +18 -0
  106. package/template.js +46 -0
  107. package/theme-plugin.js +172 -0
  108. package/theme.js +115 -0
  109. package/token-discipline.js +116 -0
  110. package/token-metrics.js +37 -0
  111. package/tool-names.js +10 -0
  112. package/tool-schema.js +23 -0
  113. package/transcribe.js +104 -0
  114. package/ui.js +113 -0
  115. package/usage.js +92 -0
  116. package/workflow.js +246 -0
package/allocation.js ADDED
@@ -0,0 +1,34 @@
1
+ import { m as modelText } from './i18n.js';
2
+ // Model catalog lookups happen only when a configuration is saved, never per request.
3
+ export async function modelCatalog(llm, tiers = {}) {
4
+ const entries = []; const errors = [];
5
+ for (const provider of llm.listProviders()) {
6
+ try {
7
+ for (const model of await llm.listModels(provider.id)) {
8
+ entries.push({ provider: provider.id, providerName: provider.name, model: model.id, name: model.name,
9
+ tiers: Object.entries(tiers).filter(([, ids]) => ids.includes(model.id)).map(([tier]) => tier) });
10
+ }
11
+ } catch { errors.push({ provider: provider.id, error: modelText('allocation.027') }); }
12
+ }
13
+ return { entries, errors };
14
+ }
15
+ /** Every capability whose provider/model changed must exist in the live catalog. */
16
+ export function changedRoutes(before, after) {
17
+ const routes = c => [c, ...c.fallbacks, ...(c.longContext ? [c.longContext] : [])];
18
+ const known = new Set(Object.values(before.capabilities).flatMap(routes).map(r => `${r.provider}/${r.model}`));
19
+ return Object.entries(after.capabilities).flatMap(([id, c]) => routes(c)
20
+ .filter(r => r.provider !== undefined && !known.has(`${r.provider}/${r.model}`))
21
+ .map(r => ({ capability: id, provider: r.provider, model: r.model, tier: c.tier })));
22
+ }
23
+ export function verifyRoutes(routes, catalog) {
24
+ for (const r of routes) {
25
+ if (!catalog.entries.some(e => e.provider === r.provider && e.model === r.model)) {
26
+ throw new Error(modelText('allocation.028', { 0: r.capability, 1: r.provider, 2: r.model }));
27
+ }
28
+ }
29
+ }
30
+ /** Replace the inherited route; provider-specific controls do not transfer between models. */
31
+ export function allocatedRequest(previous, role) {
32
+ const { reasoningEffort, temperature, maxTokens, stop, ...rest } = previous;
33
+ return { ...rest, provider: role.provider, model: role.model };
34
+ }
@@ -0,0 +1,141 @@
1
+ import { m as modelText } from './i18n.js';
2
+ // Dispatch on DSH's shared task board, the way the official team works: every assignment becomes board tasks
3
+ // (subject, description, write scopes, dependencies), ready tasks are reassigned to their member as soon as it
4
+ // exists, members follow list → get → claim → work → complete, and a rotation successor inherits the open
5
+ // tasks of the member it replaces. Write scopes are advisory in DSH; here they can be enforced for edits.
6
+ import { isAbsolute, relative, resolve } from 'node:path';
7
+ import { baseName } from './session-rotation.js';
8
+ import { restrictiveToolName } from './tool-names.js';
9
+ const MAX_TASKS = 12;
10
+ const text = (v, max, label) => {
11
+ if (typeof v !== 'string' || !v.trim() || v.length > max) throw new Error(modelText('board-dispatch.029', { 0: label, 1: max }));
12
+ return v.trim();
13
+ };
14
+ /** Workspace-relative scope like DSH's: no leading slash, no "." or ".." segments. */
15
+ export function normalizeScope(value) {
16
+ const s = String(value ?? '').replaceAll('\\', '/').replace(/^\.\//, '').replace(/\/+$/, '');
17
+ if (!s || s.startsWith('/') || /^[a-z]:/i.test(s) || s.split('/').some(seg => !seg || seg === '.' || seg === '..')) throw new Error(modelText('board-dispatch.030', { 0: JSON.stringify(value) }));
18
+ return s;
19
+ }
20
+ /** A path is inside a scope when it is the scope or below it (same rule as DSH's overlap check). */
21
+ export const inScope = (rel, scope) => rel === scope || rel.startsWith(scope + '/');
22
+ /** Models sometimes send nested arrays as JSON text; accept that form. */
23
+ export const arrayArg = value => {
24
+ if (typeof value !== 'string') return value;
25
+ try { return JSON.parse(value); } catch { return value; }
26
+ };
27
+ /**
28
+ * Normalize the optional `tasks` of each assignment. Each task may name a `key`; `blocked_by` lists keys of tasks
29
+ * that appear earlier in the plan, so the board graph is built in order and can never form a cycle.
30
+ * Assignments without tasks get one task from their `task` text.
31
+ */
32
+ export function planTasks(assignments, rawTasksByRole) {
33
+ const keys = new Set(); const out = [];
34
+ for (const a of assignments) {
35
+ const raw = arrayArg(rawTasksByRole[a.role]);
36
+ const list = raw === undefined ? [{ subject: a.task.split('\n')[0].slice(0, 120), description: a.task }] : raw;
37
+ if (!Array.isArray(list) || !list.length || list.length > MAX_TASKS) throw new Error(modelText('board-dispatch.031', { 0: a.role, 1: MAX_TASKS }));
38
+ for (const [i, t] of list.entries()) {
39
+ const label = modelText('board-dispatch.032', { 0: a.role, 1: i + 1 });
40
+ const key = t.key === undefined ? `${a.role}#${i + 1}` : text(String(t.key), 64, modelText('board-dispatch.033', { 0: label }));
41
+ if (keys.has(key)) throw new Error(modelText('board-dispatch.034', { 0: key }));
42
+ const blockedBy = (arrayArg(t.blocked_by ?? t.blockedBy) ?? []).map(String);
43
+ if (!Array.isArray(blockedBy)) throw new Error(modelText('board-dispatch.035', { 0: label }));
44
+ for (const b of blockedBy) if (!keys.has(b)) throw new Error(modelText('board-dispatch.036', { 0: label, 1: b }));
45
+ const scopes = arrayArg(t.write_scopes ?? t.writeScopes) ?? [];
46
+ if (!Array.isArray(scopes) || scopes.length > 20) throw new Error(modelText('board-dispatch.037', { 0: label }));
47
+ keys.add(key);
48
+ out.push({ key, role: a.role, displayName: a.displayName, subject: text(t.subject, 200, modelText('board-dispatch.038', { 0: label })),
49
+ description: text(t.description ?? a.task, 16000, modelText('board-dispatch.039', { 0: label })), writeScopes: [...new Set(scopes.map(normalizeScope))], blockedBy });
50
+ }
51
+ }
52
+ return out;
53
+ }
54
+ export function createBoardDispatch(ctx, team) {
55
+ const leads = new Map(); // lead id → Map(task id → { role, key })
56
+ const teams = () => ctx.agentTeams;
57
+ const boardOf = lead => { if (!leads.has(lead.id)) leads.set(lead.id, new Map()); return leads.get(lead.id); };
58
+ const listTasks = lead => { try { return teams().listTasks?.(lead) ?? []; } catch { return []; } };
59
+ /** Reassign ready, unowned tasks planned for `role` to member `name` (Lead authority). Returns how many failed. */
60
+ async function handOutOnce(lead, role, name) {
61
+ const planned = boardOf(lead); let failed = 0;
62
+ for (const task of listTasks(lead)) {
63
+ const entry = planned.get(task.id);
64
+ if (!entry || entry.role !== role || task.status !== 'pending' || task.ownerName || !task.ready) continue;
65
+ try { await teams().updateTask(lead, { taskId: task.id, expectedRevision: task.revision, action: 'reassign', owner: name }); } catch { failed++; }
66
+ }
67
+ return failed;
68
+ }
69
+ /**
70
+ * Hand out with a few retries: a member that just claimed its first message may still be provisioning, and
71
+ * DSH only reassigns to active members. If it never succeeds, the member can still claim the task itself.
72
+ */
73
+ async function handOut(lead, role, name, { attempts = 4, delayMs = 1500, sleep = ms => new Promise(r => setTimeout(r, ms)) } = {}) {
74
+ for (let i = 0; i < attempts; i++) {
75
+ if (!(await handOutOnce(lead, role, name))) return true;
76
+ if (i < attempts - 1) await sleep(delayMs);
77
+ }
78
+ return false;
79
+ }
80
+ const api = {
81
+ /** Create the plan's tasks on the board and hand ready ones to members that already exist. */
82
+ async create(lead, plan, rawTasksByRole = {}) {
83
+ if (typeof teams()?.createTask !== 'function') return null;
84
+ const tasks = planTasks(plan.assignments, rawTasksByRole);
85
+ const ids = new Map(); const byRole = {};
86
+ for (const t of tasks) {
87
+ const view = await teams().createTask(lead, { subject: t.subject, description: modelText('board-dispatch.040', { 0: t.description, 1: t.displayName ?? t.role, 2: t.role }),
88
+ blockedBy: t.blockedBy.map(k => ids.get(k)), writeScopes: t.writeScopes });
89
+ ids.set(t.key, view.id);
90
+ boardOf(lead).set(view.id, { role: t.role, key: t.key });
91
+ (byRole[t.role] ??= []).push({ id: view.id, subject: t.subject, writeScopes: t.writeScopes, blockedBy: t.blockedBy.map(k => ids.get(k)) });
92
+ }
93
+ const members = (() => { try { return teams().listMembers(lead); } catch { return []; } })();
94
+ for (const role of Object.keys(byRole)) {
95
+ const live = members.filter(m => m.role !== 'lead' && baseName(m.name) === role).sort((a, b) => b.name.length - a.name.length || b.name.localeCompare(a.name))[0];
96
+ // Existing members are already active, so one attempt is enough and dispatch is not delayed.
97
+ if (live) await handOut(lead, role, live.name, { attempts: 1 });
98
+ }
99
+ return byRole;
100
+ },
101
+ handOut,
102
+ /** Open tasks currently owned by a member, newest board state. */
103
+ owned(lead, name) { return listTasks(lead).filter(t => t.ownerName === name && t.status === 'in_progress'); },
104
+ /** Tasks planned for a role that are still open (pending or in progress). */
105
+ plannedFor(lead, role) { const planned = boardOf(lead); return listTasks(lead).filter(t => planned.get(t.id)?.role === role && t.status !== 'completed'); },
106
+ /** Move every open task of `from` to `to` (rotation). */
107
+ async transfer(lead, from, to) {
108
+ for (const task of listTasks(lead)) {
109
+ if (task.ownerName !== from || (task.status !== 'in_progress' && task.status !== 'pending')) continue;
110
+ try { await teams().updateTask(lead, { taskId: task.id, expectedRevision: task.revision, action: 'reassign', owner: to }); } catch { /* the lead can still reassign by hand */ }
111
+ }
112
+ },
113
+ /** Deny an edit outside the write scopes of the tasks a teammate holds (when any of them declares scopes). */
114
+ guard(exec, limits = { enforce: true }) {
115
+ exec = { ...exec, name: restrictiveToolName(exec.name, new Set(['write', 'edit', 'str_replace_editor'])) };
116
+ if (!limits.enforce || !['write', 'edit', 'str_replace_editor'].includes(exec.name) || (exec.name === 'str_replace_editor' && exec.arguments?.command === 'view')) return undefined;
117
+ const m = teams()?.tryMembership?.(exec.agent);
118
+ if (m?.role !== 'teammate' || !m.root) return undefined;
119
+ const held = api.owned(m.root, m.name);
120
+ const scopes = held.flatMap(t => t.writeScopes ?? []);
121
+ if (!held.length || !scopes.length) return undefined;
122
+ const project = team.pinned(exec.agent);
123
+ const raw = exec.arguments?.[exec.name === 'str_replace_editor' ? 'path' : 'file_path'];
124
+ if (!project || typeof raw !== 'string') return undefined;
125
+ const rel = relative(project, resolve(ctx.workingDirectory?.get?.(exec.agent.session) ?? project, raw)).split('\\').join('/');
126
+ if (!rel || rel.startsWith('../') || isAbsolute(rel)) return undefined;
127
+ if (scopes.some(s => inScope(rel, s))) return undefined;
128
+ return modelText('board-dispatch.041', { 0: rel, 1: held.map(t => t.id).join('、'), 2: [...new Set(scopes)].join('、') });
129
+ },
130
+ /** Runtime context for a teammate: its board tasks and the DSH board workflow. Empty when it has none. */
131
+ context(agent) {
132
+ const m = teams()?.tryMembership?.(agent);
133
+ if (m?.role !== 'teammate' || !m.root) return '';
134
+ const mine = listTasks(m.root).filter(t => t.status !== 'completed' && (t.ownerName === m.name || (!t.ownerName && boardOf(m.root).get(t.id)?.role === baseName(m.name))));
135
+ if (!mine.length) return '';
136
+ const line = t => `${t.id}「${t.subject}」${t.ownerName === m.name ? modelText('board-dispatch.042') : t.ready ? modelText('board-dispatch.043') : modelText('board-dispatch.044', { 0: t.blockedBy.join('、') })}${t.writeScopes?.length ? modelText('board-dispatch.045', { 0: t.writeScopes.join('、') }) : ''}`;
137
+ return modelText('board-dispatch.046', { 0: mine.map(line).join(';') });
138
+ },
139
+ };
140
+ return api;
141
+ }
package/brand.js ADDED
@@ -0,0 +1,41 @@
1
+ // Single source of truth for the AIWUK brand and the extension package names.
2
+ // Pure data, no imports: build-shared.mjs copies this file into packages/*/shared/.
3
+ export const BRAND = Object.freeze({ id: 'aiwuk', en: 'AIWUK', zh: 'AI悟空', domain: 'aiwuk.com', scope: '@aiwuk' });
4
+ // Same value as MOTHERSHIP in the mothership protocol package (packages/protocol/src/brand.ts).
5
+ export const MOTHERSHIP = Object.freeze({ en: 'AIWUK Mothership', zh: 'AI悟空 母舰' });
6
+
7
+ const ext = (pkg, en, zh, description) => Object.freeze({ pkg, en, zh, description: Object.freeze(description) });
8
+
9
+ export const EXTENSIONS = Object.freeze({
10
+ team: ext('@aiwuk/team', 'AIWUK Team', 'AI悟空 协作团队', {
11
+ en: 'Capability-routed multi-agent team for DeepSeek Harness: per-role model routing, same-tier failover and conversational team configuration.',
12
+ zh: '为 DeepSeek Harness 提供按能力路由的多智能体团队:按角色分配模型、同档容灾、对话式配置团队。',
13
+ }),
14
+ autocomplete: ext('@aiwuk/autocomplete', 'AIWUK Autocomplete', 'AI悟空 输入补全', {
15
+ en: 'Composer autocomplete: inline continuation while you pause and next-message suggestions, accepted with Tab, never sent automatically.',
16
+ zh: '输入框自动补全:打字停顿时行内续写、回复后建议下一句,按 Tab 采纳,绝不自动发送。',
17
+ }),
18
+ memory: ext('@aiwuk/memory', 'AIWUK Memory', 'AI悟空 全局记忆', {
19
+ en: 'Profile-wide explicit memory tools and bounded automatic recall for all sessions.',
20
+ zh: '面向所有会话的显式记忆工具与有界自动召回。',
21
+ }),
22
+ search: ext('@aiwuk/search', 'AIWUK Search', 'AI悟空 全能搜索', {
23
+ en: 'Multi-engine web search, page fetch and user-approved audio transcription for all sessions.',
24
+ zh: '面向所有会话的多引擎网页搜索、网页正文读取与授权音频转写。',
25
+ }),
26
+ connector: ext('@aiwuk/connector', 'AIWUK Connector', 'AI悟空 母舰接入器', {
27
+ en: 'Connects this DSH instance to an AIWUK Mothership hub for fleet management and managed configuration.',
28
+ zh: '将本 DSH 实例接入 AI悟空 母舰,用于集群管理与托管配置。',
29
+ }),
30
+ });
31
+
32
+ // Old package name -> new package name. Rollback reinstalls the old package from its original source.
33
+ export const RENAME_MAP = Object.freeze({
34
+ 'dsh-capability-team': '@aiwuk/team',
35
+ 'dsh-capability-autocomplete': '@aiwuk/autocomplete',
36
+ 'dsh-capability-memory': '@aiwuk/memory',
37
+ 'dsh-omni-search': '@aiwuk/search',
38
+ '@dsh-mothership/connector': '@aiwuk/connector',
39
+ '@dsh-mothership/connector-bundle': '@aiwuk/connector-bundle',
40
+ '@dsh-mothership/connector-updater': '@aiwuk/connector-updater',
41
+ });
@@ -0,0 +1,284 @@
1
+ const React = require('react');
2
+ const h = React.createElement;
3
+ const NS = 'capability-team';
4
+
5
+ const zh = {
6
+ 'onb.title': 'AI悟空 协作团队:三步开始', 'onb.step1': '1. 启用官方 Agent Teams', 'onb.step2': '2. 模型档位匹配', 'onb.step3': '3. 开始第一个团队任务',
7
+ 'onb.teamReady': '官方 Agent Teams 服务已运行。',
8
+ 'onb.teamMissing': 'AI悟空 协作团队建立在官方实验包 {name} 之上;它当前未启用,团队功能不会启动。',
9
+ 'onb.teamWarning': '注意:启用后对本配置档(profile)中的所有会话生效,并停用原生的通用子代理工具(subagent / fork 等),改由团队工具委派。只有你点击下方按钮才会启用。',
10
+ 'onb.enable': '启用 Agent Teams', 'onb.enabling': '正在启用…', 'onb.applied': '已启用并生效。请刷新页面后新建会话。',
11
+ 'onb.restart': '已启用,需要重启 DSH 后生效(原因:{reason})。', 'onb.failed': '启用失败,错误码:{code}。也可在“插件”页手动启用。',
12
+ 'onb.noManager': '当前连接不能管理插件;请在侧栏“插件”页手动启用 {name}。',
13
+ 'onb.coverage': '{covered}/{total} 项能力已在你的模型目录中匹配到合格档位(共 {models} 个模型)。', 'onb.coverageUnknown': '模型目录暂不可读;稍后在团队总览中查看。',
14
+ 'onb.unassigned': '未匹配:{list}。这些角色的请求会被阻止;可补充渠道,或让主控开启单模型模式(需你确认)。',
15
+ 'onb.newSession': '新建会话 → 在模式选择中选择“AIWUK Team(AI悟空 协作团队)”,然后直接描述任务。', 'onb.dismiss': '知道了', 'onb.later': '稍后',
16
+ 'roles.singleModel': '单模型模式', 'roles.singleModelHint': '未分配模型的角色统一使用你确认的单个模型;无备选,失败直接报告。',
17
+ 'role.name.lead': '主控', 'role.name.architect': '技术总监', 'role.name.backend': '后端', 'role.name.frontend': '前端',
18
+ 'role.name.researcher': '研究员', 'role.name.writer': '文档', 'role.name.qa': '测试',
19
+ 'live.quote.lead': '目标已明确,分工就绪。', 'live.quote.architect': '先定方案与接口,再动手。', 'live.quote.backend': '接口与数据,随时待命。',
20
+ 'live.quote.frontend': '页面与交互,交给我。', 'live.quote.researcher': '先查证,再下结论。', 'live.quote.writer': '文档随时可以落笔。', 'live.quote.qa': '没有证据,不算完成。',
21
+ 'nav.models': '模型', 'nav.roles': '角色', 'nav.usage': '用量', 'nav.logs': '日志',
22
+ 'navfull.models': '模型管理', 'navfull.roles': '角色与配置', 'navfull.usage': '用量', 'navfull.logs': '请求日志', 'navfull.artifacts': '成果货架', 'navfull.report': '战报',
23
+ 'usage.hint': '预算计数 token(不含缓存读取)= 未缓存输入 + 缓存写入 + 输出,缓存读取单列且仍可能收费,不等于账单金额。总量与每步耗时由宿主实时推送;按模型拆分的 token 来自上次刷新。', 'usage.total': '团队合计 {n}', 'usage.billable': '预算计数 {n}', 'usage.cacheRead': '缓存读取 {n}', 'usage.budget': '预算 {used} / {max}', 'usage.over': '已达预算,请求被阻止', 'usage.none': '暂无用量记录', 'usage.io': '输入 {i} · 输出 {o}', 'usage.step': '{n} 步 · 平均 {s}s/步', 'usage.ttft': '首 token {s}s', 'usage.decode': '{n} token/s', 'usage.stepHint': 'DSH 会话统计:每步模型墙钟时间、首 token 延迟与解码速度', 'overview.live': '实时',
24
+ 'models.preview': '已保存策略下的请求候选(非实际调用)', 'models.blocked': '已阻止:无允许模型', 'models.unassigned': '尚未分配', 'models.refreshPreview': '策略已保存,请刷新状态获取新的候选预览。',
25
+ 'evidence.title': '本会话模型日志', 'evidence.hint': '只展示本会话非继承日志。请求配置不等于调用成功,响应记录也不等于任务完成。',
26
+ 'evidence.request-header': '已记录请求配置', 'evidence.assistant-message': '已记录助手响应', 'evidence.empty': '暂无可核实记录',
27
+ 'models.help': '关闭开关即禁用该模型,也可以按前缀批量排除。设置是全局的:保存后对所有AI悟空 协作团队会话(含新建会话)从下一次请求起生效,已发出的请求不受影响;目录存在不代表调用成功。',
28
+ 'models.enabled': '启用', 'models.disabledBadge': '已禁用', 'models.tierCount': '{n} 个 · 已禁用 {d}', 'models.dirty': '{n} 项更改未保存', 'models.reset': '撤销更改',
29
+ 'models.filter': '筛选模型或角色…', 'models.noMatch': '没有匹配的模型', 'models.orphans': '目录外的已禁用模型', 'models.unused': '暂未被角色使用',
30
+ 'evidence.short.request-header': '请求', 'evidence.short.assistant-message': '响应', 'logs.thisSession': '本会话', 'logs.count': '{n} 条', 'logs.interrupted': '已中断',
31
+ 'roles.fallbackList': '备选:{list}',
32
+ 'roles.editOnly': '只能修改 {list}', 'roles.noEdit': '不能修改文件', 'roles.noShell': '不能执行命令', 'roles.preset': 'DSH 沙箱 {name}', 'roles.current': '当前 {route}', 'roles.liveModel': '最近一次请求实际使用的模型(实时)', 'logs.live': '实时:各成员最近一次请求的模型', 'logs.steps': '{n} 步', 'roles.deny': '禁用 {list}', 'roles.accessHint': '权限由工具守卫强制执行', 'roles.whenToUse': '适用:{text}', 'roles.maxTokens': '每会话预算 {n}', 'roles.longContext': '≥{n} 改用 {route}', 'roles.planFirst': '执行前需主控批准计划',
33
+ 'workflow.mode': '执行模式', 'workflow.mode.enforce': '强制', 'workflow.mode.remind': '仅提醒', 'workflow.mode.off': '关闭', 'workflow.analysisBudget': '指派前只读分析', 'workflow.directBudget': '主控自行处理上限',
34
+ 'workflow.freeTools': '免费模型工具', 'workflow.freeModels': '免费模型顺序', 'workflow.analysisTools': '分析类工具', 'workflow.coordinationTools': '协调类工具', 'workflow.allFree': '目录中全部免费模型', 'workflow.times': '{n} 次',
35
+ 'workflow.fileLimits': '文件铁律', 'workflow.fileLimits.value': '源文件 ≤{source} 行 · 测试 ≤{test} 行 · 整读 ≤{read} 行 · 汇报 ≤{report} 字', 'workflow.fileLimits.off': '关闭',
36
+ 'workflow.tokens': 'Token 规则', 'workflow.tokens.value': '空闲时上下文 ≥{ratio}% 自动压缩 · 命令/搜索输出超过 {chars} 字只留头尾',
37
+ 'confirm.habit': '按你的习惯 {n}/{of}', 'confirm.failing': '最近失败 {n} 次', 'confirm.primaryFailing': '主模型 {route} 最近失败 {n} 次,建议换一个。', 'confirm.habitSettled': '最近 3 次你都这样选,可以改为“保存为项目默认”。', 'plan.boardScope': '写入范围 {list}', 'plan.boardAfter': '等待 {list}', 'workflow.enforceWriteScopes': '写入范围', 'workflow.enforceWriteScopes.on': '强制(范围外修改会被拒绝)', 'workflow.enforceWriteScopes.off': '仅提示', 'cards.prefs': '模型偏好', 'cards.prefs.summary': '已学到 {n} 个能力的偏好', 'cards.prefs.cleared': '已清空学到的偏好',
38
+ 'picker.sameTier': '同档推荐', 'confirm.crossTier': '跨档', 'confirm.crossTierFallback': '跨档:故障时会切换到这个模型', 'confirm.crossTierTaskOnly': '跨档选择仅本次生效',
39
+ 'confirm.expand': '展开', 'confirm.collapse': '收起', 'picker.search': '输入搜索模型…', 'picker.count': '{n} / {total} 个模型', 'picker.empty': '没有匹配的模型', 'picker.noProvider': '其他',
40
+ 'cards.memorySearch': '记忆检索', 'cards.memorySearch.summary': '“{q}” · {n} 条 · {mode}', 'cards.memory.mode.hybrid': '全文+向量', 'cards.memory.mode.text': '仅全文', 'cards.memoryWrite': '写入记忆', 'cards.memoryWrite.saved': '已保存', 'cards.memoryWrite.merged': '已合并到相同记忆', 'cards.memory.kind.handoff': '交接', 'cards.memory.kind.result': '结果', 'cards.memory.kind.pitfall': '踩坑', 'cards.memory.kind.decision': '决定', 'cards.memory.kind.note': '笔记',
41
+ 'usage.avgPrompt': '每步平均输入 {n}', 'usage.cacheShare': '缓存读取占 {p}%', 'usage.heavyContext': '每步上下文偏大,建议轮换会话', 'usage.contextHint': '每步平均输入 =(未缓存输入 + 缓存读取 + 缓存写入)÷ 步数。数值越大,每一步重发的上下文越多。',
42
+ 'cards.handoff': '交接', 'cards.handoff.summary': '{name} 已交接 · {n} 个未完成任务', 'cards.handoff.diff': '代码改动', 'cards.handoff.test': '最后一次测试', 'cards.rotate': '会话轮换', 'cards.rotate.summary': '{from} → {to}',
43
+ 'workflow.confirmDispatch': '分派确认', 'workflow.confirmDispatch.always': '每次都确认', 'workflow.confirmDispatch.on-change': '首次及模型变化时确认', 'workflow.confirmDispatch.never': '不确认', 'workflow.rotation': '会话轮换', 'workflow.rotation.value': '压缩 {soft} 次提醒、{hard} 次轮换 · 上下文 ≥{ratio}% · ≥{turns} 轮',
44
+ 'cards.catalog': '模型目录', 'cards.catalog.summary': '{n} 个模型 · {p} 个渠道', 'cards.catalog.errors': '读取失败的渠道', 'cards.budget': '任务步数预算', 'cards.override': '临时模型', 'cards.lease.role': '成员', 'cards.lease.status': '状态', 'cards.lease.judgment': '判定', 'cards.lease.steps': '步数', 'cards.lease.ends': '到期', 'cards.lease.endReason': '结束原因',
45
+ 'cards.export': '导出团队模板', 'cards.export.summary': '{n} 个角色 · {c} 个能力', 'cards.search': '聚合搜索', 'cards.search.summary': '“{q}” · {n} 条结果', 'cards.fetch': '网页读取',
46
+ 'plan.fallbacks': '回退:{list}', 'confirm.title': '确认分派', 'confirm.hint': '核对每个角色的模型和回退模型,确认后才会派活;可以直接修改。', 'confirm.primary': '主模型', 'confirm.fallbacks': '回退模型', 'confirm.noFallbacks': '无回退模型', 'confirm.addFallback': '添加回退模型…', 'confirm.max': '最多 {n} 个回退模型', 'confirm.up': '上移', 'confirm.down': '下移', 'confirm.remove': '移除',
47
+ 'confirm.scope': '修改范围', 'confirm.scope.task': '只用于这次任务', 'confirm.scope.project': '保存为项目默认', 'confirm.scope.projectHint': '会修改能力 {list} 的模型,使用这些能力的所有角色都会受影响。', 'confirm.ok': '确认分派', 'confirm.cancel': '取消', 'confirm.loading': '正在读取待确认的分派…', 'confirm.sent': '已确认,正在派活。', 'confirm.cancelled': '已取消这次分派。', 'confirm.stale': '确认请求已失效(可能插件已重载或已超时),请中断本轮后重新分派。',
48
+ 'confirm.error.conflict': '可用模型已变化,已刷新,请重新确认。', 'confirm.error.invalid': '模型选择无效:', 'confirm.error.other': '提交失败,请重试。', 'confirm.confirmedBy': '已由你确认',
49
+ 'models.primary': '主用', 'models.fallback': '备用', 'models.save': '全局保存', 'models.saving': '正在保存…', 'models.saved': '已全局保存;所有会话的下一次请求按新规则检查。',
50
+ 'tier.high': '旗舰档', 'tier.upper': '高阶档', 'tier.medium': '中阶档', 'tier.low': '轻量档', 'tier.unknown': '未分类',
51
+ 'state.running': '正在执行',
52
+ 'state.failed': '执行失败',
53
+ 'state.stopped': '已中止',
54
+ 'action.inspect': '查看调用',
55
+ 'plan.title': '派活计划',
56
+ 'plan.analysis': '需求分析',
57
+ 'plan.reason': '理由',
58
+ 'plan.assignments': '指派',
59
+ 'plan.next': '下一步',
60
+ 'plan.budget': '本轮自行执行上限 {n} 次',
61
+ 'plan.unlimited': '你已确认由主控亲自完成,本轮不限执行次数',
62
+ 'direct.title': '允许主控亲自完成?', 'direct.hint': '允许后本轮不限执行步数,你发下一条消息时恢复限制;文件规则和权限不变。', 'direct.allow': '允许', 'direct.deny': '不允许', 'direct.loading': '正在读取待确认的请求…', 'direct.sent': '已允许,主控继续执行。', 'direct.cancelled': '已拒绝,执行限制不变。', 'direct.stale': '确认请求已失效(可能插件已重载或已超时),请中断本轮后重试。', 'direct.native': '这次确认已转到弹出的问答框,请在那里选择。', 'confirm.native': '这次分派确认已转到弹出的问答框,请在那里选择。', 'confirm.docked': '等待你确认:确认面板已显示在下方输入框上方。',
63
+ 'mode.delegate': '指派队友',
64
+ 'mode.free': '免费模型',
65
+ 'mode.direct': '主控处理',
66
+ 'free.title': '免费模型任务',
67
+ 'free.prompt': '交付内容',
68
+ 'free.result': '结果',
69
+ 'free.model': '模型',
70
+ 'free.tools': '工具',
71
+ 'free.task': '看板任务',
72
+ 'free.calls': '工具调用 {n} 次',
73
+ 'free.changed': '改动文件',
74
+ 'free.changedCount': '改动 {n} 个文件',
75
+ 'free.skipped': '不可用而跳过的模型',
76
+ 'tools.none': '仅文字',
77
+ 'tools.read': '只读文件',
78
+ 'tools.write': '读写文件',
79
+ 'team.readTitle': '团队配置',
80
+ 'team.saveTitle': '保存团队配置',
81
+ 'team.summary': '{name} · 版本 {rev} · {n} 个角色',
82
+ 'team.saved': '已保存 · 版本 {rev}',
83
+ 'team.roles': '角色',
84
+ 'team.unassigned': '未分配(请求将被阻止)',
85
+ 'overview.title': '团队总览', 'overview.hint': '读取本会话真实状态,不启动模型、不修改配置。', 'overview.empty': '尚未读取团队配置。',
86
+ 'overview.ready': '已就绪', 'overview.notMounted': '未挂载', 'overview.abnormal': '需处理', 'overview.preset': '预设', 'overview.missingTools': '缺少工具', 'overview.details': '挂载诊断',
87
+ 'overview.revision': '版本 {rev}', 'overview.updated': '更新于 {time}', 'overview.statRoles': '角色', 'overview.firstLoad': '读取团队配置', 'overview.logNote': '实时状态由宿主推送,不写入对话;点“刷新”读取配置时,对话里会留下一条命令记录。', 'overview.statWorking': '工作中',
88
+ 'live.title': '团队工作台', 'live.runningCount': '{n} 个正在工作', 'live.polling': '实时推送', 'live.running': '工作中', 'live.idle': '空闲', 'live.inactive': '未启动', 'live.provisioning': '启动中', 'live.failed': '异常',
89
+ 'live.noTask': '暂无任务', 'live.open': '打开该队友的会话', 'live.busyNoTask': '正在处理消息…', 'live.liveModel': '最近一次实际请求的模型(插件用量记录)', 'live.configModel': '配置的主用模型(尚无实际请求记录)',
90
+ 'live.lastRequest': '上次请求', 'live.fallback': '备选', 'live.notInConfig': '非配置路由', 'live.configTag': '配置', 'live.leadPick': '对话中选择的模型(尚无实际请求记录)', 'live.routeWarn': '⚠ 不在配置内', 'live.routeWarnHint': '实际请求的模型不在该角色的主模型与备选中,请检查路由或配置',
91
+ 'models.prefixTitle': '按前缀排除', 'models.prefixPlaceholder': '输入前缀,如 @cf/、provider-a/or/、grok-imagine', 'models.prefixAdd': '排除',
92
+ 'models.prefixPreview': '{rule} 将排除 {n} 个模型:{list}', 'models.prefixInvalid': '前缀至少 2 个字符,不能含空格或中间的 *', 'models.prefixExists': '这条规则已存在',
93
+ 'models.prefixHelp': '前缀同时匹配“渠道/模型”和单独的模型 ID;规则会持续生效,以后新增的同前缀模型也会被排除。保存后生效。',
94
+ 'models.ruleCount': '{n} 个', 'models.ruleRemove': '移除规则 {rule}', 'models.byRule': '规则 {rule}',
95
+ 'models.tiers': '模型档位', 'models.allTiers': '全部', 'models.more': '显示更多(还有 {n} 个)', 'overview.statModels': '模型', 'overview.statDisabled': '已禁用', 'overview.statBlocked': '受阻角色',
96
+ 'overview.refresh': '刷新', 'overview.loading': '正在读取…',
97
+ 'overview.policy': '工作流配置', 'overview.noData': '当前会话未提供团队配置。请检查挂载状态;旧会话不会自动切换预设。',
98
+ 'team.fallbacks': '同档备选 {n} 个',
99
+ 'team.cooling': '冷却中的模型',
100
+ 'team.project': '项目',
101
+ 'usage.asOf': '截至 {time}',
102
+ 'usage.unknown': '未知',
103
+ 'usage.partialLow': '可能偏低',
104
+ 'subagent.notice': '这是队友会话,团队视图请在主控会话查看',
105
+ 'subagent.currentMember': '当前成员: {name} ({role})',
106
+ 'subagent.openLead': '打开主控会话',
107
+ 'roleview.viewOverview': '查看团队总览',
108
+ 'roleview.backToRole': '返回角色视图',
109
+ 'roleview.myTasks': '我的任务',
110
+ 'roleview.noTasks': '暂无分配给我的任务',
111
+ 'roleview.activity': '当前活动',
112
+ 'roleview.noActivity': '当前暂无活动记录',
113
+ 'roleview.modelAndPerms': '模型与权限',
114
+ 'roleview.taskControl': '任务控制',
115
+ 'roleview.usage': '我的用量',
116
+ 'roleview.noUsage': '暂无用量记录',
117
+ 'roleview.artifacts': '我的交付物',
118
+ 'roleview.noArtifacts': '暂无交付物',
119
+ 'roleview.logs': '我的日志',
120
+ 'roleview.noLogs': '暂无日志记录',
121
+ 'subtabs.team': '团队成员',
122
+ 'subtabs.models': '模型分配',
123
+ 'subtabs.runtime': '运行状态',
124
+ 'runtime.noNotices': '暂无运行时提示',
125
+ 'subagent.unresolved': '无法确定主控会话,暂不显示团队视图',
126
+ 'error.tabCrashed': '该标签页渲染异常,已安全隔离',
127
+ 'theme.title': '团队主题',
128
+ 'theme.current': '当前主题: {name}',
129
+ 'theme.scopeDesc': '仅更换显示名/主题的指令不改变模型与权限;通过对话由主控提出方案并在确认框显示完整差异后才保存;导入模板可能同时改变职责、工作流与权限,请检查确认框差异。台词与徽章别名为内置静态,不随主题自动变化。',
130
+ 'theme.howToChange': '如何更换主题',
131
+ 'theme.chatInstruction': '在主控会话中对主控(Lead)发送指令,通过 project-role-theme 技能调整:',
132
+ 'theme.promptWestern': '把团队换成西方魔幻主题',
133
+ 'theme.promptOutlaws': '把团队换成水浒传主题',
134
+ 'theme.promptSciFi': '把团队换成赛博科幻主题',
135
+ 'theme.promptCopy': '复制提示词',
136
+ 'theme.promptCopied': '已复制',
137
+ 'theme.promptManual': '复制失败,请手动全选复制输入框内容',
138
+ 'theme.templateInstruction': '或在主控会话导出/导入团队模板(通过 capability_team_export / capability_team_import):',
139
+ 'theme.templateDesc': '导出模板可备份当前角色与能力,导入模板可批量重设角色名册与职责。',
140
+ 'output': '原始输出',
141
+ 'live.openBtn': '打开会话',
142
+ 'live.contextPressure': '上下文',
143
+ 'live.contextUnknown': '未知',
144
+ 'live.budgetTitle': '预算',
145
+ 'live.taskDeps': '任务依赖',
146
+ 'live.longestChain': '最长依赖链',
147
+ 'live.noDeps': '暂无任务依赖',
148
+ 'live.bubbleRunning': '执行中',
149
+ 'live.bubbleWaiting': '等待中',
150
+ 'live.quote.sun-quan': '江东基业,当同心协力。',
151
+ 'live.quote.zhuge-liang': '运筹帷幄之中,决胜千里之外。',
152
+ 'live.quote.lv-bu': '方天画戟已备,随时待命!',
153
+ 'live.quote.diao-chan': '一点生机,万般颜色。',
154
+ 'live.quote.zhao-yun': '一身是胆,白马银枪在此!',
155
+ 'live.quote.chen-lin': '秉笔直书,檄文已在胸中。',
156
+ 'live.quote.zhou-yu': '谈笑间,樯橹灰飞烟灭。',
157
+ 'live.quote.default': '整装待发,随时听候调遣。',
158
+ 'model.grade.legendary': '传说金',
159
+ 'model.grade.epic': '史诗紫',
160
+ 'model.grade.rare': '稀有蓝',
161
+ 'model.grade.cloth': '布衣',
162
+ 'version.unsupported': '版本不支持 (需要 schemaVersion: 1)',
163
+ 'common.unknown': '未知',
164
+ 'common.listSep': '、',
165
+ 'runtime.title': '运行时与容灾',
166
+ 'runtime.restarted': '运行时已重启',
167
+ 'runtime.snapshotLag': '快照,可能滞后',
168
+ 'runtime.cooling': '冷却中 {s}s',
169
+ 'runtime.switched': '路由切换 {from} → {to}(原因:{reason}{detail})',
170
+ 'runtime.reason.failover': '容灾',
171
+ 'runtime.reason.long-context': '长上下文',
172
+ 'runtime.unavailable': '运行时容灾服务不可见或不可用',
173
+ 'runtime.noSwitches': '暂无路由切换记录',
174
+ 'activity.tool': '工具: {tool}',
175
+ 'activity.processing': '正在处理',
176
+ 'activity.parallel': '并行 {n} 个工具',
177
+ 'activity.unsettled': '历史未收尾',
178
+ 'activity.recent': '最近活动 ({n})',
179
+ 'nav.artifacts': '成果',
180
+ 'artifacts.title': '交付物与成果',
181
+ 'artifacts.empty': '暂无成果交付物',
182
+ 'artifacts.allRoles': '全部角色',
183
+ 'artifacts.openDesktop': '打开',
184
+ 'artifacts.openFail': '打开失败',
185
+ 'artifacts.changes': '本会话变更',
186
+ 'artifacts.noChanges': '暂无代码变更记录',
187
+ 'artifacts.diffOversized': '差异过大 (>1MiB),请前往宿主面板查看',
188
+ 'artifacts.baselineInvalid': '基线已失效',
189
+ 'artifacts.diffEmpty': '无差异内容',
190
+ 'nav.report': '战报',
191
+ 'report.title': '团队战报',
192
+ 'report.window': '观察窗口: {start} 至 {end}(跨度 {span},含空闲)',
193
+ 'report.wallTime': '人次墙钟: {time}',
194
+ 'report.turnsSteps': '总轮次: {turns} · 总步数: {steps}',
195
+ 'report.tokensTotal': '预算计数 Token 合计: {total}',
196
+ 'report.tokensIo': '输入: {in} · 输出: {out} · 缓存写入: {cw}',
197
+ 'report.unknownMembers': '以下成员用量未知,未计入汇总:{list}',
198
+ 'report.cacheRead': '缓存读取(单独列出): {cr}',
199
+ 'report.mutations': '看板变更次数: {n}',
200
+ 'report.sectionOwn': '会话执行指标',
201
+ 'report.hostRetries': '宿主重试开始次数: {n}',
202
+ 'report.failedTurns': '失败轮次: {n}',
203
+ 'report.msgAccepted': '消息工具成功: {n}',
204
+ 'report.sectionRuntime': '运行时容灾指标(自运行时启动起)',
205
+ 'report.requestFailures': '请求失败: {n}',
206
+ 'report.pluginRetries': '插件重试: {n}',
207
+ 'report.failoverSwitches': '容灾切换: {n}',
208
+ 'report.longContextSwitches': '长上下文切换: {n}',
209
+ 'report.def.title': '指标定义与说明',
210
+ 'report.def.wallTime': '人次墙钟:所有成员已完成轮次墙钟时间求和,反映并发人力总开销。',
211
+ 'report.def.tokensTotal': '预算计数 token(不含缓存读取):未缓存输入 + 缓存写入 + 输出。缓存读取单列且仍可能收费,不等于账单金额。',
212
+ 'report.def.cacheRead': '缓存读取:命中上下文缓存的 token 数,单列且仍可能收费,不计入模型预算计数但反映缓存效率。',
213
+ 'report.def.mutations': '看板变更次数:仅统计 Lead 主控会话触发的任务看板修改次数。',
214
+ 'report.def.hostRetries': '宿主重试开始次数:各成员会话遇到请求异常时由宿主发起重试的累计次数。',
215
+ 'report.def.failedTurns': '失败轮次:各成员会话执行异常或中断的轮次总数。',
216
+ 'report.def.msgAccepted': '消息工具成功:团队内部成功调用 send_message 沟通并被接收的次数。',
217
+ 'report.def.requestFailures': '请求失败:运行时检测到的底层模型请求失败次数。',
218
+ 'report.def.pluginRetries': '插件重试:由容灾插件自动触发的模型重试次数。',
219
+ 'report.def.failoverSwitches': '容灾切换:主模型故障后由容灾插件自动切换到同档备选模型的次数。',
220
+ 'report.def.longContextSwitches': '长上下文切换:上下文达到阈值触发切换到长上下文模型及切回的次数。',
221
+ 'control.title': '任务控制',
222
+ 'control.toggle': '任务控制',
223
+ 'control.lease.ended': '租约已结束',
224
+ 'control.lease.status.armed': '待命',
225
+ 'control.lease.status.running': '执行中',
226
+ 'control.lease.status.ended': '已结束',
227
+ 'control.steps.label': '步数 {used} / {est}',
228
+ 'control.steps.disclaimer': '非成果质量评级;每次 step/start 计一步',
229
+ 'control.steps.unqualified': '已超出预估步数',
230
+ 'control.steps.warning': '接近预估步数',
231
+ 'control.override.title': '临时模型',
232
+ 'control.override.badge': '{from} → {to}',
233
+ 'control.override.none': '未设置临时模型',
234
+ 'control.override.tier': '档位 {tier}',
235
+ 'control.override.expiresAt': '到期时间 {time}',
236
+ 'control.override.autoRestore': '空闲/完成/超时后自动恢复为配置模型',
237
+ 'control.override.pauseLongContext': '临时模型期间暂停长上下文切换',
238
+ 'control.override.nextRequest': '下一次请求起生效',
239
+ 'control.override.setAction': '设置临时模型',
240
+ 'control.override.restoreAction': '恢复配置模型',
241
+ 'control.override.pick': '选择候选模型',
242
+ 'control.override.pickHint': '候选仅来自后端目录,不可手填',
243
+ 'control.override.noCandidates': '暂无候选模型',
244
+ 'control.override.reason': '原因(可选)',
245
+ 'control.override.confirm.title': '确认设置临时模型',
246
+ 'control.override.confirm.member': '成员:{name}',
247
+ 'control.override.confirm.change': '{from} → {to}({tier})',
248
+ 'control.override.confirm.cost': '临时模型可能改变计费费率,且会使当前缓存失效',
249
+ 'control.override.confirm.restore': '空闲/完成/超时后自动恢复为配置模型;下一次请求起生效',
250
+ 'control.override.confirm.ok': '确认设置',
251
+ 'control.override.confirm.cancel': '取消',
252
+ 'control.budget.title': '启动预算',
253
+ 'control.budget.startAction': '开始计数',
254
+ 'control.budget.complexity': '复杂度',
255
+ 'control.budget.complexity.simple': '简单', 'control.budget.complexity.complex': '复杂',
256
+ 'control.budget.complexity.low': '低',
257
+ 'control.budget.complexity.medium': '中',
258
+ 'control.budget.complexity.high': '高',
259
+ 'control.budget.timeoutSeconds': '超时(秒)',
260
+ 'control.action.end': '结束租约',
261
+ 'control.audit.title': '最近操作',
262
+ 'control.audit.empty': '暂无记录',
263
+ 'control.error.badRequest': '请求格式有误',
264
+ 'control.error.forbidden': '没有权限执行该操作',
265
+ 'control.error.notFound': '租约或角色不存在',
266
+ 'control.error.conflict': '版本已变化,请重新确认后再试',
267
+ 'control.error.invalid': '参数未通过校验',
268
+ 'control.error.unavailable': '服务暂不可用,请稍后重试',
269
+ 'control.error.unknown': '操作失败',
270
+ 'control.error.network': '网络请求失败',
271
+ 'control.error.reconfirm': '请重新查看最新状态后再确认一次。',
272
+ 'control.pending': '处理中…',
273
+ 'list.more': '更多(剩余 {n} 条)',
274
+ 'list.collapse': '收起',
275
+ 'stage.title': '像素办公室', 'stage.summary': '{n} / {m} 人在岗', 'stage.collapse': '收起办公室', 'stage.expand': '展开办公室',
276
+ 'stage.open': '打开会话', 'stage.empty': '队伍尚未成型,发出第一个需求后队友会入座',
277
+ 'stage.detail': '成员详情', 'stage.detailClose': '收起详情', 'stage.detailHint': '点击办公室里的角色或其名牌,查看模型、上下文、冷却与任务控制等详情',
278
+ 'stage.parallel': '并行 {n}',
279
+ 'stage.act.thinking': '思考中', 'stage.act.thinkingBubble': '思考中…', 'stage.act.reading': '读文件', 'stage.act.writing': '写代码',
280
+ 'stage.act.terminal': '跑命令', 'stage.act.searching': '搜索中', 'stage.act.browsing': '查网页', 'stage.act.messaging': '传信中',
281
+ 'stage.act.board': '看板操作', 'stage.act.waiting': '等待队友', 'stage.act.working': '用工具', 'stage.act.failed': '出错了',
282
+ 'stage.act.failedBubble': '出错了,需要处理', 'stage.act.arriving': '正在入座…', 'stage.act.idle': '空闲', 'stage.act.offline': '未上岗',
283
+ 'stage.act.doneBubble': '任务完成!',
284
+ };