dsh-cohub 0.1.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js ADDED
@@ -0,0 +1,919 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "dsh-cohub",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ var React = require("react");
8
+
9
+ var NS = "cohub";
10
+ var inject = ["slots", "locale", "remote", "remote.llm", "remote.session", "settingsScope"];
11
+
12
+ var SKILL_ROWS = [
13
+ { name: "co-orchestrator", label: "调度编排" },
14
+ { name: "co-planner", label: "方案制定" },
15
+ { name: "co-oracle", label: "架构/代码审查" },
16
+ { name: "co-explorer", label: "搜索方案制定" },
17
+ { name: "co-librarian", label: "资料研究" },
18
+ { name: "co-observer", label: "视觉分析" },
19
+ { name: "co-fixer", label: "代码修改方案" },
20
+ { name: "co-designer", label: "UI/UX 设计" },
21
+ { name: "co-council", label: "多模型共识" },
22
+ { name: "co-rule-user", label: "用户规则" },
23
+ { name: "co-rule-project", label: "项目规则" },
24
+ { name: "co-rule-app", label: "应用规则" },
25
+
26
+ ];
27
+
28
+ var zh = {
29
+ title: "CoHub 代理模型",
30
+ description: "为每个专职代理单独指定模型供应商与模型。留空则继承父模型;配置失效时自动回退。",
31
+ provider: "供应商",
32
+ model: "模型",
33
+ configured: "显式配置",
34
+ inherited: "继承父模型",
35
+ loading: "加载中…",
36
+ unavailable: "当前设置不可用。",
37
+ save: "保存",
38
+ saving: "保存中…",
39
+ discard: "放弃修改",
40
+ saved: "已保存。",
41
+ failed: "保存失败:",
42
+ loadProvidersFailed: "模型供应商列表加载失败",
43
+ customModel: "输入模型 ID",
44
+ selectProviderFirst: "请先选择供应商",
45
+ scheduleTitle: "调度参数(可选)",
46
+ scheduleDesc: "影响 orchestrator 的并行批大小 / 墙钟预算与委派重试;留空使用默认值。",
47
+ batchSize: "批大小(单批并行委派上限)",
48
+ wallClock: "墙钟预算(毫秒)",
49
+ maxRetries: "委派重试上限(0 = 不重试)",
50
+ useJobTrackingLabel: "Job 跟踪",
51
+ adaptiveBatchLabel: "批间自适应",
52
+ useJobTrackingAuto: "auto(自动)",
53
+ useJobTrackingOn: "on(启用)",
54
+ useJobTrackingOff: "off(关闭)",
55
+ adaptiveBatchAuto: "auto(自适应)",
56
+ adaptiveBatchOff: "off(固定)",
57
+ retryDelayMs: "重试间隔(毫秒)",
58
+ retryableReasons: "可重试原因(逗号分隔)",
59
+ retryableReasonsHint: "如 aborted, error;未知原因不重试",
60
+ stallTitle: "停滞检测(可选)",
61
+ stallDesc: "对委派子代理的运行期观测;启用后会自动中止 S1-S4 信号并复用重试机制。",
62
+ stallEnabled: "启用停滞检测",
63
+ consecutiveErrors: "S1 连续同类错误阈值",
64
+ idleMs: "S2 无结果空转(毫秒)",
65
+ reasoningWithoutAction: "S3 纯推理无动作阈值",
66
+ loopCount: "S4 重复调用循环阈值",
67
+ graceMs: "宽限窗口(毫秒)",
68
+ recoverable: "可重试(触发后按 retryableReasons 判定)",
69
+ envSigTitle: "环境契约持久化(可选)",
70
+ envSigDesc: "把执行器环境契约从每次探针改为一次学习持续使用。",
71
+ envSigUse: "契约模式",
72
+ envSigUseAuto: "auto(默认:观察后写入)",
73
+ envSigUseOff: "off(每次都探针)",
74
+ envSigUseManual: "manual(只读 manual 配置)",
75
+ envSigTtl: "缓存 TTL(毫秒)",
76
+ envSigConfirmCount: "确认次数(达到后写入)",
77
+ invalidCleared: "⚠️ 已检测到 {count} 个代理的配置失效,已自动重置为继承。",
78
+ invalidClearedList: "受影响代理:{list}",
79
+ providerPlaceholder: "选择供应商(留空则继承)",
80
+ modelPlaceholder: "选择模型(留空则用供应商默认)"
81
+ };
82
+ var en = {
83
+ title: "CoHub Agent Models",
84
+ description: "Pick a provider and model for each specialist agent. Leave blank to inherit the parent model; stale config auto-resets.",
85
+ provider: "Provider",
86
+ model: "Model",
87
+ configured: "Explicit",
88
+ inherited: "Inherited",
89
+ loading: "Loading…",
90
+ unavailable: "This setting is unavailable.",
91
+ save: "Save",
92
+ saving: "Saving…",
93
+ discard: "Discard",
94
+ saved: "Saved.",
95
+ failed: "Save failed: ",
96
+ loadProvidersFailed: "Failed to load provider catalog",
97
+ customModel: "Enter model ID",
98
+ selectProviderFirst: "Select a provider first",
99
+ scheduleTitle: "Scheduling (optional)",
100
+ scheduleDesc: "Controls the orchestrator's parallel batch size, wall-clock budget, and delegate retries. Leave blank for defaults.",
101
+ batchSize: "Batch size (max parallel delegates)",
102
+ wallClock: "Wall-clock budget (ms)",
103
+ maxRetries: "Delegate retry limit (0 = no retry)",
104
+ useJobTrackingLabel: "Job tracking",
105
+ adaptiveBatchLabel: "Adaptive batch",
106
+ useJobTrackingAuto: "auto (automatic)",
107
+ useJobTrackingOn: "on (enabled)",
108
+ useJobTrackingOff: "off (disabled)",
109
+ adaptiveBatchAuto: "auto (adaptive)",
110
+ adaptiveBatchOff: "off (fixed)",
111
+ retryDelayMs: "Retry delay (ms)",
112
+ retryableReasons: "Retryable reasons (comma-separated)",
113
+ retryableReasonsHint: "e.g. aborted, error; unknown reasons will not retry",
114
+ stallTitle: "Stall detection (optional)",
115
+ stallDesc: "Online observation of delegate subagents; when enabled, S1-S4 signals auto-abort and reuse the retry mechanism.",
116
+ stallEnabled: "Enable stall detection",
117
+ consecutiveErrors: "S1 consecutive identical errors",
118
+ idleMs: "S2 idle timeout (ms)",
119
+ reasoningWithoutAction: "S3 reasoning-without-action",
120
+ loopCount: "S4 repeat-call loop",
121
+ graceMs: "Grace window (ms)",
122
+ recoverable: "Recoverable (trigger respects retryableReasons)",
123
+ envSigTitle: "Env-contract persistence (optional)",
124
+ envSigDesc: "Cache the executor env-contract after learning once; avoid probing every run.",
125
+ envSigUse: "Contract mode",
126
+ envSigUseAuto: "auto (default: observe then write)",
127
+ envSigUseOff: "off (probe every time)",
128
+ envSigUseManual: "manual (read manual config only)",
129
+ envSigTtl: "Cache TTL (ms)",
130
+ envSigConfirmCount: "Confirm count (write after threshold)",
131
+ invalidCleared: "⚠️ Detected stale config for {count} agent(s); reset to inherit.",
132
+ invalidClearedList: "Affected agents: {list}",
133
+ providerPlaceholder: "Select provider (leave blank to inherit)",
134
+ modelPlaceholder: "Select model (leave blank for provider default)"
135
+ };
136
+
137
+ function emptyDraft() {
138
+ var draft = {};
139
+ for (var i = 0; i < SKILL_ROWS.length; i += 1) {
140
+ draft[SKILL_ROWS[i].name] = { provider: "", model: "", maxTokens: undefined };
141
+ }
142
+ return draft;
143
+ }
144
+
145
+ function rowFromSkill(skill) {
146
+ return {
147
+ provider: typeof skill.provider === "string" ? skill.provider : "",
148
+ model: typeof skill.model === "string" ? skill.model : "",
149
+ maxTokens: typeof skill.maxTokens === "number" ? skill.maxTokens : undefined
150
+ };
151
+ }
152
+
153
+ function buildDraft(skills) {
154
+ var draft = emptyDraft();
155
+ if (Array.isArray(skills)) {
156
+ for (var i = 0; i < skills.length; i += 1) {
157
+ var skill = skills[i];
158
+ if (!skill || typeof skill.name !== "string") continue;
159
+ if (!Object.prototype.hasOwnProperty.call(draft, skill.name)) {
160
+ draft[skill.name] = { provider: "", model: "", maxTokens: undefined };
161
+ }
162
+ draft[skill.name] = rowFromSkill(skill);
163
+ }
164
+ }
165
+ return draft;
166
+ }
167
+
168
+ function isConfigured(row) {
169
+ return row.provider !== "" || row.model !== "" || row.maxTokens !== undefined;
170
+ }
171
+
172
+ function nameSet(skills) {
173
+ var set = new Set();
174
+ if (Array.isArray(skills)) {
175
+ for (var i = 0; i < skills.length; i += 1) {
176
+ var skill = skills[i];
177
+ if (skill && typeof skill.name === "string") set.add(skill.name);
178
+ }
179
+ }
180
+ return set;
181
+ }
182
+
183
+ function useLlmTopology(api, remote) {
184
+ var [state, setState] = React.useState({ providers: [], modelsByProvider: {}, loading: true, error: null });
185
+
186
+ var load = React.useCallback(function () {
187
+ var generation = 0;
188
+ return async function () {
189
+ generation += 1;
190
+ var providers = [];
191
+ var modelsByProvider = {};
192
+ try {
193
+ var responses = await Promise.all([
194
+ api.llm.listConfigurableProviders(),
195
+ api.session.modelCatalog()
196
+ ]);
197
+ var providersResponse = responses[0];
198
+ var modelsResponse = responses[1];
199
+ if (!providersResponse || !providersResponse.ok) {
200
+ throw new Error(providersResponse && providersResponse.error ? providersResponse.error.message : "llm.listConfigurableProviders failed");
201
+ }
202
+ if (!modelsResponse || !modelsResponse.ok) {
203
+ throw new Error(modelsResponse && modelsResponse.error ? modelsResponse.error.message : "session.modelCatalog failed");
204
+ }
205
+ var configurable = providersResponse.value || [];
206
+ for (var i = 0; i < configurable.length; i += 1) {
207
+ var item = configurable[i];
208
+ if (item.declared === false) continue;
209
+ providers.push({
210
+ id: item.provider,
211
+ label: item.displayName && item.displayName !== item.provider ? item.displayName + " (" + item.provider + ")" : item.provider,
212
+ active: item.declared !== false
213
+ });
214
+ }
215
+ var groups = (modelsResponse.value && modelsResponse.value.groups) || [];
216
+ for (var j = 0; j < groups.length; j += 1) {
217
+ var group = groups[j];
218
+ if (!group || typeof group.id !== "string") continue;
219
+ var models = (group.models || []).map(function (model) {
220
+ return {
221
+ id: model.id,
222
+ label: model.name && model.name !== model.id ? model.name + " (" + model.id + ")" : model.id
223
+ };
224
+ });
225
+ modelsByProvider[group.id] = models;
226
+ var known = providers.some(function (provider) { return provider.id === group.id; });
227
+ if (!known) {
228
+ providers.push({
229
+ id: group.id,
230
+ label: group.name && group.name !== group.id ? group.name + " (" + group.id + ")" : group.id,
231
+ active: true
232
+ });
233
+ }
234
+ }
235
+ providers.sort(function (left, right) { return left.id.localeCompare(right.id); });
236
+ setState({ providers: providers, modelsByProvider: modelsByProvider, loading: false, error: null });
237
+ } catch (error) {
238
+ setState({ providers: providers, modelsByProvider: modelsByProvider, loading: false, error: error && error.message ? error.message : String(error) });
239
+ }
240
+ };
241
+ }, [api]);
242
+
243
+ React.useEffect(function () {
244
+ var run = load();
245
+ run();
246
+ var off = remote && remote.$on ? remote.$on("llm/adapters-updated", function () { run(); }) : undefined;
247
+ return function () {
248
+ if (typeof off === "function") off();
249
+ };
250
+ }, [load, remote]);
251
+
252
+ return {
253
+ providers: state.providers,
254
+ modelsByProvider: state.modelsByProvider,
255
+ loading: state.loading,
256
+ error: state.error
257
+ };
258
+ }
259
+
260
+ function installCss() {
261
+ var tagId = "dsh-cohub/cohub-card.css";
262
+ if (typeof document === "undefined") return;
263
+ if (document.querySelector('style[data-plugin-css="' + tagId + '"]') !== null) return;
264
+ var css = [
265
+ ".cohub-card{max-width:760px;color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);border-radius:12px;padding:14px 16px;background:var(--dsw-alias-bg-layer-3);}",
266
+ ".cohub-title{margin:0;font-size:15px;font-weight:600;line-height:22px;}",
267
+ ".cohub-desc{color:var(--dsw-alias-label-tertiary);margin:4px 0 0;font-size:13px;line-height:20px;}",
268
+ ".cohub-status{margin:8px 0 0;font-size:12px;line-height:18px;}",
269
+ ".cohub-rows{margin:14px 0 0;padding:0;list-style:none;display:flex;flex-direction:column;gap:8px;}",
270
+ ".cohub-row{border:1px solid var(--dsw-alias-border-l2);border-radius:10px;padding:10px 12px;background:var(--dsw-alias-bg-layer-2);}",
271
+ ".cohub-row-head{display:flex;align-items:center;gap:8px;}",
272
+ ".cohub-row-name{font-size:13px;font-weight:600;line-height:20px;}",
273
+ ".cohub-row-id{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;}",
274
+ ".cohub-badge{margin-left:auto;border-radius:999px;padding:1px 8px;font-size:11px;line-height:17px;white-space:nowrap;}",
275
+ ".cohub-badge-explicit{color:var(--dsw-alias-state-success-primary);border:1px solid var(--dsw-alias-state-success-primary);}",
276
+ ".cohub-badge-inherited{color:var(--dsw-alias-label-tertiary);border:1px solid var(--dsw-alias-border-l2);}",
277
+ ".cohub-fields{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:8px;}",
278
+ ".cohub-field{display:flex;flex-direction:column;gap:4px;}",
279
+ ".cohub-label{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px;}",
280
+ ".cohub-select,.cohub-input{box-sizing:border-box;width:100%;height:32px;font:inherit;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:0 10px;font-size:13px;line-height:20px;}",
281
+ ".cohub-select:focus-visible,.cohub-input:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none;}",
282
+ ".cohub-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:12px;}",
283
+ ".cohub-button{height:32px;font:inherit;cursor:pointer;border-radius:8px;padding:0 12px;font-size:13px;line-height:20px;}",
284
+ ".cohub-button-primary{color:var(--dsw-alias-label-primary-foreground);background:var(--dsw-alias-button-primary-fill);border:none;}",
285
+ ".cohub-button-primary:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover);}",
286
+ ".cohub-button-ghost{color:var(--dsw-alias-label-secondary);background:transparent;border:1px solid var(--dsw-alias-border-l2);}",
287
+ ".cohub-button-ghost:hover:not(:disabled){color:var(--dsw-alias-label-primary);}",
288
+ ".cohub-button:disabled{opacity:.45;cursor:default;}",
289
+ ".cohub-error{color:var(--dsw-alias-state-error-primary);}",
290
+ ".cohub-saved{color:var(--dsw-alias-state-success-primary);}",
291
+ ".cohub-subtitle{margin:16px 0 0;font-size:13px;font-weight:600;line-height:20px;}",
292
+ ".cohub-schedule{border:1px solid var(--dsw-alias-border-l2);border-radius:10px;padding:10px 12px;margin-top:10px;background:var(--dsw-alias-bg-layer-2);}",
293
+ ".cohub-schedule-fields{display:grid;grid-template-columns:1fr 1fr 1fr 1fr;gap:8px;margin-top:8px;}",
294
+ ".cohub-retry-fields{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:8px;}",
295
+ ".cohub-field-row{display:flex;flex-direction:column;gap:4px;margin-top:10px;}",
296
+ ".cohub-stall-fields{display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px;margin-top:8px;}",
297
+ ".cohub-envsig-fields{display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px;margin-top:8px;}",
298
+ ".cohub-checkbox-row{display:flex;align-items:center;gap:6px;color:var(--dsw-alias-label-secondary);font-size:13px;line-height:20px;cursor:pointer;}",
299
+ ".cohub-notice{background:var(--dsw-alias-state-warning-bg,#fff8e1);color:var(--dsw-alias-state-warning-primary,#8d6e00);border:1px solid var(--dsw-alias-state-warning-border,#ffc107);border-radius:8px;padding:8px 12px;margin-bottom:8px;font-size:13px;line-height:20px;}",
300
+ ".cohub-clear-btn{background:none;border:none;color:var(--dsw-alias-label-tertiary);cursor:pointer;font-size:16px;line-height:1;padding:0 4px;margin-left:4px;}.cohub-clear-btn:hover{color:var(--dsw-alias-label-primary);}"
301
+ ].join("\n");
302
+ var tag = document.createElement("style");
303
+ tag.dataset.plugin = "dsh-cohub";
304
+ tag.dataset.pluginCss = tagId;
305
+ tag.textContent = css;
306
+ document.head.appendChild(tag);
307
+ }
308
+
309
+ function CohubSettingsCard(props) {
310
+ var scope = props.scope;
311
+ var api = props.api;
312
+ var remote = props.remote;
313
+ var t = typeof props.t === "function" ? props.t : function (key) { return zh[key] || key; };
314
+
315
+ if (!scope || !api) return null;
316
+
317
+ var subscribe = React.useCallback(function (listener) { return scope.subscribe(listener); }, [scope]);
318
+ var getSnapshot = React.useCallback(function () { return scope.getSnapshot(); }, [scope]);
319
+ var snapshot = React.useSyncExternalStore(subscribe, getSnapshot);
320
+
321
+ var [draft, setDraft] = React.useState(function () {
322
+ return buildDraft(Array.isArray(snapshot.value && snapshot.value.skills) ? snapshot.value.skills : []);
323
+ }, { key: "cohub" });
324
+ var [dirty, setDirty] = React.useState(false);
325
+ var [touched, setTouched] = React.useState(function () { return new Set(); });
326
+ var [saving, setSaving] = React.useState(false);
327
+ var [saved, setSaved] = React.useState(false);
328
+ var [error, setError] = React.useState("");
329
+ var [invalidNotice, setInvalidNotice] = React.useState(null);
330
+
331
+ var [scheduleDraft, setScheduleDraft] = React.useState(function () {
332
+ var s = snapshot.value && snapshot.value.schedule;
333
+ return {
334
+ maxParallelBatch: s && typeof s.maxParallelBatch === "number" ? s.maxParallelBatch : 3,
335
+ wallClockBudgetMs: s && typeof s.wallClockBudgetMs === "number" ? s.wallClockBudgetMs : 600000,
336
+ useJobTracking: s && typeof s.useJobTracking === "string" ? s.useJobTracking : "auto",
337
+ adaptiveBatch: s && typeof s.adaptiveBatch === "string" ? s.adaptiveBatch : "auto"
338
+ };
339
+ });
340
+ var [retryDraft, setRetryDraft] = React.useState(function () {
341
+ var r = snapshot.value && snapshot.value.delegateRetry;
342
+ return {
343
+ maxRetries: r && typeof r.maxRetries === "number" ? r.maxRetries : 0,
344
+ retryDelayMs: r && typeof r.retryDelayMs === "number" ? r.retryDelayMs : 1000,
345
+ retryableReasons: Array.isArray(r && r.retryableReasons) ? r.retryableReasons : ["aborted"]
346
+ };
347
+ });
348
+ var [stallDraft, setStallDraft] = React.useState(function () {
349
+ var s = snapshot.value && snapshot.value.delegateRetry && snapshot.value.delegateRetry.stall;
350
+ return {
351
+ enabled: !!(s && s.enabled),
352
+ consecutiveErrors: s && typeof s.consecutiveErrors === "number" ? s.consecutiveErrors : 3,
353
+ idleMs: s && typeof s.idleMs === "number" ? s.idleMs : 180000,
354
+ reasoningWithoutAction: s && typeof s.reasoningWithoutAction === "number" ? s.reasoningWithoutAction : 50,
355
+ loopCount: s && typeof s.loopCount === "number" ? s.loopCount : 3,
356
+ graceMs: s && typeof s.graceMs === "number" ? s.graceMs : 30000,
357
+ recoverable: s && typeof s.recoverable === "boolean" ? s.recoverable : true
358
+ };
359
+ });
360
+ var [envSigDraft, setEnvSigDraft] = React.useState(function () {
361
+ var e = snapshot.value && snapshot.value.envSignatures;
362
+ return {
363
+ use: e && typeof e.use === "string" ? e.use : "auto",
364
+ ttlMs: e && typeof e.ttlMs === "number" ? e.ttlMs : 604800000,
365
+ confirmCount: e && typeof e.confirmCount === "number" ? e.confirmCount : 2
366
+ };
367
+ });
368
+ var [scheduleTouched, setScheduleTouched] = React.useState(false);
369
+ var [retryTouched, setRetryTouched] = React.useState(false);
370
+ var [stallTouched, setStallTouched] = React.useState(false);
371
+ var [envSigTouched, setEnvSigTouched] = React.useState(false);
372
+
373
+ var topology = useLlmTopology(api, remote);
374
+
375
+ React.useEffect(function () {
376
+ if (!dirty) {
377
+ setDraft(buildDraft(Array.isArray(snapshot.value && snapshot.value.skills) ? snapshot.value.skills : []));
378
+ setTouched(new Set());
379
+ var s = snapshot.value && snapshot.value.schedule;
380
+ setScheduleDraft({
381
+ maxParallelBatch: s && typeof s.maxParallelBatch === "number" ? s.maxParallelBatch : 3,
382
+ wallClockBudgetMs: s && typeof s.wallClockBudgetMs === "number" ? s.wallClockBudgetMs : 600000,
383
+ useJobTracking: s && typeof s.useJobTracking === "string" ? s.useJobTracking : "auto",
384
+ adaptiveBatch: s && typeof s.adaptiveBatch === "string" ? s.adaptiveBatch : "auto"
385
+ });
386
+ var r = snapshot.value && snapshot.value.delegateRetry;
387
+ setRetryDraft({
388
+ maxRetries: r && typeof r.maxRetries === "number" ? r.maxRetries : 0,
389
+ retryDelayMs: r && typeof r.retryDelayMs === "number" ? r.retryDelayMs : 1000,
390
+ retryableReasons: Array.isArray(r && r.retryableReasons) ? r.retryableReasons : ["aborted"]
391
+ });
392
+ var st = snapshot.value && snapshot.value.delegateRetry && snapshot.value.delegateRetry.stall;
393
+ setStallDraft({
394
+ enabled: !!(st && st.enabled),
395
+ consecutiveErrors: st && typeof st.consecutiveErrors === "number" ? st.consecutiveErrors : 3,
396
+ idleMs: st && typeof st.idleMs === "number" ? st.idleMs : 180000,
397
+ reasoningWithoutAction: st && typeof st.reasoningWithoutAction === "number" ? st.reasoningWithoutAction : 50,
398
+ loopCount: st && typeof st.loopCount === "number" ? st.loopCount : 3,
399
+ graceMs: st && typeof st.graceMs === "number" ? st.graceMs : 30000,
400
+ recoverable: st && typeof st.recoverable === "boolean" ? st.recoverable : true
401
+ });
402
+ var e = snapshot.value && snapshot.value.envSignatures;
403
+ setEnvSigDraft({
404
+ use: e && typeof e.use === "string" ? e.use : "auto",
405
+ ttlMs: e && typeof e.ttlMs === "number" ? e.ttlMs : 604800000,
406
+ confirmCount: e && typeof e.confirmCount === "number" ? e.confirmCount : 2
407
+ });
408
+ setScheduleTouched(false);
409
+ setRetryTouched(false);
410
+ setStallTouched(false);
411
+ setEnvSigTouched(false);
412
+ }
413
+ }, [snapshot, dirty]);
414
+
415
+ var prevTopologyRef = React.useRef(topology.loading);
416
+ React.useEffect(function () {
417
+ var wasLoading = prevTopologyRef.current;
418
+ prevTopologyRef.current = topology.loading;
419
+ if (topology.loading) return;
420
+ if (!wasLoading) return;
421
+
422
+ var providerIds = new Set(topology.providers.map(function (p) { return p.id; }));
423
+ var cleared = [];
424
+ setDraft(function (prev) {
425
+ var next = {};
426
+ var changed = false;
427
+ for (var key in prev) {
428
+ var row = prev[key];
429
+ var newRow = { provider: row.provider, model: row.model, maxTokens: row.maxTokens };
430
+ if (row.provider && !providerIds.has(row.provider)) {
431
+ newRow.provider = "";
432
+ newRow.model = "";
433
+ changed = true;
434
+ cleared.push(key);
435
+ } else if (row.provider && row.model) {
436
+ var models = topology.modelsByProvider[row.provider] || [];
437
+ var modelIds = new Set(models.map(function (m) { return m.id; }));
438
+ if (!modelIds.has(row.model)) {
439
+ newRow.model = "";
440
+ changed = true;
441
+ cleared.push(key);
442
+ }
443
+ }
444
+ next[key] = newRow;
445
+ }
446
+ return changed ? next : prev;
447
+ });
448
+ if (cleared.length > 0) {
449
+ var skillLabels = cleared.map(function (name) {
450
+ var found = SKILL_ROWS.find(function (s) { return s.name === name; });
451
+ return found ? found.label : name;
452
+ });
453
+ setInvalidNotice(
454
+ t("invalidCleared").replace("{count}", String(cleared.length)) + " " +
455
+ t("invalidClearedList").replace("{list}", skillLabels.join("、"))
456
+ );
457
+ setDirty(true);
458
+ setSaved(false);
459
+ }
460
+ }, [topology.loading, topology.providers, topology.modelsByProvider]);
461
+
462
+ var effectiveSkills = Array.isArray(snapshot.value && snapshot.value.skills) ? snapshot.value.skills : [];
463
+ var baseNames = nameSet(snapshot.base && snapshot.base.skills);
464
+ var userNames = nameSet(snapshot.user && snapshot.user.skills);
465
+ var ready = snapshot.status === "ready";
466
+ var writable = ready && snapshot.writable === true;
467
+
468
+ function update(name, field, value) {
469
+ setDraft(function (prev) {
470
+ var next = {};
471
+ for (var key in prev) next[key] = prev[key];
472
+ next[name] = { provider: prev[name].provider, model: prev[name].model, maxTokens: prev[name].maxTokens };
473
+ next[name][field] = value;
474
+ return next;
475
+ });
476
+ setTouched(function (prev) {
477
+ var next = new Set(prev);
478
+ next.add(name);
479
+ return next;
480
+ });
481
+ setDirty(true);
482
+ setSaved(false);
483
+ setError("");
484
+ }
485
+
486
+ function updateSchedule(field, value) {
487
+ setScheduleDraft(function (prev) {
488
+ var next = {};
489
+ for (var key in prev) next[key] = prev[key];
490
+ next[field] = value;
491
+ return next;
492
+ });
493
+ setScheduleTouched(true);
494
+ setDirty(true);
495
+ setSaved(false);
496
+ setError("");
497
+ }
498
+
499
+ function updateRetry(field, value) {
500
+ setRetryDraft(function (prev) {
501
+ var next = {};
502
+ for (var key in prev) next[key] = prev[key];
503
+ next[field] = value;
504
+ return next;
505
+ });
506
+ setRetryTouched(true);
507
+ setDirty(true);
508
+ setSaved(false);
509
+ setError("");
510
+ }
511
+
512
+ function updateStall(field, value) {
513
+ setStallDraft(function (prev) {
514
+ var next = {};
515
+ for (var key in prev) next[key] = prev[key];
516
+ next[field] = value;
517
+ return next;
518
+ });
519
+ setStallTouched(true);
520
+ setDirty(true);
521
+ setSaved(false);
522
+ setError("");
523
+ }
524
+
525
+ function updateEnvSig(field, value) {
526
+ setEnvSigDraft(function (prev) {
527
+ var next = {};
528
+ for (var key in prev) next[key] = prev[key];
529
+ next[field] = value;
530
+ return next;
531
+ });
532
+ setEnvSigTouched(true);
533
+ setDirty(true);
534
+ setSaved(false);
535
+ setError("");
536
+ }
537
+
538
+ function discard() {
539
+ setDraft(buildDraft(effectiveSkills));
540
+ setTouched(new Set());
541
+ var s = snapshot.value && snapshot.value.schedule;
542
+ setScheduleDraft({
543
+ maxParallelBatch: s && typeof s.maxParallelBatch === "number" ? s.maxParallelBatch : 3,
544
+ wallClockBudgetMs: s && typeof s.wallClockBudgetMs === "number" ? s.wallClockBudgetMs : 600000,
545
+ useJobTracking: s && typeof s.useJobTracking === "string" ? s.useJobTracking : "auto",
546
+ adaptiveBatch: s && typeof s.adaptiveBatch === "string" ? s.adaptiveBatch : "auto"
547
+ });
548
+ var r = snapshot.value && snapshot.value.delegateRetry;
549
+ setRetryDraft({
550
+ maxRetries: r && typeof r.maxRetries === "number" ? r.maxRetries : 0,
551
+ retryDelayMs: r && typeof r.retryDelayMs === "number" ? r.retryDelayMs : 1000,
552
+ retryableReasons: Array.isArray(r && r.retryableReasons) ? r.retryableReasons : ["aborted"]
553
+ });
554
+ var st = snapshot.value && snapshot.value.delegateRetry && snapshot.value.delegateRetry.stall;
555
+ setStallDraft({
556
+ enabled: !!(st && st.enabled),
557
+ consecutiveErrors: st && typeof st.consecutiveErrors === "number" ? st.consecutiveErrors : 3,
558
+ idleMs: st && typeof st.idleMs === "number" ? st.idleMs : 180000,
559
+ reasoningWithoutAction: st && typeof st.reasoningWithoutAction === "number" ? st.reasoningWithoutAction : 50,
560
+ loopCount: st && typeof st.loopCount === "number" ? st.loopCount : 3,
561
+ graceMs: st && typeof st.graceMs === "number" ? st.graceMs : 30000,
562
+ recoverable: st && typeof st.recoverable === "boolean" ? st.recoverable : true
563
+ });
564
+ var e = snapshot.value && snapshot.value.envSignatures;
565
+ setEnvSigDraft({
566
+ use: e && typeof e.use === "string" ? e.use : "auto",
567
+ ttlMs: e && typeof e.ttlMs === "number" ? e.ttlMs : 604800000,
568
+ confirmCount: e && typeof e.confirmCount === "number" ? e.confirmCount : 2
569
+ });
570
+ setScheduleTouched(false);
571
+ setRetryTouched(false);
572
+ setStallTouched(false);
573
+ setEnvSigTouched(false);
574
+ setDirty(false);
575
+ setSaved(false);
576
+ setError("");
577
+ }
578
+
579
+ async function save() {
580
+ if (!dirty || saving || !writable) return;
581
+ setSaving(true);
582
+ setSaved(false);
583
+ setError("");
584
+ var next = [];
585
+ for (var name in draft) {
586
+ var row = draft[name];
587
+ var item = { name: name };
588
+ if (row.provider) item.provider = row.provider;
589
+ if (row.model) item.model = row.model;
590
+ if (row.maxTokens !== undefined) item.maxTokens = row.maxTokens;
591
+ if (item.provider || item.model || item.maxTokens !== undefined) next.push(item);
592
+ }
593
+ try {
594
+ if (next.length === 0) await scope.unset("skills");
595
+ else await scope.set("skills", next);
596
+ if (scheduleTouched) {
597
+ var batch = parseInt(scheduleDraft.maxParallelBatch, 10);
598
+ var wall = parseInt(scheduleDraft.wallClockBudgetMs, 10);
599
+ if (!Number.isFinite(batch) || batch < 1) batch = 3;
600
+ if (!Number.isFinite(wall) || wall < 0) wall = 600000;
601
+ await scope.set("schedule", {
602
+ maxParallelBatch: batch,
603
+ wallClockBudgetMs: wall,
604
+ useJobTracking: scheduleDraft.useJobTracking || "auto",
605
+ adaptiveBatch: scheduleDraft.adaptiveBatch || "auto"
606
+ });
607
+ }
608
+ if (retryTouched || stallTouched) {
609
+ var retries = parseInt(retryDraft.maxRetries, 10);
610
+ var delay = parseInt(retryDraft.retryDelayMs, 10);
611
+ if (!Number.isFinite(retries) || retries < 0) retries = 0;
612
+ if (!Number.isFinite(delay) || delay < 0) delay = 1000;
613
+ var reasons = String(retryDraft.retryableReasons || "")
614
+ .split(/[\s,]+/)
615
+ .filter(function (s) { return s && s.length > 0; });
616
+ if (reasons.length === 0) reasons = ["aborted"];
617
+ var retryPayload = {
618
+ maxRetries: retries,
619
+ retryDelayMs: delay,
620
+ retryableReasons: reasons
621
+ };
622
+ if (stallTouched) {
623
+ var ce = parseInt(stallDraft.consecutiveErrors, 10);
624
+ var idle = parseInt(stallDraft.idleMs, 10);
625
+ var rwa = parseInt(stallDraft.reasoningWithoutAction, 10);
626
+ var loop = parseInt(stallDraft.loopCount, 10);
627
+ var grace = parseInt(stallDraft.graceMs, 10);
628
+ if (!Number.isFinite(ce) || ce < 1) ce = 3;
629
+ if (!Number.isFinite(idle) || idle < 0) idle = 180000;
630
+ if (!Number.isFinite(rwa) || rwa < 1) rwa = 50;
631
+ if (!Number.isFinite(loop) || loop < 1) loop = 3;
632
+ if (!Number.isFinite(grace) || grace < 0) grace = 30000;
633
+ retryPayload.stall = {
634
+ enabled: !!stallDraft.enabled,
635
+ consecutiveErrors: ce,
636
+ idleMs: idle,
637
+ reasoningWithoutAction: rwa,
638
+ loopCount: loop,
639
+ graceMs: grace,
640
+ recoverable: !!stallDraft.recoverable
641
+ };
642
+ } else {
643
+ var cur = snapshot.value && snapshot.value.delegateRetry;
644
+ if (cur && cur.stall) retryPayload.stall = cur.stall;
645
+ }
646
+ await scope.set("delegateRetry", retryPayload);
647
+ }
648
+ if (envSigTouched) {
649
+ var ttl = parseInt(envSigDraft.ttlMs, 10);
650
+ var cc = parseInt(envSigDraft.confirmCount, 10);
651
+ if (!Number.isFinite(ttl) || ttl < 0) ttl = 604800000;
652
+ if (!Number.isFinite(cc) || cc < 1) cc = 2;
653
+ await scope.set("envSignatures", {
654
+ use: envSigDraft.use || "auto",
655
+ ttlMs: ttl,
656
+ confirmCount: cc
657
+ });
658
+ }
659
+ setDirty(false);
660
+ setTouched(new Set());
661
+ setScheduleTouched(false);
662
+ setRetryTouched(false);
663
+ setStallTouched(false);
664
+ setEnvSigTouched(false);
665
+ setSaved(true);
666
+ } catch (err) {
667
+ setError(err && err.message ? err.message : String(err));
668
+ } finally {
669
+ setSaving(false);
670
+ }
671
+ }
672
+
673
+ if (!ready) {
674
+ return React.createElement("div", { className: "cohub-card" },
675
+ React.createElement("h3", { className: "cohub-title" }, t("title")),
676
+ React.createElement("p", { className: "cohub-desc" }, t("description")),
677
+ React.createElement("p", { className: "cohub-status" }, t(snapshot.status === "unavailable" ? "unavailable" : "loading"))
678
+ );
679
+ }
680
+
681
+ var rows = SKILL_ROWS.map(function (skill) {
682
+ var row = draft[skill.name] || { provider: "", model: "", maxTokens: undefined };
683
+ var models = topology.modelsByProvider[row.provider] || [];
684
+ var modelOptions = models.map(function (model) {
685
+ return React.createElement("option", { key: model.id, value: model.id }, model.label);
686
+ });
687
+ if (row.model && !models.some(function (m) { return m.id === row.model; })) {
688
+ modelOptions.unshift(
689
+ React.createElement("option", { key: "__current", value: row.model, disabled: true }, row.model + " (已失效)")
690
+ );
691
+ }
692
+ var providerOptions;
693
+ if (topology.loading) {
694
+ providerOptions = [React.createElement("option", { key: "__loading", value: "", disabled: true }, t("loading"))];
695
+ } else if (topology.error) {
696
+ providerOptions = [React.createElement("option", { key: "__error", value: "", disabled: true }, t("loadProvidersFailed"))];
697
+ } else if (topology.providers.length === 0) {
698
+ providerOptions = [React.createElement("option", { key: "__empty", value: "", disabled: true }, t("loadProvidersFailed"))];
699
+ } else {
700
+ providerOptions = topology.providers.map(function (provider) {
701
+ return React.createElement("option", { key: provider.id, value: provider.id }, provider.label);
702
+ });
703
+ if (row.provider && !topology.providers.some(function (p) { return p.id === row.provider; })) {
704
+ providerOptions.unshift(
705
+ React.createElement("option", { key: "__current-provider", value: row.provider, disabled: true }, row.provider + " (已失效)")
706
+ );
707
+ }
708
+ }
709
+
710
+ var modelControl;
711
+ if (!row.provider) {
712
+ modelControl = React.createElement("select", { className: "cohub-select", value: "", disabled: true },
713
+ React.createElement("option", { value: "" }, t("selectProviderFirst"))
714
+ );
715
+ } else if (topology.loading) {
716
+ modelControl = React.createElement("select", { className: "cohub-select", value: "", disabled: true },
717
+ React.createElement("option", { value: "" }, t("loading"))
718
+ );
719
+ } else if (models.length > 0) {
720
+ modelControl = React.createElement("select", {
721
+ className: "cohub-select",
722
+ value: row.model,
723
+ disabled: !writable,
724
+ onChange: function (event) { update(skill.name, "model", event.target.value); }
725
+ }, modelOptions);
726
+ } else {
727
+ modelControl = React.createElement("input", {
728
+ className: "cohub-input",
729
+ value: row.model,
730
+ disabled: !writable,
731
+ placeholder: t("customModel"),
732
+ onChange: function (event) { update(skill.name, "model", event.target.value); }
733
+ });
734
+ }
735
+
736
+ var badgeClass = userNames.has(skill.name) || touched.has(skill.name) ? "cohub-badge cohub-badge-explicit" : baseNames.has(skill.name) ? "cohub-badge cohub-badge-inherited" : "cohub-badge cohub-badge-inherited";
737
+ var badgeText = userNames.has(skill.name) || touched.has(skill.name) ? t("configured") : t("inherited");
738
+
739
+ return React.createElement("li", { key: skill.name, className: "cohub-row" },
740
+ React.createElement("div", { className: "cohub-row-head" },
741
+ React.createElement("span", { className: "cohub-row-name" }, skill.label),
742
+ React.createElement("span", { className: "cohub-row-id" }, skill.name),
743
+ React.createElement("span", { className: badgeClass }, badgeText)
744
+ ),
745
+ React.createElement("div", { className: "cohub-fields" },
746
+ React.createElement("div", { className: "cohub-field" },
747
+ React.createElement("label", { className: "cohub-label" }, t("provider")),
748
+ React.createElement("select", {
749
+ className: "cohub-select",
750
+ value: row.provider,
751
+ disabled: !writable,
752
+ onChange: function (event) { update(skill.name, "provider", event.target.value); }
753
+ }, providerOptions),
754
+ row.provider && writable ?
755
+ React.createElement("button", { type: "button", className: "cohub-clear-btn", onClick: function () { update(skill.name, "provider", ""); update(skill.name, "model", ""); }, title: "清除" }, "\u00D7") :
756
+ null
757
+ ),
758
+ React.createElement("div", { className: "cohub-field" },
759
+ React.createElement("label", { className: "cohub-label" }, t("model")),
760
+ modelControl,
761
+ row.model && writable && row.provider ?
762
+ React.createElement("button", { type: "button", className: "cohub-clear-btn", onClick: function () { update(skill.name, "model", ""); }, title: "清除" }, "\u00D7") :
763
+ null
764
+ )
765
+ )
766
+ );
767
+ });
768
+
769
+ return React.createElement("div", { className: "cohub-card" },
770
+ React.createElement("h3", { className: "cohub-title" }, t("title")),
771
+ React.createElement("p", { className: "cohub-desc" }, t("description")),
772
+ topology.error ? React.createElement("p", { className: "cohub-status cohub-error" }, t("loadProvidersFailed") + ": " + topology.error) : null,
773
+ invalidNotice ? React.createElement("div", { className: "cohub-notice" },
774
+ React.createElement("span", null, invalidNotice)
775
+ ) : null,
776
+ React.createElement("ul", { className: "cohub-rows" }, rows),
777
+ React.createElement("div", { className: "cohub-schedule" },
778
+ React.createElement("h4", { className: "cohub-subtitle" }, t("scheduleTitle")),
779
+ React.createElement("p", { className: "cohub-desc" }, t("scheduleDesc")),
780
+ React.createElement("div", { className: "cohub-schedule-fields" },
781
+ React.createElement("div", { className: "cohub-field" },
782
+ React.createElement("label", { className: "cohub-label" }, t("batchSize")),
783
+ React.createElement("input", { className: "cohub-input", type: "number", min: 1, step: 1, value: scheduleDraft.maxParallelBatch, disabled: !writable, onChange: function (event) { updateSchedule("maxParallelBatch", event.target.value); } })
784
+ ),
785
+ React.createElement("div", { className: "cohub-field" },
786
+ React.createElement("label", { className: "cohub-label" }, t("wallClock")),
787
+ React.createElement("input", { className: "cohub-input", type: "number", min: 0, step: 1000, value: scheduleDraft.wallClockBudgetMs, disabled: !writable, onChange: function (event) { updateSchedule("wallClockBudgetMs", event.target.value); } })
788
+ ),
789
+ React.createElement("div", { className: "cohub-field" },
790
+ React.createElement("label", { className: "cohub-label" }, t("useJobTrackingLabel")),
791
+ React.createElement("select", { className: "cohub-select", value: scheduleDraft.useJobTracking, disabled: !writable, onChange: function (event) { updateSchedule("useJobTracking", event.target.value); } },
792
+ React.createElement("option", { value: "auto" }, t("useJobTrackingAuto")),
793
+ React.createElement("option", { value: "on" }, t("useJobTrackingOn")),
794
+ React.createElement("option", { value: "off" }, t("useJobTrackingOff"))
795
+ )
796
+ ),
797
+ React.createElement("div", { className: "cohub-field" },
798
+ React.createElement("label", { className: "cohub-label" }, t("adaptiveBatchLabel")),
799
+ React.createElement("select", { className: "cohub-select", value: scheduleDraft.adaptiveBatch, disabled: !writable, onChange: function (event) { updateSchedule("adaptiveBatch", event.target.value); } },
800
+ React.createElement("option", { value: "auto" }, t("adaptiveBatchAuto")),
801
+ React.createElement("option", { value: "off" }, t("adaptiveBatchOff"))
802
+ )
803
+ )
804
+ )
805
+ ),
806
+ React.createElement("div", { className: "cohub-retry" },
807
+ React.createElement("h4", { className: "cohub-subtitle" }, t("maxRetries") + " / " + t("retryDelayMs")),
808
+ React.createElement("div", { className: "cohub-retry-fields" },
809
+ React.createElement("div", { className: "cohub-field" },
810
+ React.createElement("label", { className: "cohub-label" }, t("maxRetries")),
811
+ React.createElement("input", { className: "cohub-input", type: "number", min: 0, step: 1, value: retryDraft.maxRetries, disabled: !writable, onChange: function (event) { updateRetry("maxRetries", event.target.value); } })
812
+ ),
813
+ React.createElement("div", { className: "cohub-field" },
814
+ React.createElement("label", { className: "cohub-label" }, t("retryDelayMs")),
815
+ React.createElement("input", { className: "cohub-input", type: "number", min: 0, step: 100, value: retryDraft.retryDelayMs, disabled: !writable, onChange: function (event) { updateRetry("retryDelayMs", event.target.value); } })
816
+ )
817
+ ),
818
+ React.createElement("div", { className: "cohub-field-row" },
819
+ React.createElement("label", { className: "cohub-label" }, t("retryableReasons")),
820
+ React.createElement("input", { className: "cohub-input", type: "text", value: (Array.isArray(retryDraft.retryableReasons) ? retryDraft.retryableReasons : []).join(", "), disabled: !writable, placeholder: "aborted, error", onChange: function (event) { updateRetry("retryableReasons", event.target.value); } }),
821
+ React.createElement("p", { className: "cohub-desc" }, t("retryableReasonsHint"))
822
+ )
823
+ ),
824
+ React.createElement("div", { className: "cohub-stall" },
825
+ React.createElement("h4", { className: "cohub-subtitle" }, t("stallTitle")),
826
+ React.createElement("p", { className: "cohub-desc" }, t("stallDesc")),
827
+ React.createElement("label", { className: "cohub-checkbox-row" },
828
+ React.createElement("input", { type: "checkbox", checked: !!stallDraft.enabled, disabled: !writable, onChange: function (event) { updateStall("enabled", event.target.checked); } }),
829
+ " " + t("stallEnabled")
830
+ ),
831
+ React.createElement("div", { className: "cohub-stall-fields" },
832
+ React.createElement("div", { className: "cohub-field" },
833
+ React.createElement("label", { className: "cohub-label" }, t("consecutiveErrors")),
834
+ React.createElement("input", { className: "cohub-input", type: "number", min: 1, step: 1, value: stallDraft.consecutiveErrors, disabled: !writable || !stallDraft.enabled, onChange: function (event) { updateStall("consecutiveErrors", event.target.value); } })
835
+ ),
836
+ React.createElement("div", { className: "cohub-field" },
837
+ React.createElement("label", { className: "cohub-label" }, t("idleMs")),
838
+ React.createElement("input", { className: "cohub-input", type: "number", min: 0, step: 1000, value: stallDraft.idleMs, disabled: !writable || !stallDraft.enabled, onChange: function (event) { updateStall("idleMs", event.target.value); } })
839
+ ),
840
+ React.createElement("div", { className: "cohub-field" },
841
+ React.createElement("label", { className: "cohub-label" }, t("reasoningWithoutAction")),
842
+ React.createElement("input", { className: "cohub-input", type: "number", min: 1, step: 1, value: stallDraft.reasoningWithoutAction, disabled: !writable || !stallDraft.enabled, onChange: function (event) { updateStall("reasoningWithoutAction", event.target.value); } })
843
+ ),
844
+ React.createElement("div", { className: "cohub-field" },
845
+ React.createElement("label", { className: "cohub-label" }, t("loopCount")),
846
+ React.createElement("input", { className: "cohub-input", type: "number", min: 1, step: 1, value: stallDraft.loopCount, disabled: !writable || !stallDraft.enabled, onChange: function (event) { updateStall("loopCount", event.target.value); } })
847
+ ),
848
+ React.createElement("div", { className: "cohub-field" },
849
+ React.createElement("label", { className: "cohub-label" }, t("graceMs")),
850
+ React.createElement("input", { className: "cohub-input", type: "number", min: 0, step: 1000, value: stallDraft.graceMs, disabled: !writable || !stallDraft.enabled, onChange: function (event) { updateStall("graceMs", event.target.value); } })
851
+ )
852
+ ),
853
+ React.createElement("label", { className: "cohub-checkbox-row" },
854
+ React.createElement("input", { type: "checkbox", checked: !!stallDraft.recoverable, disabled: !writable || !stallDraft.enabled, onChange: function (event) { updateStall("recoverable", event.target.checked); } }),
855
+ " " + t("recoverable")
856
+ )
857
+ ),
858
+ React.createElement("div", { className: "cohub-envsig" },
859
+ React.createElement("h4", { className: "cohub-subtitle" }, t("envSigTitle")),
860
+ React.createElement("p", { className: "cohub-desc" }, t("envSigDesc")),
861
+ React.createElement("div", { className: "cohub-envsig-fields" },
862
+ React.createElement("div", { className: "cohub-field" },
863
+ React.createElement("label", { className: "cohub-label" }, t("envSigUse")),
864
+ React.createElement("select", { className: "cohub-select", value: envSigDraft.use, disabled: !writable, onChange: function (event) { updateEnvSig("use", event.target.value); } },
865
+ React.createElement("option", { value: "auto" }, t("envSigUseAuto")),
866
+ React.createElement("option", { value: "off" }, t("envSigUseOff")),
867
+ React.createElement("option", { value: "manual" }, t("envSigUseManual"))
868
+ )
869
+ ),
870
+ React.createElement("div", { className: "cohub-field" },
871
+ React.createElement("label", { className: "cohub-label" }, t("envSigTtl")),
872
+ React.createElement("input", { className: "cohub-input", type: "number", min: 0, step: 86400000, value: envSigDraft.ttlMs, disabled: !writable, onChange: function (event) { updateEnvSig("ttlMs", event.target.value); } })
873
+ ),
874
+ React.createElement("div", { className: "cohub-field" },
875
+ React.createElement("label", { className: "cohub-label" }, t("envSigConfirmCount")),
876
+ React.createElement("input", { className: "cohub-input", type: "number", min: 1, step: 1, value: envSigDraft.confirmCount, disabled: !writable, onChange: function (event) { updateEnvSig("confirmCount", event.target.value); } })
877
+ )
878
+ )
879
+ ),
880
+ error ? React.createElement("p", { className: "cohub-status cohub-error" }, t("failed") + error) : null,
881
+ saved ? React.createElement("p", { className: "cohub-status cohub-saved" }, t("saved")) : null,
882
+ React.createElement("div", { className: "cohub-actions" },
883
+ React.createElement("button", { type: "button", className: "cohub-button cohub-button-ghost", disabled: !dirty || saving, onClick: discard }, t("discard")),
884
+ React.createElement("button", { type: "button", className: "cohub-button cohub-button-primary", disabled: !dirty || saving || !writable, onClick: save }, t(saving ? "saving" : "save"))
885
+ )
886
+ );
887
+ }
888
+
889
+ function apply(ctx) {
890
+ installCss();
891
+ ctx.effect(function () {
892
+ return ctx.locale.register(NS, { zh: zh, en: en });
893
+ }, "cohub: settings dictionaries");
894
+
895
+ var scope = ctx.settingsScope.bind({ namespace: NS });
896
+ var remote = ctx.remote;
897
+
898
+ // alpha.2 后 settings.plugin.item slot 改成 keyed 类型(key = settings namespace);
899
+ // 按 .agents/notes/implemented/architecture/2026-08-12-plugin-owned-settings-surface.md,
900
+ // 用 key/locale 注册,不再声明 id/order,也不需要 slots.inject 第三参数。
901
+ ctx.slots.inject("settings.plugin.item", function () {
902
+ return ctx.slots.register({
903
+ name: "settings.plugin.item",
904
+ key: NS,
905
+ locale: NS,
906
+ inject: function () {
907
+ return { scope: scope, api: remote, t: ctx.locale.bind(NS), remote: remote };
908
+ }
909
+ }, CohubSettingsCard);
910
+ });
911
+ }
912
+
913
+ exports.apply = apply;
914
+ exports.inject = inject;
915
+ return module.exports;
916
+ }
917
+ });
918
+
919
+