larkin 0.4.28 → 0.5.0
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/CHANGELOG.md +11 -0
- package/README.md +5 -9
- package/artifacts/release/THIRD_PARTY_NOTICES.txt +751 -4425
- package/dist/app/agent-cli.mjs +14 -2
- package/dist/app/agent-config.mjs +26 -84
- package/dist/app/binary-entry.mjs +0 -20
- package/dist/app/cli.mjs +8 -14
- package/dist/app/internal-command.cjs +0 -2
- package/dist/app/internal-command.mjs +0 -2
- package/dist/app/local-control.mjs +16 -3
- package/dist/app/runtime-model-directory.mjs +2 -16
- package/dist/app/runtime-process.mjs +42 -6
- package/dist/app/setup.mjs +52 -57
- package/dist/dashboard/dashboard-config-controller.mjs +83 -24
- package/dist/dashboard/dashboard-view-model.mjs +4 -7
- package/dist/dashboard/web/assets/dashboard.js +1 -1
- package/dist/feishu/host-shell.cjs +68 -17
- package/dist/feishu/host-shell.mjs +69 -18
- package/dist/platform/config.cjs +201 -138
- package/dist/platform/config.mjs +199 -138
- package/dist/runtime/pi-artifact-provenance.mjs +3 -3
- package/dist/runtime/pi-bash-timeout-extension.mjs +4 -5
- package/dist/runtime/pi-compaction-recovery.cjs +9 -11
- package/dist/runtime/pi-compaction-recovery.mjs +8 -10
- package/dist/runtime/pi-extension-api.mjs +1 -0
- package/dist/runtime/pi-model-catalog.cjs +7 -8
- package/dist/runtime/pi-model-catalog.mjs +7 -8
- package/dist/runtime/pi-subagent-injection.mjs +17 -4
- package/dist/runtime/runtime-adapters.mjs +41 -38
- package/dist/runtime/runtime-host.cjs +197 -20
- package/dist/runtime/runtime-host.mjs +198 -21
- package/dist/runtime/runtime-model-catalog.cjs +1 -1
- package/dist/runtime/runtime-model-catalog.mjs +1 -1
- package/dist/runtime/runtime-readiness.cjs +112 -49
- package/dist/runtime/runtime-readiness.mjs +103 -49
- package/dist/runtime/user-runtime.cjs +7 -24
- package/dist/runtime/user-runtime.mjs +7 -23
- package/dist/setup/bot-register.mjs +15 -123
- package/dist/setup/setup-agent-choice.mjs +48 -74
- package/dist/setup/setup-bind.mjs +51 -151
- package/dist/setup/setup-binding.mjs +6 -9
- package/package.json +3 -2
- package/dist/app/pi-auth-cli.mjs +0 -67
- package/dist/platform/process-boundary-trace.cjs +0 -108
- package/dist/runtime/builtin-pi-assets.cjs +0 -117
- package/dist/runtime/builtin-pi-assets.mjs +0 -105
- package/dist/runtime/pi-artifact-provenance.cjs +0 -147
- package/dist/runtime/pi-distribution-label.cjs +0 -6
- package/dist/runtime/pi-distribution-label.mjs +0 -3
- package/dist/runtime/pi-inline-extensions.mjs +0 -78
- package/dist/runtime/pi-official-auth.mjs +0 -491
- package/dist/runtime/pi-profile-migration.cjs +0 -764
- package/dist/runtime/pi-profile-migration.mjs +0 -719
- package/dist/runtime/pi-provider-config.cjs +0 -331
- package/dist/runtime/pi-provider-config.mjs +0 -314
package/dist/app/setup.mjs
CHANGED
|
@@ -7,13 +7,11 @@ import path from "node:path";
|
|
|
7
7
|
import readline from "node:readline/promises";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
9
|
import * as larkinConfig from "../platform/config.mjs";
|
|
10
|
-
import {
|
|
11
|
-
import { fromUserRuntime, isUserRuntime } from "../runtime/user-runtime.mjs";
|
|
12
|
-
const PI_PROVIDER_IDS = PI_PROVIDER_PRESETS.map((p) => p.id).join(" | ") + " | custom";
|
|
10
|
+
import { isUserRuntime } from "../runtime/user-runtime.mjs";
|
|
13
11
|
import { acquireProcessLock, readProcessState } from "../platform/process-state.mjs";
|
|
14
12
|
import { requestAgentUpsert } from "./local-control.mjs";
|
|
15
13
|
import { openOwnedDashboardWhenReady } from "./setup-dashboard.mjs";
|
|
16
|
-
import { probeNativeRuntimeReadiness } from "../runtime/runtime-readiness.mjs";
|
|
14
|
+
import { probeNativeRuntimeReadiness, resolveRuntimeExecutable, runtimeInstallNextAction } from "../runtime/runtime-readiness.mjs";
|
|
17
15
|
import { internalCommandSpec, processCommandToken } from "./internal-command.mjs";
|
|
18
16
|
import { ensureOfficialLarkCliForSetup, formatOfficialLarkCliConsent, } from "./official-lark-cli.mjs";
|
|
19
17
|
const CFG_DIR = process.env.LARKIN_CONFIG_DIR || path.join(os.homedir(), ".larkin");
|
|
@@ -33,60 +31,54 @@ if (has("--start") && has("--no-start"))
|
|
|
33
31
|
if (has("--comment-subscription")) {
|
|
34
32
|
die("--comment-subscription 已移除:评论订阅默认 application(平台验证的应用级订阅),不需要该 flag");
|
|
35
33
|
}
|
|
34
|
+
const REMOVED_SETUP_FLAGS = ["--provider", "--api-key", "--base-url", "--pi-distribution", "--api-key-stdin", "--model-from-preset"];
|
|
35
|
+
if (REMOVED_SETUP_FLAGS.some((name) => has(name) || argv.some((arg) => arg.startsWith(`${name}=`)))) {
|
|
36
|
+
die("setup 不再接受 --provider/--api-key/--base-url;请安装并登录外部 pi、codex 或 claude");
|
|
37
|
+
}
|
|
36
38
|
// 默认应用级评论订阅:平台验证的应用订阅让该应用可见文档的全部评论进入 Agent Inbox。
|
|
37
39
|
const commentSubscription = "application";
|
|
38
|
-
const OPT = { runtime: flag("--runtime") || null, commentSubscription, start:
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
const OPT = { runtime: flag("--runtime") || null, commentSubscription, start: !has("--no-start"), help: has("--help") || has("-h"), nonInteractive: !Boolean(process.stdin.isTTY) };
|
|
41
|
+
const RUNTIME_ENUM = ["pi", "codex", "claude"];
|
|
42
|
+
function runtimeCommand(runtime, env = process.env) {
|
|
43
|
+
if (runtime === "pi")
|
|
44
|
+
return env.LARKIN_PI_COMMAND || "pi";
|
|
45
|
+
if (runtime === "codex")
|
|
46
|
+
return env.LARKIN_CODEX_COMMAND || "codex";
|
|
47
|
+
return env.LARKIN_CLAUDE_COMMAND || "claude";
|
|
48
|
+
}
|
|
41
49
|
function normalizeRuntime(value) {
|
|
42
|
-
|
|
43
|
-
|
|
50
|
+
if (!value)
|
|
51
|
+
return null;
|
|
52
|
+
if (value === "external-pi") {
|
|
44
53
|
console.error("external-pi 已改名为 pi");
|
|
45
|
-
return
|
|
54
|
+
return "pi";
|
|
46
55
|
}
|
|
47
|
-
if (
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
return fromUserRuntime(raw);
|
|
51
|
-
}
|
|
52
|
-
const normalizedRuntime = normalizeRuntime(OPT.runtime);
|
|
53
|
-
// 参数化路径:显式 --runtime、无 TTY(Agent 驱动)、或任何 provider 参数。
|
|
54
|
-
// 交互终端且未指定任何参数时,不传 --runtime 给 bot-register,由其交互选择流程接管。
|
|
55
|
-
const parameterized = Boolean(OPT.runtime) || OPT.nonInteractive
|
|
56
|
-
|| ["--provider", "--api-key", "--base-url"].some((name) => has(name));
|
|
57
|
-
// builtin-pi 前置校验:授权前就 fast-fail(避免用户白授权后才发现缺 key);--help 永远跳过
|
|
58
|
-
if (!OPT.help && parameterized && normalizedRuntime.distribution === "builtin") {
|
|
59
|
-
const p = flag("--provider");
|
|
60
|
-
const b = flag("--base-url");
|
|
61
|
-
const k = flag("--api-key");
|
|
62
|
-
if (!p && !b)
|
|
63
|
-
die(`builtin-pi 需要 --provider <id>(${PI_PROVIDER_IDS})或 --base-url;或 --runtime pi 用已有 pi`);
|
|
64
|
-
if (!k)
|
|
65
|
-
die("builtin-pi 需要 --api-key;或 --runtime pi 用已有登录");
|
|
56
|
+
if (isUserRuntime(value))
|
|
57
|
+
return value;
|
|
58
|
+
return die(`未知 runtime \`${value}\`;可选:${RUNTIME_ENUM.join(" | ")}`);
|
|
66
59
|
}
|
|
67
|
-
|
|
68
|
-
|
|
60
|
+
function assertRuntimeInstalled(runtime) {
|
|
61
|
+
if (resolveRuntimeExecutable(runtimeCommand(runtime), process.env))
|
|
62
|
+
return;
|
|
63
|
+
die(`${runtime} is not installed;${runtimeInstallNextAction(runtime)}`);
|
|
69
64
|
}
|
|
70
65
|
if (OPT.help) {
|
|
71
66
|
say(`larkin setup — Create or connect a Feishu (Lark) bot, then configure and attach its Agent
|
|
72
67
|
|
|
73
68
|
Usage:
|
|
74
|
-
larkin setup Select a bot in the browser and
|
|
75
|
-
larkin setup --
|
|
69
|
+
larkin setup Select a bot in the browser and choose an installed runtime
|
|
70
|
+
larkin setup --runtime pi Non-interactive setup for an externally installed runtime
|
|
76
71
|
|
|
77
72
|
Options:
|
|
78
|
-
--runtime <runtime> Agent runtime
|
|
79
|
-
--
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
--
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
--tenant feishu|lark 授权二维码之前选择品牌。默认 feishu(扫码 /page/launcher)。
|
|
88
|
-
Lark 用 --tenant lark:扫码 /page/cli,完成后凭证回传,
|
|
89
|
-
不要打开 /page/launcher。交互式未指定时会先询问。
|
|
73
|
+
--runtime <runtime> Required without a TTY. Agent runtime: pi | codex | claude
|
|
74
|
+
--model <id> Optional model ID; otherwise the runtime default is used.
|
|
75
|
+
Use \`larkin model\` after setup to inspect or switch.
|
|
76
|
+
--from-cli-profile <name> Optional: reuse an existing official lark-cli profile
|
|
77
|
+
(requires LARKIN_SETUP_APP_SECRET)
|
|
78
|
+
--tenant feishu|lark Choose the brand before the authorization QR. Default feishu
|
|
79
|
+
(scan /page/launcher). Lark uses --tenant lark: scan /page/cli,
|
|
80
|
+
then credentials return; do not open /page/launcher.
|
|
81
|
+
Interactive runs ask when omitted.
|
|
90
82
|
|
|
91
83
|
setup handles browser authorization, permission grants, credential storage, Agent configuration,
|
|
92
84
|
and target-only hot attach. Each Agent is identified by its bot App ID: selecting the same bot reuses
|
|
@@ -95,11 +87,18 @@ its existing Agent, memory, and state; creating a new bot creates a new Agent.
|
|
|
95
87
|
If larkin is running, only the selected Agent is added or updated. Otherwise setup starts the same
|
|
96
88
|
daemon + dashboard supervisor used by larkin start.
|
|
97
89
|
|
|
98
|
-
Interactive terminals
|
|
99
|
-
Non-interactive (Agent-driven) runs
|
|
100
|
-
|
|
90
|
+
Interactive terminals list pi, Codex, and Claude Code with installed / not installed status and
|
|
91
|
+
refuse a runtime that is not installed. Non-interactive (Agent-driven) runs require --runtime
|
|
92
|
+
and exit non-zero with the readiness message when that executable is missing.`);
|
|
101
93
|
process.exit(0);
|
|
102
94
|
}
|
|
95
|
+
if (OPT.nonInteractive && !OPT.runtime) {
|
|
96
|
+
die("非交互 setup 必须指定 --runtime pi|codex|claude");
|
|
97
|
+
}
|
|
98
|
+
const selectedRuntime = normalizeRuntime(OPT.runtime);
|
|
99
|
+
if (selectedRuntime)
|
|
100
|
+
assertRuntimeInstalled(selectedRuntime);
|
|
101
|
+
const parameterized = Boolean(OPT.runtime);
|
|
103
102
|
function runForeground(mode, args) {
|
|
104
103
|
return new Promise((resolve, reject) => {
|
|
105
104
|
const childSpec = internalCommandSpec(mode, args);
|
|
@@ -151,11 +150,8 @@ export async function main() {
|
|
|
151
150
|
fs.mkdirSync(CFG_DIR, { recursive: true, mode: 0o700 });
|
|
152
151
|
const resultFile = path.join(CFG_DIR, `.setup-result-${process.pid}.json`);
|
|
153
152
|
const registerArgs = ["--auto", "--result-file", resultFile];
|
|
154
|
-
if (parameterized)
|
|
155
|
-
registerArgs.push("--runtime",
|
|
156
|
-
if (normalizedRuntime.distribution)
|
|
157
|
-
registerArgs.push("--pi-distribution", normalizedRuntime.distribution);
|
|
158
|
-
}
|
|
153
|
+
if (parameterized && selectedRuntime)
|
|
154
|
+
registerArgs.push("--runtime", selectedRuntime);
|
|
159
155
|
registerArgs.push("--comment-subscription", OPT.commentSubscription);
|
|
160
156
|
if (has("--tenant")) {
|
|
161
157
|
const tenant = flag("--tenant");
|
|
@@ -163,7 +159,7 @@ export async function main() {
|
|
|
163
159
|
die("--tenant 只支持 feishu 或 lark");
|
|
164
160
|
registerArgs.push("--tenant", tenant === "lark" ? "lark" : "feishu");
|
|
165
161
|
}
|
|
166
|
-
for (const name of ["--
|
|
162
|
+
for (const name of ["--model", "--from-cli-profile"]) {
|
|
167
163
|
const value = flag(name);
|
|
168
164
|
if (value)
|
|
169
165
|
registerArgs.push(name, value);
|
|
@@ -193,12 +189,11 @@ export async function main() {
|
|
|
193
189
|
die(`Runtime ${configuredAgent.runtime} 不受支持`);
|
|
194
190
|
// 非交互(Agent 驱动)时仍跳过 probeNativeRuntimeReadiness:该探测保持 interactive-only。
|
|
195
191
|
// external-pi 绑定已在 setup-bind 内做非交互 Pi RPC catalog discovery(RPC over pipes 不需要 TTY);
|
|
196
|
-
// daemon attach 探测仍是权威校验。其余真实阻塞(缺 runtime 可执行文件 /
|
|
192
|
+
// daemon attach 探测仍是权威校验。其余真实阻塞(缺 runtime 可执行文件 / 缺登录 / 缺 lark-cli)一律 fast-fail。
|
|
197
193
|
if (!OPT.nonInteractive) {
|
|
198
194
|
const runtimeReadiness = await probeNativeRuntimeReadiness({ runtime: configuredAgent.runtime,
|
|
199
195
|
agentId: selectedAgentId, cwd: configuredAgent.workspaceDir,
|
|
200
|
-
env: { ...process.env, LARKIN_CONFIG_DIR: CFG_DIR
|
|
201
|
-
...(configuredAgent.piDistribution ? { LARKIN_PI_DISTRIBUTION: configuredAgent.piDistribution } : {}) } });
|
|
196
|
+
env: { ...process.env, LARKIN_CONFIG_DIR: CFG_DIR } });
|
|
202
197
|
if (runtimeReadiness.state !== "ready") {
|
|
203
198
|
die(`Runtime ${configuredAgent.runtime} ${runtimeReadiness.state}:${runtimeReadiness.reason || "prerequisite unavailable"};${runtimeReadiness.nextAction || "修复后重试"}`);
|
|
204
199
|
}
|
|
@@ -7,8 +7,8 @@ import { discoverClaudeModelCatalog } from "../runtime/claude-model-catalog.mjs"
|
|
|
7
7
|
import { discoverCodexModelCatalog } from "../runtime/codex-model-catalog.mjs";
|
|
8
8
|
import { discoverPiModelCatalog } from "../runtime/pi-model-catalog.mjs";
|
|
9
9
|
import { managedOfficialLarkCli } from "../app/agent-lark-cli-workspace.mjs";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
10
|
+
import { RUNTIME_OPTIONS, isUserRuntime } from "../runtime/user-runtime.mjs";
|
|
11
|
+
import { probeNativeRuntimeReadiness, RuntimePrerequisiteError } from "../runtime/runtime-readiness.mjs";
|
|
12
12
|
function pruneCache(cache, expired, maxEntries) {
|
|
13
13
|
for (const [key, value] of cache)
|
|
14
14
|
if (expired(value))
|
|
@@ -170,9 +170,38 @@ export function createPiModelDirectoryResolver(options = {}) {
|
|
|
170
170
|
const cache = new Map();
|
|
171
171
|
const failures = new Map();
|
|
172
172
|
const inFlight = new Map();
|
|
173
|
+
const generations = new Map();
|
|
174
|
+
// 单调序号:targeted 后再 global 时,in-flight 的 started 不能与新 generation 相等。
|
|
175
|
+
let seq = 0;
|
|
176
|
+
let baseline = 0;
|
|
177
|
+
const generationOf = (agentId) => Math.max(baseline, generations.get(agentId) ?? 0);
|
|
178
|
+
const dropPrefixed = (store, agentId) => {
|
|
179
|
+
if (!agentId) {
|
|
180
|
+
store.clear();
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const prefix = `${agentId}\u0000`;
|
|
184
|
+
for (const key of store.keys())
|
|
185
|
+
if (key.startsWith(prefix))
|
|
186
|
+
store.delete(key);
|
|
187
|
+
};
|
|
173
188
|
return {
|
|
189
|
+
invalidate(agentId) {
|
|
190
|
+
dropPrefixed(cache, agentId);
|
|
191
|
+
dropPrefixed(failures, agentId);
|
|
192
|
+
dropPrefixed(inFlight, agentId);
|
|
193
|
+
seq += 1;
|
|
194
|
+
if (!agentId) {
|
|
195
|
+
baseline = seq;
|
|
196
|
+
generations.clear();
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
generations.set(agentId, seq);
|
|
200
|
+
}
|
|
201
|
+
},
|
|
174
202
|
async resolve(input) {
|
|
175
|
-
const key = [input.agentId, input.cwd, input.agentDir, input.command ?? "", ...(input.commandArgs ?? [])].join("\u0000");
|
|
203
|
+
const key = [input.agentId, input.cwd, input.agentDir ?? "", input.command ?? "", ...(input.commandArgs ?? [])].join("\u0000");
|
|
204
|
+
const started = generationOf(input.agentId);
|
|
176
205
|
pruneCache(cache, (entry) => now() >= entry.expiresAt, 64);
|
|
177
206
|
pruneCache(failures, (entry) => now() >= entry.expiresAt, 64);
|
|
178
207
|
const cached = cache.get(key);
|
|
@@ -186,7 +215,7 @@ export function createPiModelDirectoryResolver(options = {}) {
|
|
|
186
215
|
try {
|
|
187
216
|
const catalog = await discover({
|
|
188
217
|
cwd: input.cwd,
|
|
189
|
-
agentDir: input.agentDir,
|
|
218
|
+
...(input.agentDir ? { agentDir: input.agentDir } : {}),
|
|
190
219
|
...(input.command ? { command: input.command } : {}),
|
|
191
220
|
...(input.commandArgs ? { commandArgs: input.commandArgs } : {}),
|
|
192
221
|
});
|
|
@@ -196,17 +225,23 @@ export function createPiModelDirectoryResolver(options = {}) {
|
|
|
196
225
|
id, label, ...(contextWindow ? { contextWindow } : {}), supportedReasoningEfforts, ...(defaultReasoningEffort ? { defaultReasoningEffort } : {}),
|
|
197
226
|
})),
|
|
198
227
|
];
|
|
199
|
-
|
|
200
|
-
|
|
228
|
+
if (generationOf(input.agentId) === started) {
|
|
229
|
+
failures.delete(key);
|
|
230
|
+
cache.set(key, { expiresAt: now() + ttlMs, value: models });
|
|
231
|
+
}
|
|
201
232
|
return models;
|
|
202
233
|
}
|
|
203
234
|
catch (error) {
|
|
204
|
-
|
|
235
|
+
if (generationOf(input.agentId) === started)
|
|
236
|
+
failures.set(key, { expiresAt: now() + negativeTtlMs });
|
|
205
237
|
throw error;
|
|
206
238
|
}
|
|
207
239
|
})();
|
|
208
240
|
inFlight.set(key, pending);
|
|
209
|
-
void pending.finally(() =>
|
|
241
|
+
void pending.finally(() => {
|
|
242
|
+
if (inFlight.get(key) === pending)
|
|
243
|
+
inFlight.delete(key);
|
|
244
|
+
}).catch(() => undefined);
|
|
210
245
|
}
|
|
211
246
|
return await pending;
|
|
212
247
|
},
|
|
@@ -383,19 +418,18 @@ function dashboardMutation(value) {
|
|
|
383
418
|
return { kind: operation, agentId, model: String(value.model || "") };
|
|
384
419
|
return { kind: "set-agent-effort", agentId, effort: value.effort === null || value.effort === "default" ? null : String(value.effort || "") };
|
|
385
420
|
}
|
|
386
|
-
export function createDashboardConfigController({ csrfCapability, env = process.env, requestUpsert = requestAgentUpsert, chatDirectoryResolver = createChatDirectoryResolver(), claudeModelDirectoryResolver = createClaudeModelDirectoryResolver(), codexModelDirectoryResolver = createCodexModelDirectoryResolver(), piModelDirectoryResolver = createPiModelDirectoryResolver(), }) {
|
|
387
|
-
const resolvePiModelDirectory = async (agentId
|
|
388
|
-
const { config
|
|
421
|
+
export function createDashboardConfigController({ csrfCapability, env = process.env, requestUpsert = requestAgentUpsert, chatDirectoryResolver = createChatDirectoryResolver(), claudeModelDirectoryResolver = createClaudeModelDirectoryResolver(), codexModelDirectoryResolver = createCodexModelDirectoryResolver(), piModelDirectoryResolver = createPiModelDirectoryResolver(), probeRuntimeReadiness = probeNativeRuntimeReadiness, }) {
|
|
422
|
+
const resolvePiModelDirectory = async (agentId) => {
|
|
423
|
+
const { config } = loadConfig(env);
|
|
389
424
|
const agent = config.agents[agentId];
|
|
390
425
|
if (!agent)
|
|
391
426
|
throw new Error("unknown agent");
|
|
392
|
-
|
|
427
|
+
// 外部 `pi --mode rpc` 使用用户自己的 Pi home,不再注入 Larkin 持有的 agentDir。
|
|
393
428
|
return await piModelDirectoryResolver.resolve({
|
|
394
429
|
agentId,
|
|
395
430
|
cwd: agent.workspaceDir,
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
commandArgs: catalogCommand.commandArgs,
|
|
431
|
+
command: env.LARKIN_PI_COMMAND || process.env.LARKIN_PI_COMMAND || "pi",
|
|
432
|
+
commandArgs: [],
|
|
399
433
|
});
|
|
400
434
|
};
|
|
401
435
|
const resolveModelDirectory = async (runtime, agentId) => {
|
|
@@ -403,8 +437,8 @@ export function createDashboardConfigController({ csrfCapability, env = process.
|
|
|
403
437
|
const agent = config.agents[agentId];
|
|
404
438
|
if (!agent)
|
|
405
439
|
throw new Error("unknown agent");
|
|
406
|
-
if (runtime === "pi"
|
|
407
|
-
return await resolvePiModelDirectory(agentId
|
|
440
|
+
if (runtime === "pi")
|
|
441
|
+
return await resolvePiModelDirectory(agentId);
|
|
408
442
|
if (runtime === "codex")
|
|
409
443
|
return await codexModelDirectoryResolver.resolve({ agentId, cwd: agent.workspaceDir, env });
|
|
410
444
|
if (runtime === "claude")
|
|
@@ -414,6 +448,24 @@ export function createDashboardConfigController({ csrfCapability, env = process.
|
|
|
414
448
|
throw new Error("unknown runtime");
|
|
415
449
|
return authored;
|
|
416
450
|
};
|
|
451
|
+
const assertRuntimeSwitchReady = async (mutation) => {
|
|
452
|
+
if (mutation.kind !== "set-agent-runtime")
|
|
453
|
+
return;
|
|
454
|
+
if (!isUserRuntime(mutation.runtime))
|
|
455
|
+
throw new Error(`未知 runtime:${mutation.runtime}`);
|
|
456
|
+
const { config } = loadConfig(env);
|
|
457
|
+
const agent = config.agents[mutation.agentId];
|
|
458
|
+
if (!agent)
|
|
459
|
+
throw new Error("unknown agent");
|
|
460
|
+
const readiness = await probeRuntimeReadiness({
|
|
461
|
+
runtime: mutation.runtime,
|
|
462
|
+
cwd: agent.workspaceDir,
|
|
463
|
+
env,
|
|
464
|
+
agentId: mutation.agentId,
|
|
465
|
+
});
|
|
466
|
+
if (readiness.state === "missing")
|
|
467
|
+
throw new RuntimePrerequisiteError(readiness);
|
|
468
|
+
};
|
|
417
469
|
const assertDirectoryMutation = async (mutation) => {
|
|
418
470
|
if (mutation.kind !== "set-agent-runtime" && mutation.kind !== "set-agent-model" && mutation.kind !== "set-agent-effort")
|
|
419
471
|
return;
|
|
@@ -421,9 +473,7 @@ export function createDashboardConfigController({ csrfCapability, env = process.
|
|
|
421
473
|
const agent = config.agents[mutation.agentId];
|
|
422
474
|
if (!agent)
|
|
423
475
|
throw new Error("unknown agent");
|
|
424
|
-
const runtime = mutation.kind === "set-agent-runtime"
|
|
425
|
-
? mutation.runtime
|
|
426
|
-
: toUserRuntime(agent.runtime, agent.piDistribution);
|
|
476
|
+
const runtime = mutation.kind === "set-agent-runtime" ? mutation.runtime : agent.runtime;
|
|
427
477
|
const model = mutation.kind === "set-agent-runtime" ? mutation.model || "default"
|
|
428
478
|
: mutation.kind === "set-agent-model" ? mutation.model : agent.model;
|
|
429
479
|
if (mutation.kind === "set-agent-effort" && mutation.effort === null)
|
|
@@ -454,11 +504,11 @@ export function createDashboardConfigController({ csrfCapability, env = process.
|
|
|
454
504
|
}
|
|
455
505
|
return true;
|
|
456
506
|
}
|
|
457
|
-
if (
|
|
507
|
+
if (requestUrl.pathname === "/api/models/pi" && req.method === "GET") {
|
|
458
508
|
try {
|
|
459
509
|
assertPrivateReadRequest(req, csrfCapability);
|
|
460
510
|
const agentId = requestUrl.searchParams.get("agent") || "";
|
|
461
|
-
const models = await resolvePiModelDirectory(agentId
|
|
511
|
+
const models = await resolvePiModelDirectory(agentId);
|
|
462
512
|
json(res, 200, { models });
|
|
463
513
|
}
|
|
464
514
|
catch (error) {
|
|
@@ -502,12 +552,21 @@ export function createDashboardConfigController({ csrfCapability, env = process.
|
|
|
502
552
|
try {
|
|
503
553
|
assertWriteRequest(req, csrfCapability);
|
|
504
554
|
const mutation = dashboardMutation(await boundedJson(req));
|
|
555
|
+
await assertRuntimeSwitchReady(mutation);
|
|
505
556
|
await assertDirectoryMutation(mutation);
|
|
506
557
|
const result = mutateConfig(env, mutation, { kind: "user" });
|
|
507
558
|
json(res, 200, { ok: true, revision: result.revision, persisted: true, applyState: result.applyState, changedScope: result.changedScope });
|
|
508
559
|
}
|
|
509
|
-
catch {
|
|
510
|
-
|
|
560
|
+
catch (error) {
|
|
561
|
+
if (error instanceof RuntimePrerequisiteError) {
|
|
562
|
+
json(res, 400, { error: error.message, readiness: error.readiness });
|
|
563
|
+
}
|
|
564
|
+
else if (error instanceof Error && error.message.startsWith("未知 runtime")) {
|
|
565
|
+
json(res, 400, { error: error.message });
|
|
566
|
+
}
|
|
567
|
+
else {
|
|
568
|
+
json(res, 400, { error: "configuration update rejected" });
|
|
569
|
+
}
|
|
511
570
|
}
|
|
512
571
|
return true;
|
|
513
572
|
}
|
|
@@ -12,7 +12,6 @@ import { isAllowedDashboardAvatarUrl } from "./dashboard-avatar.mjs";
|
|
|
12
12
|
import { collectWorkspaceEntry as collectTypedWorkspaceEntry } from "./dashboard-workspace.mjs";
|
|
13
13
|
import { buildFingerprint, packageVersion } from "../platform/build-info.mjs";
|
|
14
14
|
import * as larkinConfig from "../platform/config.mjs";
|
|
15
|
-
import { ownedPiCatalogAgentDir, piCatalogCommandSpec } from "../runtime/pi-provider-config.mjs";
|
|
16
15
|
import { toUserRuntime } from "../runtime/user-runtime.mjs";
|
|
17
16
|
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
18
17
|
const ROOT = path.resolve(HERE, "../..");
|
|
@@ -444,13 +443,11 @@ async function collectAgentStatus(a, configDir, daemonStartedAt, piModelResolver
|
|
|
444
443
|
let piCatalog = [];
|
|
445
444
|
if (a.runtime === "pi" && piModelResolver) {
|
|
446
445
|
try {
|
|
447
|
-
const catalogCommand = piCatalogCommandSpec(a.piDistribution, process.env);
|
|
448
446
|
piCatalog = await piModelResolver.resolve({
|
|
449
447
|
agentId: a.agentId,
|
|
450
448
|
cwd: a.workspaceDir,
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
commandArgs: catalogCommand.commandArgs,
|
|
449
|
+
command: process.env.LARKIN_PI_COMMAND || "pi",
|
|
450
|
+
commandArgs: [],
|
|
454
451
|
});
|
|
455
452
|
}
|
|
456
453
|
catch { /* unknown or unavailable catalog keeps the explicit turns fallback */ }
|
|
@@ -503,7 +500,7 @@ async function collectAgentStatus(a, configDir, daemonStartedAt, piModelResolver
|
|
|
503
500
|
agentId: a.agentId,
|
|
504
501
|
name: a.name,
|
|
505
502
|
displayName: (botIdentity && botIdentity.name) || a.name,
|
|
506
|
-
runtime: toUserRuntime(a.runtime
|
|
503
|
+
runtime: toUserRuntime(a.runtime),
|
|
507
504
|
model: status.session?.runtime === a.runtime && status.session?.model ? String(status.session.model) : a.model,
|
|
508
505
|
effort: status.session?.runtime === a.runtime && status.session?.reasoningEffort ? String(status.session.reasoningEffort) : a.effort || null,
|
|
509
506
|
runtimeReadiness,
|
|
@@ -527,7 +524,7 @@ async function collectAgentStatus(a, configDir, daemonStartedAt, piModelResolver
|
|
|
527
524
|
sessions: agentState.sessions || {},
|
|
528
525
|
session: sessionId ? {
|
|
529
526
|
id: sessionId,
|
|
530
|
-
runtime: toUserRuntime(a.runtime
|
|
527
|
+
runtime: toUserRuntime(a.runtime),
|
|
531
528
|
startedAt: usage.startedAt || (status.session?.id === sessionId ? status.session.startedAt : null) || null,
|
|
532
529
|
ageSec: ageSec(usage.startedAt || (status.session?.id === sessionId ? status.session.startedAt : null)),
|
|
533
530
|
lastTurnAt: status.session?.lastTurnAt || null,
|
|
@@ -46,4 +46,4 @@ Error generating stack: `+e.message+`
|
|
|
46
46
|
`},or=function(){var e=parseInt(document.body.getAttribute(`data-scroll-locked`)||`0`,10);return isFinite(e)?e:0},sr=function(){C.useEffect(function(){return document.body.setAttribute(ir,(or()+1).toString()),function(){var e=or()-1;e<=0?document.body.removeAttribute(ir):document.body.setAttribute(ir,e.toString())}},[])},cr=function(e){var t=e.noRelative,n=e.noImportant,r=e.gapMode,i=r===void 0?`margin`:r;sr();var a=C.useMemo(function(){return nr(i)},[i]);return C.createElement(rr,{styles:ar(a,!t,i,n?``:`!important`)})},lr=!1;if(typeof window<`u`)try{var ur=Object.defineProperty({},"passive",{get:function(){return lr=!0,!0}});window.addEventListener(`test`,ur,ur),window.removeEventListener(`test`,ur,ur)}catch{lr=!1}var dr=lr?{passive:!1}:!1,fr=function(e){return e.tagName===`TEXTAREA`},pr=function(e,t){if(!(e instanceof Element))return!1;var n=window.getComputedStyle(e);return n[t]!==`hidden`&&!(n.overflowY===n.overflowX&&!fr(e)&&n[t]===`visible`)},mr=function(e){return pr(e,`overflowY`)},hr=function(e){return pr(e,`overflowX`)},gr=function(e,t){var n=t.ownerDocument,r=t;do{if(typeof ShadowRoot<`u`&&r instanceof ShadowRoot&&(r=r.host),yr(e,r)){var i=br(e,r);if(i[1]>i[2])return!0}r=r.parentNode}while(r&&r!==n.body);return!1},_r=function(e){return[e.scrollTop,e.scrollHeight,e.clientHeight]},vr=function(e){return[e.scrollLeft,e.scrollWidth,e.clientWidth]},yr=function(e,t){return e===`v`?mr(t):hr(t)},br=function(e,t){return e===`v`?_r(t):vr(t)},xr=function(e,t){return e===`h`&&t===`rtl`?-1:1},Sr=function(e,t,n,r,i){var a=xr(e,window.getComputedStyle(t).direction),o=a*r,s=n.target,c=t.contains(s),l=!1,u=o>0,d=0,f=0;do{if(!s)break;var p=br(e,s),m=p[0],h=p[1]-p[2]-a*m;(m||h)&&yr(e,s)&&(d+=h,f+=m);var g=s.parentNode;s=g&&g.nodeType===Node.DOCUMENT_FRAGMENT_NODE?g.host:g}while(!c&&s!==document.body||c&&(t.contains(s)||t===s));return(u&&(i&&Math.abs(d)<1||!i&&o>d)||!u&&(i&&Math.abs(f)<1||!i&&-o>f))&&(l=!0),l},Cr=function(e){return`changedTouches`in e?[e.changedTouches[0].clientX,e.changedTouches[0].clientY]:[0,0]},wr=function(e){return[e.deltaX,e.deltaY]},Tr=function(e){return e&&`current`in e?e.current:e},Er=function(e,t){return e[0]===t[0]&&e[1]===t[1]},Dr=function(e){return`
|
|
47
47
|
.block-interactivity-${e} {pointer-events: none;}
|
|
48
48
|
.allow-interactivity-${e} {pointer-events: all;}
|
|
49
|
-
`},Or=0,kr=[];function Ar(e){var t=C.useRef([]),n=C.useRef([0,0]),r=C.useRef(),i=C.useState(Or++)[0],a=C.useState(Qn)[0],o=C.useRef(e);C.useEffect(function(){o.current=e},[e]),C.useEffect(function(){if(e.inert){document.body.classList.add(`block-interactivity-${i}`);var t=Dn([e.lockRef.current],(e.shards||[]).map(Tr),!0).filter(Boolean);return t.forEach(function(e){return e.classList.add(`allow-interactivity-${i}`)}),function(){document.body.classList.remove(`block-interactivity-${i}`),t.forEach(function(e){return e.classList.remove(`allow-interactivity-${i}`)})}}},[e.inert,e.lockRef.current,e.shards]);var s=C.useCallback(function(e,t){if(`touches`in e&&e.touches.length===2||e.type===`wheel`&&e.ctrlKey)return!o.current.allowPinchZoom;var i=Cr(e),a=n.current,s=`deltaX`in e?e.deltaX:a[0]-i[0],c=`deltaY`in e?e.deltaY:a[1]-i[1],l,u=e.target,d=Math.abs(s)>Math.abs(c)?`h`:`v`;if(`touches`in e&&d===`h`&&u.type===`range`)return!1;var f=window.getSelection(),p=f&&f.anchorNode;if(p&&(p===u||p.contains(u)))return!1;var m=gr(d,u);if(!m)return!0;if(m?l=d:(l=d===`v`?`h`:`v`,m=gr(d,u)),!m)return!1;if(!r.current&&`changedTouches`in e&&(s||c)&&(r.current=l),!l)return!0;var h=r.current||l;return Sr(h,t,e,h===`h`?s:c,!0)},[]),c=C.useCallback(function(e){var n=e;if(!(!kr.length||kr[kr.length-1]!==a)){var r=`deltaY`in n?wr(n):Cr(n),i=t.current.filter(function(e){return e.name===n.type&&(e.target===n.target||n.target===e.shadowParent)&&Er(e.delta,r)})[0];if(i&&i.should){n.cancelable&&n.preventDefault();return}if(!i){var c=(o.current.shards||[]).map(Tr).filter(Boolean).filter(function(e){return e.contains(n.target)});(c.length>0?s(n,c[0]):!o.current.noIsolation)&&n.cancelable&&n.preventDefault()}}},[]),l=C.useCallback(function(e,n,r,i){var a={name:e,delta:n,target:r,should:i,shadowParent:jr(r)};t.current.push(a),setTimeout(function(){t.current=t.current.filter(function(e){return e!==a})},1)},[]),u=C.useCallback(function(e){n.current=Cr(e),r.current=void 0},[]),d=C.useCallback(function(t){l(t.type,wr(t),t.target,s(t,e.lockRef.current))},[]),f=C.useCallback(function(t){l(t.type,Cr(t),t.target,s(t,e.lockRef.current))},[]);C.useEffect(function(){return kr.push(a),e.setCallbacks({onScrollCapture:d,onWheelCapture:d,onTouchMoveCapture:f}),document.addEventListener(`wheel`,c,dr),document.addEventListener(`touchmove`,c,dr),document.addEventListener(`touchstart`,u,dr),function(){kr=kr.filter(function(e){return e!==a}),document.removeEventListener(`wheel`,c,dr),document.removeEventListener(`touchmove`,c,dr),document.removeEventListener(`touchstart`,u,dr)}},[]);var p=e.removeScrollBar,m=e.inert;return C.createElement(C.Fragment,null,m?C.createElement(a,{styles:Dr(i)}):null,p?C.createElement(cr,{noRelative:e.noRelative,gapMode:e.gapMode}):null)}function jr(e){for(var t=null;e!==null;)e instanceof ShadowRoot&&(t=e.host,e=e.host),e=e.parentNode;return t}var Mr=Vn(Hn,Ar),Nr=C.forwardRef(function(e,t){return C.createElement(Wn,Tn({},e,{ref:t,sideCar:Mr}))});Nr.classNames=Wn.classNames;var Pr=function(e){return typeof document>`u`?null:(Array.isArray(e)?e[0]:e).ownerDocument.body},Fr=new WeakMap,Ir=new WeakMap,Lr={},Rr=0,zr=function(e){return e&&(e.host||zr(e.parentNode))},Br=function(e,t){return t.map(function(t){if(e.contains(t))return t;var n=zr(t);return n&&e.contains(n)?n:(console.error(`aria-hidden`,t,`in not contained inside`,e,`. Doing nothing`),null)}).filter(function(e){return!!e})},Vr=function(e,t,n,r){var i=Br(t,Array.isArray(e)?e:[e]);Lr[n]||(Lr[n]=new WeakMap);var a=Lr[n],o=[],s=new Set,c=new Set(i),l=function(e){!e||s.has(e)||(s.add(e),l(e.parentNode))};i.forEach(l);var u=function(e){!e||c.has(e)||Array.prototype.forEach.call(e.children,function(e){if(s.has(e))u(e);else try{var t=e.getAttribute(r),i=t!==null&&t!==`false`,c=(Fr.get(e)||0)+1,l=(a.get(e)||0)+1;Fr.set(e,c),a.set(e,l),o.push(e),c===1&&i&&Ir.set(e,!0),l===1&&e.setAttribute(n,`true`),i||e.setAttribute(r,`true`)}catch(t){console.error(`aria-hidden: cannot operate on `,e,t)}})};return u(t),s.clear(),Rr++,function(){o.forEach(function(e){var t=Fr.get(e)-1,i=a.get(e)-1;Fr.set(e,t),a.set(e,i),t||(Ir.has(e)||e.removeAttribute(r),Ir.delete(e)),i||e.removeAttribute(n)}),Rr--,Rr||(Fr=new WeakMap,Fr=new WeakMap,Ir=new WeakMap,Lr={})}},Hr=function(e,t,n){n===void 0&&(n=`data-aria-hidden`);var r=Array.from(Array.isArray(e)?e:[e]),i=t||Pr(e);return i?(r.push.apply(r,Array.from(i.querySelectorAll(`[aria-live], script`))),Vr(r,i,n,`aria-hidden`)):function(){return null}},Ur=Object.defineProperty,Wr=(e,t)=>Ur(e,`name`,{value:t,configurable:!0}),Gr=`Dialog`,[Kr,qr]=Be(Gr),[Jr,Yr]=Kr(Gr),Xr=Wr(e=>{let{__scopeDialog:t,children:n,open:r,defaultOpen:i,onOpenChange:a,modal:o=!0}=e,s=C.useRef(null),c=C.useRef(null),[l,u]=nt({prop:r,defaultProp:i??!1,onChange:a,caller:Gr}),[d,f]=C.useState(0),[p,m]=C.useState(0);return(0,A.jsx)(Jr,{scope:t,triggerRef:s,contentRef:c,contentId:qe(),titleId:qe(),descriptionId:qe(),titlePresent:d>0,descriptionPresent:p>0,setTitleCount:f,setDescriptionCount:m,open:l,onOpenChange:u,onOpenToggle:C.useCallback(()=>u(e=>!e),[u]),modal:o,children:n})},`Dialog`),Zr=`DialogPortal`,[Qr,$r]=Kr(Zr,{forceMount:void 0}),ei=Wr(e=>{let{__scopeDialog:t,forceMount:n,children:r,container:i}=e,a=Yr(Zr,t);return(0,A.jsx)(Qr,{scope:t,forceMount:n,children:C.Children.map(r,e=>(0,A.jsx)(fn,{present:n||a.open,children:(0,A.jsx)(cn,{asChild:!0,container:i,children:e})}))})},`DialogPortal`),ti=`DialogOverlay`,ni=C.forwardRef(Wr(function(e,t){let n=$r(ti,e.__scopeDialog),{forceMount:r=n.forceMount,...i}=e,a=Yr(ti,e.__scopeDialog);return a.modal?(0,A.jsx)(fn,{present:r||a.open,children:(0,A.jsx)(ii,{...i,ref:t})}):null},`DialogOverlay`)),ri=ut(`DialogOverlay.RemoveScroll`),ii=C.forwardRef(Wr(function(e,t){let{__scopeDialog:n,...r}=e,i=Yr(ti,n),a=Fe(t,Lt());return(0,A.jsx)(Nr,{as:ri,allowPinchZoom:!0,shards:[i.contentRef],children:(0,A.jsx)(Tt.div,{"data-state":gi(i.open),...r,ref:a,style:{pointerEvents:`auto`,...r.style}})})},`DialogOverlayImpl`)),ai=`DialogContent`,oi=C.forwardRef(Wr(function(e,t){let n=$r(ai,e.__scopeDialog),{forceMount:r=n.forceMount,...i}=e,a=Yr(ai,e.__scopeDialog);return(0,A.jsx)(fn,{present:r||a.open,children:a.modal?(0,A.jsx)(si,{...i,ref:t}):(0,A.jsx)(ci,{...i,ref:t})})},`DialogContent`)),si=C.forwardRef(Wr(function(e,t){let n=Yr(ai,e.__scopeDialog),r=C.useRef(null),i=Fe(t,n.contentRef,r);return C.useEffect(()=>{let e=r.current;if(e)return Hr(e)},[]),(0,A.jsx)(li,{...e,ref:i,trapFocus:n.open,disableOutsidePointerEvents:n.open,onCloseAutoFocus:Ee(e.onCloseAutoFocus,e=>{e.preventDefault(),n.triggerRef.current?.focus()}),onPointerDownOutside:Ee(e.onPointerDownOutside,e=>{let t=e.detail.originalEvent,n=t.button===0&&t.ctrlKey===!0;(t.button===2||n)&&e.preventDefault()}),onFocusOutside:Ee(e.onFocusOutside,e=>e.preventDefault())})},`DialogContentModal`)),ci=C.forwardRef(Wr(function(e,t){let n=Yr(ai,e.__scopeDialog),r=C.useRef(!1),i=C.useRef(!1);return(0,A.jsx)(li,{...e,ref:t,trapFocus:!1,disableOutsidePointerEvents:!1,onCloseAutoFocus:t=>{e.onCloseAutoFocus?.(t),t.defaultPrevented||(r.current||n.triggerRef.current?.focus(),t.preventDefault()),r.current=!1,i.current=!1},onInteractOutside:t=>{e.onInteractOutside?.(t),t.defaultPrevented||(r.current=!0,t.detail.originalEvent.type===`pointerdown`&&(i.current=!0));let a=t.target;n.triggerRef.current?.contains(a)&&t.preventDefault(),t.detail.originalEvent.type===`focusin`&&i.current&&t.preventDefault()}})},`DialogContentNonModal`)),li=C.forwardRef(Wr(function(e,t){let{__scopeDialog:n,trapFocus:r,onOpenAutoFocus:i,onCloseAutoFocus:a,...o}=e,s=Yr(ai,n);return Cn(),(0,A.jsx)(A.Fragment,{children:(0,A.jsx)(Jt,{asChild:!0,loop:!0,trapped:r,onMountAutoFocus:i,onUnmountAutoFocus:a,children:(0,A.jsx)(It,{role:`dialog`,id:s.contentId,"aria-describedby":s.descriptionPresent?s.descriptionId:void 0,"aria-labelledby":s.titlePresent?s.titleId:void 0,"data-state":gi(s.open),...o,ref:t,deferPointerDownOutside:!0,onDismiss:()=>s.onOpenChange(!1)})})})},`DialogContentImpl`)),ui=`DialogTitle`,di=C.forwardRef(Wr(function(e,t){let{__scopeDialog:n,...r}=e,i=Yr(ui,n),{setTitleCount:a}=i;return He(()=>(a(e=>e+1),()=>a(e=>e-1)),[a]),(0,A.jsx)(Tt.h2,{id:i.titleId,...r,ref:t})},`DialogTitle`)),fi=`DialogDescription`,pi=C.forwardRef(Wr(function(e,t){let{__scopeDialog:n,...r}=e,i=Yr(fi,n),{setDescriptionCount:a}=i;return He(()=>(a(e=>e+1),()=>a(e=>e-1)),[a]),(0,A.jsx)(Tt.p,{id:i.descriptionId,...r,ref:t})},`DialogDescription`)),mi=`DialogClose`,hi=C.forwardRef(Wr(function(e,t){let{__scopeDialog:n,...r}=e,i=Yr(mi,n);return(0,A.jsx)(Tt.button,{type:`button`,...r,ref:t,onClick:Ee(e.onClick,()=>i.onOpenChange(!1))})},`DialogClose`));function gi(e){return e?`open`:`closed`}Wr(gi,`getState`);function _i(...e){return e.filter(Boolean).join(` `)}function vi({className:e,...t}){return(0,A.jsx)(`button`,{className:_i(`ui-button`,e),...t})}function yi({className:e,...t}){return(0,A.jsx)(`span`,{className:_i(`ui-badge`,e),...t})}function bi({open:e,onOpenChange:t,title:n,description:r,children:i}){return(0,A.jsx)(Xr,{open:e,onOpenChange:t,children:(0,A.jsxs)(ei,{children:[(0,A.jsx)(ni,{className:`sheet-overlay`}),(0,A.jsxs)(oi,{className:`sheet-content`,children:[(0,A.jsxs)(`div`,{className:`sheet-head`,children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(di,{children:n}),r?(0,A.jsx)(pi,{children:r}):null]}),(0,A.jsx)(hi,{asChild:!0,children:(0,A.jsx)(vi,{"aria-label":`关闭面板`,className:`icon-button`,children:(0,A.jsx)(me,{size:18})})})]}),i]})]})})}function xi({title:e,detail:t}){return(0,A.jsxs)(`div`,{className:`empty-state`,children:[(0,A.jsx)(`strong`,{children:e}),t?(0,A.jsx)(`p`,{children:t}):null]})}var Si=[`codex`,`claude`,`pi`,`builtin-pi`],Ci={overview:`概览`,conversation:`对话`,configuration:`配置`,reminders:`提醒`,workspace:`工作区`,logs:`日志`},wi=window.__LARKIN_DASHBOARD__||{packageVersion:`dev`,dashboardVersion:`dev`,buildFingerprint:``,csrfCapability:``},Ti=class extends Error{body;constructor(e,t){super(e),this.body=t}};async function Ei(e,t={}){let n=await fetch(e,{cache:`no-store`,...t});if(!n.ok){let e=await n.json().catch(()=>({}));throw new Ti(e.error||`HTTP ${n.status}`,e)}return n.json()}function Di(e,t){if(!(e instanceof Ti)||!e.body.readiness)return e instanceof Error?e.message:t;let n=e.body.readiness;return[n.reason||e.message,n.nextAction?`下一步:${n.nextAction}`:null].filter(Boolean).join(`;`)}async function Oi(e){return Ei(`/api/config`,{method:`PATCH`,headers:{"Content-Type":`application/json`,"X-Larkin-CSRF":wi.csrfCapability},body:JSON.stringify(e)})}function ki(e,t={}){return Ei(e,{...t,headers:{...t.headers,"X-Larkin-CSRF":wi.csrfCapability}})}function Ai(e){return e==null||!Number.isFinite(e)?`暂无`:e<60?`${e}s 前`:e<3600?`${Math.floor(e/60)}m 前`:e<86400?`${Math.floor(e/3600)}h 前`:`${Math.floor(e/86400)}d 前`}function ji(e){let t=new Date(String(e||``));return Number.isFinite(t.getTime())?t.toLocaleString(`zh-CN`,{hour12:!1}):`未知时间`}function Mi(e){return Number.isFinite(Number(e))?Number(e).toLocaleString(`en-US`):`—`}function Ni(e){return e.issue?`异常`:e.lastActivity?.state?String(e.lastActivity.state):e.running?`空闲`:`离线`}function Pi(){let[e,t]=(0,C.useState)(null),[n,r]=(0,C.useState)(null),[i,a]=(0,C.useState)(!0),[o,s]=(0,C.useState)(!1),c=(0,C.useRef)(Se()),l=(0,C.useRef)(null),u=(0,C.useRef)(null),d=(0,C.useCallback)(async()=>{u.current?.abort();let e=new AbortController;u.current=e;let n=c.current.issue();try{let i=await Ei(`/api/status`,{signal:e.signal});if(!c.current.accepts(n))return;if(wi.buildFingerprint&&i.buildFingerprint&&i.buildFingerprint!==wi.buildFingerprint){window.location.reload();return}t(i),r(null),s(!1)}catch(t){if(e.signal.aborted||!c.current.accepts(n))return;r(t instanceof Error?t.message:String(t)),s(!0)}finally{c.current.accepts(n)&&a(!1)}},[]);return(0,C.useEffect)(()=>{let e=!0,t=async()=>{await d(),e&&(l.current=window.setTimeout(t,3e3))};return t(),()=>{e=!1,l.current!==null&&window.clearTimeout(l.current),u.current?.abort()}},[d]),{data:e,error:n,loading:i,stale:o,retry:d}}function Fi({agent:e}){let t=(e.displayName||e.name||e.agentId).slice(0,2).toUpperCase(),[n,r]=(0,C.useState)(!1);(0,C.useEffect)(()=>r(!1),[e.agentId,e.bot?.hasAvatar]);let i=e.bot?.hasAvatar&&!n;return(0,A.jsx)(`span`,{className:`agent-avatar`,"aria-hidden":`true`,children:i?(0,A.jsx)(`img`,{src:`/api/avatar/${encodeURIComponent(e.agentId)}`,alt:``,onError:()=>r(!0)}):t})}function Ii({agents:e,selectedId:t,onSelect:n,compact:r=!1}){let[i,a]=(0,C.useState)(``),o=(0,C.useMemo)(()=>be(e,i),[e,i]),s=(0,C.useRef)([]),c=(e,t)=>{if(!o.length)return;let n=t===0?e:(e+t+o.length)%o.length;s.current[n]?.focus()};return(0,A.jsxs)(`div`,{className:_i(`sidebar-inner`,r&&`compact-sidebar`),children:[(0,A.jsxs)(`label`,{className:`agent-search`,children:[(0,A.jsx)(de,{size:15,"aria-hidden":`true`}),(0,A.jsx)(`span`,{className:`sr-only`,children:`搜索 Agent`}),(0,A.jsx)(`input`,{value:i,onChange:e=>a(e.target.value),placeholder:`搜索 Agent…`})]}),(0,A.jsxs)(`div`,{className:`agent-list`,role:`listbox`,"aria-label":`Agent 列表`,children:[o.map((e,r)=>(0,A.jsxs)(`button`,{ref:e=>{s.current[r]=e},type:`button`,role:`option`,"aria-selected":e.agentId===t,className:_i(`agent-list-item`,e.agentId===t&&`selected`),onClick:()=>n(e.agentId),onKeyDown:e=>{e.key===`ArrowDown`&&(e.preventDefault(),c(r,1)),e.key===`ArrowUp`&&(e.preventDefault(),c(r,-1)),e.key===`Home`&&(e.preventDefault(),c(0,0)),e.key===`End`&&(e.preventDefault(),c(o.length-1,0))},children:[(0,A.jsx)(Fi,{agent:e}),(0,A.jsxs)(`span`,{className:`agent-list-copy`,children:[(0,A.jsx)(`strong`,{children:e.displayName||e.name}),(0,A.jsxs)(`small`,{children:[e.runtime,` · `,e.model,e.runtimeReadiness?` · ${e.runtimeReadiness.state}`:``]}),(0,A.jsxs)(`span`,{className:`status-line`,children:[(0,A.jsx)(ie,{size:10}),` `,e.connection.state,` · `,Ni(e)]})]}),e.issue?(0,A.jsx)(k,{size:15,className:`danger`,"aria-label":`异常`}):(0,A.jsx)(re,{size:15,"aria-hidden":`true`})]},e.agentId)),o.length?null:(0,A.jsx)(xi,{title:`没有匹配的 Agent`,detail:`可按名称或 App ID 搜索`})]})]})}function Li({open:e,onOpenChange:t,onSaved:n}){let[r,i]=(0,C.useState)(`require`),[a,o]=(0,C.useState)(`require`),[s,c]=(0,C.useState)(!1),[l,u]=(0,C.useState)(null),d=a!==r;return(0,C.useEffect)(()=>{if(!e)return;let t=new AbortController;return c(!0),ki(`/api/config`,{signal:t.signal}).then(e=>{i(e.mentionPolicy),o(e.mentionPolicy),u(null)}).catch(e=>{t.signal.aborted||u(e.message)}).finally(()=>{t.signal.aborted||c(!1)}),()=>t.abort()},[e]),(0,A.jsx)(bi,{open:e,onOpenChange:e=>{!e&&d&&!window.confirm(`全局设置尚未保存,确定放弃草稿吗?`)||t(e)},title:`全局设置`,description:`只管理所有 Agent 共同继承的默认值;高级操作仍使用 CLI。`,children:(0,A.jsxs)(`div`,{className:`settings-form`,children:[(0,A.jsxs)(`label`,{children:[(0,A.jsx)(`span`,{children:`真人群消息默认策略`}),(0,A.jsxs)(`select`,{value:a,onChange:e=>o(e.target.value),disabled:s,children:[(0,A.jsx)(`option`,{value:`require`,children:`require · 群内需要 @`}),(0,A.jsx)(`option`,{value:`free`,children:`free · 群内无需 @`})]})]}),(0,A.jsx)(`p`,{className:`field-help`,children:`未单独设置的 Agent 和群会使用这个值。机器人消息仍必须精确 @ 当前 Agent。`}),(0,A.jsxs)(`div`,{className:`form-actions`,children:[(0,A.jsx)(vi,{onClick:()=>o(r),disabled:!d||s,children:`放弃草稿`}),(0,A.jsx)(vi,{className:`primary`,onClick:async()=>{c(!0);try{let e=await Oi({operation:`set-global-mention`,value:a});i(a),u(`已保存 · ${e.applyState} · ${e.revision.slice(0,20)}…`),n()}catch(e){u(e instanceof Error?e.message:String(e))}finally{c(!1)}},disabled:!d||s,children:s?`保存中…`:`保存全局设置`})]}),l?(0,A.jsx)(`p`,{role:`status`,className:`feedback`,children:l}):null]})})}function Ri({config:e,onSave:t,disabled:n}){let[r,i]=(0,C.useState)(``),[a,o]=(0,C.useState)(``),[s,c]=(0,C.useState)(`require`),l=e.knownChats.filter(e=>e.kind===`group`&&e.override!==`inherit`).filter(e=>{let t=r.trim().toLocaleLowerCase();return!t||e.chatId.toLocaleLowerCase().includes(t)||String(e.displayName||`未解析群名`).toLocaleLowerCase().includes(t)});return(0,A.jsxs)(`section`,{className:`group-policy-section`,"aria-labelledby":`group-policy-title`,children:[(0,A.jsxs)(`div`,{className:`section-heading`,children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`h3`,{id:`group-policy-title`,children:`群策略`}),(0,A.jsx)(`p`,{children:`这里只显示为当前 Agent 单独设置过消息策略的群。`})]}),(0,A.jsxs)(`label`,{className:`table-search`,children:[(0,A.jsx)(de,{size:14}),(0,A.jsx)(`span`,{className:`sr-only`,children:`搜索群`}),(0,A.jsx)(`input`,{value:r,onChange:e=>i(e.target.value),placeholder:`搜索群名或 chat_id`})]})]}),(0,A.jsxs)(`div`,{className:`policy-table-wrap`,children:[(0,A.jsxs)(`table`,{className:`policy-table`,children:[(0,A.jsx)(`thead`,{children:(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`th`,{children:`群`}),(0,A.jsx)(`th`,{children:`消息策略`}),(0,A.jsx)(`th`,{children:`操作`})]})}),(0,A.jsx)(`tbody`,{children:l.map(e=>(0,A.jsxs)(`tr`,{children:[(0,A.jsxs)(`td`,{children:[(0,A.jsx)(`strong`,{children:e.displayName||e.chatId}),e.displayName?(0,A.jsx)(`code`,{children:e.chatId}):(0,A.jsx)(`small`,{children:`群名暂时不可用`})]}),(0,A.jsx)(`td`,{children:(0,A.jsxs)(`select`,{"aria-label":`${e.displayName||e.chatId} 消息策略`,value:e.override,disabled:n,onChange:n=>void t(e.chatId,n.target.value),children:[(0,A.jsx)(`option`,{value:`require`,children:`需要 @`}),(0,A.jsx)(`option`,{value:`free`,children:`无需 @`})]})}),(0,A.jsx)(`td`,{children:(0,A.jsx)(vi,{disabled:n,onClick:()=>void t(e.chatId,`inherit`),children:`移除特别配置`})})]},e.chatId))})]}),l.length?null:(0,A.jsx)(xi,{title:r?`没有匹配的群`:`还没有单独配置的群`,detail:`新增后,Larkin 会自动解析并缓存群名。`})]}),(0,A.jsxs)(`div`,{className:`chat-add`,children:[(0,A.jsxs)(`label`,{children:[(0,A.jsx)(`span`,{children:`完整 chat_id`}),(0,A.jsx)(`input`,{value:a,onChange:e=>o(e.target.value),placeholder:`oc_QAConfigChat1`})]}),(0,A.jsxs)(`label`,{children:[(0,A.jsx)(`span`,{children:`消息策略`}),(0,A.jsxs)(`select`,{value:s,onChange:e=>c(e.target.value),children:[(0,A.jsx)(`option`,{value:`require`,children:`需要 @`}),(0,A.jsx)(`option`,{value:`free`,children:`无需 @`})]})]}),(0,A.jsx)(vi,{disabled:n||!/^oc_[A-Za-z0-9_-]+$/.test(a),onClick:()=>void t(a,s).then(()=>o(``)),children:`保存群策略`})]})]})}function zi({agentId:e,onDirtyChange:t,refreshKey:n}){let[r,i]=(0,C.useState)(null),[a,o]=(0,C.useState)({}),[s,c]=(0,C.useState)({}),[l,u]=(0,C.useState)(!0),[d,f]=(0,C.useState)(null),[p,m]=(0,C.useState)(null),h=(0,C.useRef)(Se()),g=(0,C.useRef)(Se()),_=!xe(a,s);(0,C.useEffect)(()=>t(_),[_,t]),(0,C.useEffect)(()=>{let e=e=>{_&&e.preventDefault()};return window.addEventListener(`beforeunload`,e),()=>window.removeEventListener(`beforeunload`,e)},[_]);let v=(0,C.useCallback)(async(t=!1)=>{let n=h.current.issue();u(!0);try{let r=await ki(`/api/config?agent=${encodeURIComponent(e)}`);if(!h.current.accepts(n))return;let a=r.agents[0];if(!a)throw Error(`配置投影中没有当前 Agent`);let s={runtime:a.runtimeOption||a.runtime,model:a.model,effort:a.effort||`default`,mention:a.mention.override};i(r),o(s),(!t||!_)&&c(s)}catch(e){h.current.accepts(n)&&f(e instanceof Error?e.message:String(e))}finally{h.current.accepts(n)&&u(!1)}},[e,_]);(0,C.useEffect)(()=>{v(!1)},[e]),(0,C.useEffect)(()=>{n>0&&v(!0)},[n]);let y=r?.agents[0],b=(e,t)=>c(n=>({...n,[e]:t})),x=String(s.runtime||y?.runtime||``),S=String(s.model||y?.model||`default`);(0,C.useEffect)(()=>{if(m({runtime:x,status:`loading`,models:[]}),!new Set([`pi`,`builtin-pi`,`codex`,`claude`]).has(x)){m({runtime:x,status:`error`,models:[]});return}let t=g.current.issue(),n=new AbortController;return ki(`/api/models/${x}?agent=${encodeURIComponent(e)}`,{signal:n.signal}).then(e=>{g.current.accepts(t)&&m({runtime:x,status:`ready`,models:e.models})}).catch(e=>{!n.signal.aborted&&g.current.accepts(t)&&(m({runtime:x,status:`error`,models:[]}),f(`${x} 模型列表暂时不可用:${e instanceof Error?e.message:String(e)}`))}),()=>n.abort()},[e,x]);let w=p?.runtime===x&&p.status===`ready`,ee=p?.runtime===x?p.status:`loading`,te=w?p.models:[],T=`${S} · 当前配置(模型目录${ee===`error`?`不可用`:`加载中`})`,E=w?te.some(e=>e.id===S)?te:[{id:S,label:`${S} · 当前配置`},...te]:[{id:S,label:T}],ne=w&&S!=="default"&&te.find(e=>e.id===S)?.supportedReasoningEfforts||[],re=s.runtime!==a.runtime||s.model!==a.model||s.effort!==a.effort,ie=()=>Ei(`/api/config/apply`,{method:`POST`,headers:{"Content-Type":`application/json`,"X-Larkin-CSRF":wi.csrfCapability},body:JSON.stringify({agentId:e})}),ae=async()=>{if(y){u(!0);try{let t=[];s.runtime===a.runtime?s.model!==a.model&&t.push({operation:`set-agent-model`,agentId:e,model:s.model}):t.push({operation:`set-agent-runtime`,agentId:e,runtime:s.runtime,model:s.model}),s.effort!==a.effort&&t.push({operation:`set-agent-effort`,agentId:e,effort:s.effort}),s.mention!==a.mention&&t.push({operation:`set-agent-mention`,agentId:e,value:s.mention});let n=null;for(let e of t)n=await Oi(e);if(re)try{await ie(),f(`配置已保存并应用`)}catch(e){f(`配置已保存但未应用:${Di(e,`稍后重试`)}`)}else f(n?`配置已保存`:`没有需要保存的修改`);await v(!1)}catch(e){f(e instanceof Error?e.message:String(e))}finally{u(!1)}}},oe=async()=>{u(!0);try{await ie(),f(`已应用保存的运行配置`),await v(!0)}catch(e){f(`配置保持已保存但未应用:${Di(e,`稍后重试`)}`)}finally{u(!1)}},se=async(t,n)=>{u(!0);try{let r=await Oi({operation:`set-chat-mention`,agentId:e,chatId:t,value:n});f(`群策略已保存 · ${r.applyState}`),await v(!0)}catch(e){f(e instanceof Error?e.message:String(e))}finally{u(!1)}};if(!y&&l)return(0,A.jsx)(xi,{title:`加载 Agent 配置…`});if(!y)return(0,A.jsx)(xi,{title:`配置不可用`,detail:d||`请重试`});let ce=y.apply.applyState===`pending`?`待应用`:y.apply.applyState===`applied`?`已应用`:`状态未知`;return(0,A.jsxs)(`div`,{className:`configuration-page`,children:[(0,A.jsxs)(`section`,{className:`config-section`,children:[(0,A.jsxs)(`div`,{className:`section-heading`,children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`h3`,{children:`Agent 配置`}),(0,A.jsxs)(`p`,{children:[`只作用于 `,e,`;运行配置会在安全时机自动应用,Agent 正忙时会保留待处理。`]})]}),(0,A.jsx)(yi,{className:y.apply.applyState===`pending`?`warning`:`success`,children:ce})]}),(0,A.jsxs)(`p`,{className:`cli-guidance`,children:[`这里只提供常用微调。更多配置可以直接告诉当前 Agent,让它运行 `,(0,A.jsx)(`code`,{children:`larkin config --help`}),` 后完成。`]}),(0,A.jsxs)(`div`,{className:`config-grid`,children:[(0,A.jsxs)(`label`,{children:[(0,A.jsx)(`span`,{children:`Runtime`}),(0,A.jsx)(`select`,{value:x,disabled:l,onChange:e=>{b(`runtime`,e.target.value),b(`model`,`default`),b(`effort`,`default`)},children:(r?.runtimeOptions||Si).map(e=>(0,A.jsx)(`option`,{value:e,children:e},e))})]}),(0,A.jsxs)(`label`,{children:[(0,A.jsx)(`span`,{children:`Model`}),(0,A.jsx)(`select`,{value:S,disabled:l||!w,onChange:e=>{b(`model`,e.target.value),e.target.value==="default"&&b(`effort`,`default`)},children:E.map(e=>(0,A.jsx)(`option`,{value:e.id,children:e.label||e.id},e.id))})]}),(0,A.jsxs)(`label`,{children:[(0,A.jsx)(`span`,{children:`Effort`}),(0,A.jsxs)(`select`,{value:String(s.effort||`default`),disabled:l||!w||S==="default"||!ne.length,onChange:e=>b(`effort`,e.target.value),children:[(0,A.jsx)(`option`,{value:`default`,children:`default · 不指定`}),ne.map(e=>(0,A.jsx)(`option`,{value:e,children:e},e))]})]}),(0,A.jsxs)(`label`,{children:[(0,A.jsx)(`span`,{children:`群消息策略`}),(0,A.jsxs)(`select`,{value:String(s.mention||`inherit`),disabled:l,onChange:e=>b(`mention`,e.target.value),children:[(0,A.jsx)(`option`,{value:`inherit`,children:`跟随全局设置`}),(0,A.jsx)(`option`,{value:`require`,children:`需要 @`}),(0,A.jsx)(`option`,{value:`free`,children:`无需 @`})]})]})]}),_||y.apply.applyState===`pending`?(0,A.jsxs)(`div`,{className:`form-actions`,children:[_?(0,A.jsx)(vi,{disabled:l,onClick:()=>c(a),children:`放弃草稿`}):null,_?(0,A.jsx)(vi,{className:`primary`,disabled:l,onClick:ae,children:l?`处理中…`:re?`保存并应用`:`保存 Agent 配置`}):(0,A.jsxs)(vi,{className:`primary`,disabled:l,onClick:oe,children:[(0,A.jsx)(ue,{size:14}),` 应用已保存配置`]})]}):null,d?(0,A.jsx)(`p`,{role:`status`,className:`feedback`,children:d}):null]}),(0,A.jsx)(Ri,{config:y,onSave:se,disabled:l})]})}function Bi({agent:e}){let t=e.session?.usage||{},n=e.session?.compaction||{};return(0,A.jsxs)(`div`,{className:`overview-page`,children:[(0,A.jsxs)(`div`,{className:`metrics-band`,"aria-label":`Agent 运行指标`,children:[(0,A.jsxs)(`section`,{className:`metric-stat`,children:[(0,A.jsx)(`div`,{className:`metric-icon`,children:(0,A.jsx)(ie,{})}),(0,A.jsx)(`span`,{children:`连接`}),(0,A.jsx)(`strong`,{children:e.connection.state}),(0,A.jsx)(`small`,{children:e.connection.reason})]}),(0,A.jsxs)(`section`,{className:`metric-stat`,children:[(0,A.jsx)(`div`,{className:`metric-icon`,children:(0,A.jsx)(E,{})}),(0,A.jsx)(`span`,{children:`执行状态`}),(0,A.jsx)(`strong`,{children:Ni(e)}),(0,A.jsx)(`small`,{children:e.lastActivity?Ai(e.lastActivity.ageSec):`尚无活动`})]}),(0,A.jsxs)(`section`,{className:`metric-stat`,children:[(0,A.jsx)(`div`,{className:`metric-icon`,children:(0,A.jsx)(le,{})}),(0,A.jsx)(`span`,{children:`最近消息`}),(0,A.jsx)(`strong`,{children:e.lastDeliver?.from||`暂无`}),(0,A.jsx)(`small`,{children:e.lastDeliver?`${e.lastDeliver.target||``} · ${Ai(e.lastDeliver.ageSec)}`:`尚无消息记录`})]}),(0,A.jsxs)(`section`,{className:`metric-stat`,children:[(0,A.jsx)(`div`,{className:`metric-icon`,children:(0,A.jsx)(ce,{})}),(0,A.jsx)(`span`,{children:`上下文`}),(0,A.jsx)(`strong`,{children:t.contextPercent==null?`${e.session?.turns||0} turns`:`${Math.round(Number(t.contextPercent))}%`}),(0,A.jsx)(`small`,{children:e.session?`session ${e.session.id.slice(0,12)}…`:`尚未建立 session`})]}),(0,A.jsxs)(`section`,{className:`metric-stat`,children:[(0,A.jsx)(`div`,{className:`metric-icon`,children:(0,A.jsx)(ce,{})}),(0,A.jsx)(`span`,{children:`累计 Token`}),(0,A.jsx)(`strong`,{children:Mi(t.cumulativeTokens)}),(0,A.jsx)(`small`,{children:t.available?`完整 session 累计`:t.reason||`暂无用量`})]}),(0,A.jsxs)(`section`,{className:`metric-stat`,children:[(0,A.jsx)(`div`,{className:`metric-icon`,children:(0,A.jsx)(E,{})}),(0,A.jsx)(`span`,{children:`最近一轮用量`}),(0,A.jsx)(`strong`,{children:Mi(t.latestTokens)}),(0,A.jsx)(`small`,{children:`输入、缓存与输出合计`})]}),(0,A.jsxs)(`section`,{className:`metric-stat`,children:[(0,A.jsx)(`div`,{className:`metric-icon`,children:(0,A.jsx)(ue,{})}),(0,A.jsx)(`span`,{children:`Compaction`}),(0,A.jsx)(`strong`,{children:Mi(n.count)}),(0,A.jsx)(`small`,{children:n.active?`正在压缩上下文`:n.lastFinishedAt?`最近 ${ji(n.lastFinishedAt)}`:`尚无压缩记录`})]})]}),(0,A.jsxs)(`div`,{className:`overview-sections`,children:[(0,A.jsxs)(`section`,{className:`content-section wide`,children:[(0,A.jsxs)(`div`,{className:`section-heading`,children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`h3`,{children:`最近动态`}),(0,A.jsx)(`p`,{children:`当前 Agent 的消息、工具和状态转换。`})]}),(0,A.jsx)(yi,{children:e.feed.length})]}),(0,A.jsx)(M,{items:e.feed.slice(0,10)})]}),(0,A.jsxs)(`section`,{className:`content-section`,children:[(0,A.jsx)(`h3`,{children:`运行摘要`}),(0,A.jsxs)(`dl`,{className:`facts`,children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`dt`,{children:`Runtime`}),(0,A.jsx)(`dd`,{children:e.runtime})]}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`dt`,{children:`Readiness`}),(0,A.jsx)(`dd`,{children:e.runtimeReadiness?`${e.runtimeReadiness.state}${e.runtimeReadiness.version?` · ${e.runtimeReadiness.version}`:``}${e.runtimeReadiness.executable?` · ${e.runtimeReadiness.executable}`:``}${e.runtimeReadiness.reason?` · ${e.runtimeReadiness.reason}`:``}${e.runtimeReadiness.nextAction?` · ${e.runtimeReadiness.nextAction}`:``}`:`unknown`})]}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`dt`,{children:`Model`}),(0,A.jsx)(`dd`,{children:e.model})]}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`dt`,{children:`Effort`}),(0,A.jsx)(`dd`,{children:e.effort||`default`})]}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`dt`,{children:`入站`}),(0,A.jsx)(`dd`,{children:e.inbound.state})]}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`dt`,{children:`提醒`}),(0,A.jsx)(`dd`,{children:e.activeReminders})]}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`dt`,{children:`指示灯`}),(0,A.jsx)(`dd`,{children:e.eyeIndicator.stuck?`疑似卡住`:`${e.eyeIndicator.pendingCount} pending`})]})]})]})]})]})}function M({items:e}){if(!e.length)return(0,A.jsx)(xi,{title:`还没有活动记录`});let t=e=>e.kind===`error`||e.state===`error`?`state-error`:e.kind===`deliver`?`state-deliver`:[`working`,`thinking`,`tool`].includes(String(e.state))?`state-active`:[`idle`,`online`].includes(String(e.state))?`state-idle`:`state-unknown`;return(0,A.jsx)(`ol`,{className:`timeline`,children:e.map((e,n)=>(0,A.jsxs)(`li`,{children:[(0,A.jsx)(`span`,{className:_i(`timeline-dot`,t(e))}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`strong`,{children:e.kind===`deliver`?`收到消息`:e.kind===`error`?`错误`:e.state||`活动`}),(0,A.jsx)(`p`,{children:e.text||e.detail||[e.from,e.target].filter(Boolean).join(` → `)||e.tool||`状态已更新`}),(0,A.jsx)(`time`,{children:ji(e.at)})]})]},`${e.at}-${n}`))})}function N({agent:e}){return e.conversation.length?(0,A.jsx)(`div`,{className:`conversation-list`,children:e.conversation.map((t,n)=>{let r=t.direction===`out`?`已发送`:t.wake?`入站 · 已唤醒`:`旁听 · 未唤醒`;return(0,A.jsxs)(`article`,{className:_i(`conversation-item`,t.direction===`out`?`outbound`:`inbound`,t.direction===`in`&&!t.wake&&`listening`),children:[(0,A.jsxs)(`header`,{children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(yi,{className:t.direction===`in`&&!t.wake?`warning`:t.direction===`out`?`accent`:`success`,children:r}),(0,A.jsx)(`strong`,{children:t.from||(t.direction===`out`?e.displayName:`未知发送者`)})]}),(0,A.jsx)(`time`,{children:ji(t.at)})]}),(0,A.jsx)(`p`,{children:t.text||`[非文本消息]`}),t.target?(0,A.jsx)(`small`,{children:t.target}):null]},`${t.at}-${n}`)})}):(0,A.jsx)(xi,{title:`还没有对话摘录`,detail:`Host 更新本地 conversation projection 后会显示在这里。`})}function Vi({agent:e}){if(!e.remindersList.length)return(0,A.jsx)(xi,{title:`还没有提醒`});let t={scheduled:`待执行`,pending:`待执行`,fired:`已完成`,canceled:`已取消`,cancelled:`已取消`,failed:`失败`};return(0,A.jsx)(`div`,{className:`reminder-list`,children:e.remindersList.map((e,n)=>{let r=e.status||`scheduled`,i=[`fired`,`canceled`,`cancelled`].includes(r);return(0,A.jsxs)(`article`,{className:_i(`status-${r===`cancelled`?`canceled`:r}`,i&&`done`),children:[(0,A.jsx)(ne,{size:16}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`strong`,{children:e.title||`未命名提醒`}),(0,A.jsxs)(`p`,{children:[ji(e.fireAt),e.repeat?` · 重复`:``]})]}),(0,A.jsx)(yi,{className:[`scheduled`,`pending`].includes(r)?`warning`:r===`fired`?`success`:r===`failed`?`danger-badge`:``,children:t[r]||r})]},`${e.fireAt}-${n}`)})})}function Hi({agentId:e}){let[t,n]=(0,C.useState)(null),[r,i]=(0,C.useState)(null),[a,o]=(0,C.useState)(!0),[s,c]=(0,C.useState)(null),l=(0,C.useRef)(Se()),u=(0,C.useCallback)(async t=>{let r=l.current.issue();o(!0);try{let a=await Ei(`/api/workspace?agent=${encodeURIComponent(e)}&path=${encodeURIComponent(t)}`);if(!l.current.accepts(r))return;a.kind===`directory`?(n(a),i(null)):i(a),c(null)}catch(e){l.current.accepts(r)&&c(e instanceof Error?e.message:String(e))}finally{l.current.accepts(r)&&o(!1)}},[e]);(0,C.useEffect)(()=>{u(``)},[u]);let d=t?.path.split(`/`).filter(Boolean)||[];return(0,A.jsxs)(`div`,{className:`workspace-browser`,children:[(0,A.jsxs)(`div`,{className:`workspace-side`,children:[(0,A.jsxs)(`nav`,{className:`breadcrumbs`,"aria-label":`工作区路径`,children:[(0,A.jsx)(`button`,{onClick:()=>void u(``),children:`workspace`}),d.map((e,t)=>(0,A.jsxs)(`span`,{children:[(0,A.jsx)(re,{size:12}),(0,A.jsx)(`button`,{onClick:()=>void u(d.slice(0,t+1).join(`/`)),children:e})]},`${e}-${t}`))]}),(0,A.jsxs)(`div`,{className:`workspace-list`,role:`region`,"aria-label":`工作区目录`,children:[t?.entries.map(e=>(0,A.jsxs)(`button`,{onClick:()=>void u(e.path),children:[e.kind===`directory`?(0,A.jsx)(se,{size:15}):(0,A.jsx)(oe,{size:15}),(0,A.jsx)(`span`,{children:e.name}),(0,A.jsx)(`small`,{children:e.kind===`file`?`${e.size} B`:`目录`})]},e.path)),!a&&t&&!t.entries.length?(0,A.jsx)(xi,{title:`空目录`}):null]})]}),(0,A.jsx)(`div`,{className:`workspace-preview`,role:`region`,"aria-label":`文件预览`,children:a?(0,A.jsx)(xi,{title:`读取工作区…`}):s?(0,A.jsx)(xi,{title:`工作区读取失败`,detail:s}):r?(0,A.jsxs)(A.Fragment,{children:[(0,A.jsxs)(`header`,{children:[(0,A.jsx)(`strong`,{children:r.name}),(0,A.jsx)(`small`,{children:r.truncated?`仅预览前 1 MB`:`${r.size} B`})]}),r.binary?(0,A.jsx)(xi,{title:`二进制文件不可预览`}):(0,A.jsx)(`pre`,{children:r.content})]}):(0,A.jsx)(xi,{title:`只读工作区`,detail:`选择文件进行预览`})})]})}function Ui({agent:e}){return(0,A.jsxs)(`section`,{className:`logs-section`,children:[(0,A.jsxs)(`div`,{className:`section-heading`,children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`h3`,{children:`结构化日志`}),(0,A.jsx)(`p`,{children:`最近 30 条本地状态投影;不暴露原始日志文件或路径。`})]}),(0,A.jsx)(yi,{children:e.feed.length})]}),(0,A.jsx)(M,{items:e.feed}),e.recentErrors.length?(0,A.jsxs)(`section`,{className:`error-stack`,children:[(0,A.jsx)(`h4`,{children:`最近错误`}),e.recentErrors.map((e,t)=>(0,A.jsxs)(`div`,{children:[(0,A.jsx)(ae,{size:14}),(0,A.jsx)(`span`,{children:e.text||e.message||`未知错误`}),(0,A.jsx)(`time`,{children:ji(e.at)})]},`${e.at}-${t}`))]}):null]})}function Wi({agent:e}){let t=e.session?.usage||{},n=e.session?.compaction||{},r=t.contextPercent==null?`上下文 ${e.session?.turns||0} turns`:`上下文 ${Math.round(Number(t.contextPercent))}% · ${Mi(t.latestTokens)} / ${Mi(t.contextWindow)}`;return(0,A.jsxs)(`header`,{className:`agent-header`,children:[(0,A.jsxs)(`div`,{className:`agent-title`,children:[(0,A.jsx)(Fi,{agent:e}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`p`,{children:e.agentId}),(0,A.jsx)(`h1`,{children:e.displayName||e.name})]})]}),(0,A.jsxs)(`div`,{className:`agent-header-summary`,children:[(0,A.jsx)(yi,{className:e.connection.state===`connected`?`success`:e.issue?`danger-badge`:``,children:e.connection.state}),(0,A.jsx)(`span`,{children:e.runtime}),(0,A.jsx)(`span`,{children:e.model}),(0,A.jsx)(`span`,{children:e.effort||`default effort`}),(0,A.jsx)(`span`,{children:r}),(0,A.jsxs)(`span`,{children:[`累计 `,Mi(t.cumulativeTokens),` tokens`]}),(0,A.jsxs)(`span`,{children:[`最近一轮 `,Mi(t.latestTokens),` tokens`]}),(0,A.jsxs)(`span`,{children:[`Compact `,Mi(n.count),` 次 · `,n.active?`active`:`idle`]}),(0,A.jsxs)(`span`,{children:[`最近消息 `,e.lastDeliver?Ai(e.lastDeliver.ageSec):`暂无`]}),(0,A.jsx)(`span`,{children:e.lastActivity?.detail||Ni(e)})]})]})}function Gi(){let e=Pi(),t=(0,C.useMemo)(()=>_e(window.location.search),[]),[n,r]=(0,C.useState)(t.agentId),[i,a]=(0,C.useState)(t.tab),[o,s]=(0,C.useState)(!1),[c,l]=(0,C.useState)(!1),[u,d]=(0,C.useState)(0),[f,p]=(0,C.useState)(!1),[m,h]=(0,C.useState)(null),g=(0,C.useRef)(new Map),_=e.data?.agents||[],v=e.data?.packageVersion||wi.packageVersion,y=_.find(e=>e.agentId===n)||null,b=(0,C.useCallback)((e,t)=>{let n=`${e}:${t}`,r=window.scrollY;g.current.set(n,r);try{sessionStorage.setItem(`larkin-dashboard-scroll:${n}`,String(r))}catch{}},[]),x=(0,C.useCallback)(e=>{if(g.current.has(e))return g.current.get(e)||0;try{let t=Number(sessionStorage.getItem(`larkin-dashboard-scroll:${e}`));return Number.isFinite(t)&&t>=0?t:0}catch{return 0}},[]),S=(0,C.useCallback)((e,t,o=!1)=>{n&&b(n,i);let s=o?`replaceState`:`pushState`;window.history[s](null,``,ve(e,t)),r(e),a(t)},[b,n,i]),w=()=>!f||window.confirm(`Agent 配置尚未保存,确定放弃草稿吗?`),ee=e=>{w()&&(p(!1),S(e,i),l(!1))},te=e=>{e!==`configuration`&&!w()||(e!==`configuration`&&p(!1),S(n,e))};return(0,C.useEffect)(()=>{if(!e.data)return;let t=ye(n,e.data.agents);t!==n&&(h(n?`原 Agent 已不存在,已切换到第一个可用 Agent。`:null),S(t,i,!0))},[e.data,n,i,S]),(0,C.useEffect)(()=>{let e=()=>{let e=_e(window.location.search);if(f&&!window.confirm(`Agent 配置尚未保存,确定离开吗?`)){window.history.pushState(null,``,ve(n,i));return}n&&b(n,i),p(!1),r(e.agentId),a(e.tab)};return window.addEventListener(`popstate`,e),()=>window.removeEventListener(`popstate`,e)},[f,b,n,i]),(0,C.useLayoutEffect)(()=>{if(!n)return;let e=`${n}:${i}`,t=x(e);window.scrollY!==t&&window.scrollTo({top:t,behavior:`auto`})},[x,n,i]),(0,A.jsxs)(`div`,{className:_i(`app-shell`,i===`workspace`&&`workspace-app-active`),children:[(0,A.jsxs)(`aside`,{className:`desktop-sidebar`,children:[(0,A.jsxs)(`div`,{className:`brand`,children:[(0,A.jsx)(`img`,{src:`/assets/larkin-mark.svg`,alt:``}),(0,A.jsxs)(`strong`,{children:[`Larkin `,(0,A.jsxs)(`span`,{className:`brand-version`,children:[`v`,v]})]})]}),(0,A.jsx)(Ii,{agents:_,selectedId:n,onSelect:ee}),(0,A.jsx)(`footer`,{children:e.data?.daemon.running?`${_.length} Agents · daemon online`:`daemon offline`})]}),(0,A.jsxs)(`main`,{className:_i(`workspace-shell`,i===`workspace`&&`workspace-route-active`),children:[(0,A.jsxs)(`div`,{className:`app-topbar`,children:[(0,A.jsx)(vi,{className:`mobile-menu`,"aria-label":`打开 Agent 导航`,onClick:()=>l(!0),children:(0,A.jsx)(O,{size:18})}),(0,A.jsxs)(`div`,{children:[(0,A.jsxs)(`strong`,{children:[`Larkin `,(0,A.jsxs)(`span`,{className:`brand-version`,children:[`v`,v]})]}),(0,A.jsx)(`span`,{children:e.data?.daemon.running?`运行中`:`未运行`}),e.stale?(0,A.jsx)(yi,{className:`warning`,children:`状态陈旧`}):null]}),(0,A.jsxs)(vi,{onClick:()=>s(!0),children:[(0,A.jsx)(fe,{size:15}),` 全局设置`]})]}),e.error?(0,A.jsxs)(`div`,{className:`stale-banner`,role:`alert`,children:[(0,A.jsx)(k,{size:15}),`状态刷新失败,保留最后一次数据:`,e.error,(0,A.jsx)(vi,{onClick:()=>void e.retry(),children:`重试`})]}):null,m?(0,A.jsxs)(`div`,{className:`notice`,role:`status`,children:[m,(0,A.jsx)(vi,{"aria-label":`关闭提示`,onClick:()=>h(null),children:`×`})]}):null,e.loading&&!e.data?(0,A.jsxs)(`div`,{className:`page-loading`,children:[(0,A.jsx)(ue,{className:`spin`}),`加载 Agent 工作台…`]}):y?(0,A.jsxs)(A.Fragment,{children:[(0,A.jsx)(Wi,{agent:y}),(0,A.jsx)(`nav`,{className:`agent-tabs`,"aria-label":`${y.displayName} 内容页签`,role:`tablist`,children:ge.map(e=>(0,A.jsxs)(`button`,{type:`button`,role:`tab`,"aria-selected":i===e,className:i===e?`active`:``,onClick:()=>te(e),children:[e===`overview`?(0,A.jsx)(ce,{}):e===`conversation`?(0,A.jsx)(le,{}):e===`configuration`?(0,A.jsx)(pe,{}):e===`reminders`?(0,A.jsx)(ne,{}):e===`workspace`?(0,A.jsx)(se,{}):(0,A.jsx)(D,{}),Ci[e]]},e))}),(0,A.jsxs)(`div`,{className:_i(`agent-content`,i===`workspace`&&`workspace-active`),children:[(0,A.jsx)(`section`,{role:`tabpanel`,hidden:i!==`overview`,children:(0,A.jsx)(Bi,{agent:y})}),(0,A.jsx)(`section`,{role:`tabpanel`,hidden:i!==`conversation`,children:(0,A.jsx)(N,{agent:y})}),(0,A.jsx)(`section`,{role:`tabpanel`,hidden:i!==`configuration`,children:(0,A.jsx)(zi,{agentId:y.agentId,onDirtyChange:p,refreshKey:u})}),(0,A.jsx)(`section`,{role:`tabpanel`,hidden:i!==`reminders`,children:(0,A.jsx)(Vi,{agent:y})}),(0,A.jsx)(`section`,{className:`workspace-tab-panel`,role:`tabpanel`,hidden:i!==`workspace`,children:(0,A.jsx)(Hi,{agentId:y.agentId})}),(0,A.jsx)(`section`,{role:`tabpanel`,hidden:i!==`logs`,children:(0,A.jsx)(Ui,{agent:y})})]},y.agentId)]}):(0,A.jsx)(xi,{title:`还没有配置任何 Agent`,detail:`先运行 larkin setup。`})]}),(0,A.jsx)(Li,{open:o,onOpenChange:s,onSaved:()=>d(e=>e+1)}),(0,A.jsx)(bi,{open:c,onOpenChange:l,title:`选择 Agent`,description:`搜索、查看状态并切换当前工作区。`,children:(0,A.jsx)(Ii,{compact:!0,agents:_,selectedId:n,onSelect:ee})})]})}var Ki=document.getElementById(`root`);if(!Ki)throw Error(`dashboard root is missing`);(0,he.createRoot)(Ki).render((0,A.jsx)(C.StrictMode,{children:(0,A.jsx)(Gi,{})}));
|
|
49
|
+
`},Or=0,kr=[];function Ar(e){var t=C.useRef([]),n=C.useRef([0,0]),r=C.useRef(),i=C.useState(Or++)[0],a=C.useState(Qn)[0],o=C.useRef(e);C.useEffect(function(){o.current=e},[e]),C.useEffect(function(){if(e.inert){document.body.classList.add(`block-interactivity-${i}`);var t=Dn([e.lockRef.current],(e.shards||[]).map(Tr),!0).filter(Boolean);return t.forEach(function(e){return e.classList.add(`allow-interactivity-${i}`)}),function(){document.body.classList.remove(`block-interactivity-${i}`),t.forEach(function(e){return e.classList.remove(`allow-interactivity-${i}`)})}}},[e.inert,e.lockRef.current,e.shards]);var s=C.useCallback(function(e,t){if(`touches`in e&&e.touches.length===2||e.type===`wheel`&&e.ctrlKey)return!o.current.allowPinchZoom;var i=Cr(e),a=n.current,s=`deltaX`in e?e.deltaX:a[0]-i[0],c=`deltaY`in e?e.deltaY:a[1]-i[1],l,u=e.target,d=Math.abs(s)>Math.abs(c)?`h`:`v`;if(`touches`in e&&d===`h`&&u.type===`range`)return!1;var f=window.getSelection(),p=f&&f.anchorNode;if(p&&(p===u||p.contains(u)))return!1;var m=gr(d,u);if(!m)return!0;if(m?l=d:(l=d===`v`?`h`:`v`,m=gr(d,u)),!m)return!1;if(!r.current&&`changedTouches`in e&&(s||c)&&(r.current=l),!l)return!0;var h=r.current||l;return Sr(h,t,e,h===`h`?s:c,!0)},[]),c=C.useCallback(function(e){var n=e;if(!(!kr.length||kr[kr.length-1]!==a)){var r=`deltaY`in n?wr(n):Cr(n),i=t.current.filter(function(e){return e.name===n.type&&(e.target===n.target||n.target===e.shadowParent)&&Er(e.delta,r)})[0];if(i&&i.should){n.cancelable&&n.preventDefault();return}if(!i){var c=(o.current.shards||[]).map(Tr).filter(Boolean).filter(function(e){return e.contains(n.target)});(c.length>0?s(n,c[0]):!o.current.noIsolation)&&n.cancelable&&n.preventDefault()}}},[]),l=C.useCallback(function(e,n,r,i){var a={name:e,delta:n,target:r,should:i,shadowParent:jr(r)};t.current.push(a),setTimeout(function(){t.current=t.current.filter(function(e){return e!==a})},1)},[]),u=C.useCallback(function(e){n.current=Cr(e),r.current=void 0},[]),d=C.useCallback(function(t){l(t.type,wr(t),t.target,s(t,e.lockRef.current))},[]),f=C.useCallback(function(t){l(t.type,Cr(t),t.target,s(t,e.lockRef.current))},[]);C.useEffect(function(){return kr.push(a),e.setCallbacks({onScrollCapture:d,onWheelCapture:d,onTouchMoveCapture:f}),document.addEventListener(`wheel`,c,dr),document.addEventListener(`touchmove`,c,dr),document.addEventListener(`touchstart`,u,dr),function(){kr=kr.filter(function(e){return e!==a}),document.removeEventListener(`wheel`,c,dr),document.removeEventListener(`touchmove`,c,dr),document.removeEventListener(`touchstart`,u,dr)}},[]);var p=e.removeScrollBar,m=e.inert;return C.createElement(C.Fragment,null,m?C.createElement(a,{styles:Dr(i)}):null,p?C.createElement(cr,{noRelative:e.noRelative,gapMode:e.gapMode}):null)}function jr(e){for(var t=null;e!==null;)e instanceof ShadowRoot&&(t=e.host,e=e.host),e=e.parentNode;return t}var Mr=Vn(Hn,Ar),Nr=C.forwardRef(function(e,t){return C.createElement(Wn,Tn({},e,{ref:t,sideCar:Mr}))});Nr.classNames=Wn.classNames;var Pr=function(e){return typeof document>`u`?null:(Array.isArray(e)?e[0]:e).ownerDocument.body},Fr=new WeakMap,Ir=new WeakMap,Lr={},Rr=0,zr=function(e){return e&&(e.host||zr(e.parentNode))},Br=function(e,t){return t.map(function(t){if(e.contains(t))return t;var n=zr(t);return n&&e.contains(n)?n:(console.error(`aria-hidden`,t,`in not contained inside`,e,`. Doing nothing`),null)}).filter(function(e){return!!e})},Vr=function(e,t,n,r){var i=Br(t,Array.isArray(e)?e:[e]);Lr[n]||(Lr[n]=new WeakMap);var a=Lr[n],o=[],s=new Set,c=new Set(i),l=function(e){!e||s.has(e)||(s.add(e),l(e.parentNode))};i.forEach(l);var u=function(e){!e||c.has(e)||Array.prototype.forEach.call(e.children,function(e){if(s.has(e))u(e);else try{var t=e.getAttribute(r),i=t!==null&&t!==`false`,c=(Fr.get(e)||0)+1,l=(a.get(e)||0)+1;Fr.set(e,c),a.set(e,l),o.push(e),c===1&&i&&Ir.set(e,!0),l===1&&e.setAttribute(n,`true`),i||e.setAttribute(r,`true`)}catch(t){console.error(`aria-hidden: cannot operate on `,e,t)}})};return u(t),s.clear(),Rr++,function(){o.forEach(function(e){var t=Fr.get(e)-1,i=a.get(e)-1;Fr.set(e,t),a.set(e,i),t||(Ir.has(e)||e.removeAttribute(r),Ir.delete(e)),i||e.removeAttribute(n)}),Rr--,Rr||(Fr=new WeakMap,Fr=new WeakMap,Ir=new WeakMap,Lr={})}},Hr=function(e,t,n){n===void 0&&(n=`data-aria-hidden`);var r=Array.from(Array.isArray(e)?e:[e]),i=t||Pr(e);return i?(r.push.apply(r,Array.from(i.querySelectorAll(`[aria-live], script`))),Vr(r,i,n,`aria-hidden`)):function(){return null}},Ur=Object.defineProperty,Wr=(e,t)=>Ur(e,`name`,{value:t,configurable:!0}),Gr=`Dialog`,[Kr,qr]=Be(Gr),[Jr,Yr]=Kr(Gr),Xr=Wr(e=>{let{__scopeDialog:t,children:n,open:r,defaultOpen:i,onOpenChange:a,modal:o=!0}=e,s=C.useRef(null),c=C.useRef(null),[l,u]=nt({prop:r,defaultProp:i??!1,onChange:a,caller:Gr}),[d,f]=C.useState(0),[p,m]=C.useState(0);return(0,A.jsx)(Jr,{scope:t,triggerRef:s,contentRef:c,contentId:qe(),titleId:qe(),descriptionId:qe(),titlePresent:d>0,descriptionPresent:p>0,setTitleCount:f,setDescriptionCount:m,open:l,onOpenChange:u,onOpenToggle:C.useCallback(()=>u(e=>!e),[u]),modal:o,children:n})},`Dialog`),Zr=`DialogPortal`,[Qr,$r]=Kr(Zr,{forceMount:void 0}),ei=Wr(e=>{let{__scopeDialog:t,forceMount:n,children:r,container:i}=e,a=Yr(Zr,t);return(0,A.jsx)(Qr,{scope:t,forceMount:n,children:C.Children.map(r,e=>(0,A.jsx)(fn,{present:n||a.open,children:(0,A.jsx)(cn,{asChild:!0,container:i,children:e})}))})},`DialogPortal`),ti=`DialogOverlay`,ni=C.forwardRef(Wr(function(e,t){let n=$r(ti,e.__scopeDialog),{forceMount:r=n.forceMount,...i}=e,a=Yr(ti,e.__scopeDialog);return a.modal?(0,A.jsx)(fn,{present:r||a.open,children:(0,A.jsx)(ii,{...i,ref:t})}):null},`DialogOverlay`)),ri=ut(`DialogOverlay.RemoveScroll`),ii=C.forwardRef(Wr(function(e,t){let{__scopeDialog:n,...r}=e,i=Yr(ti,n),a=Fe(t,Lt());return(0,A.jsx)(Nr,{as:ri,allowPinchZoom:!0,shards:[i.contentRef],children:(0,A.jsx)(Tt.div,{"data-state":gi(i.open),...r,ref:a,style:{pointerEvents:`auto`,...r.style}})})},`DialogOverlayImpl`)),ai=`DialogContent`,oi=C.forwardRef(Wr(function(e,t){let n=$r(ai,e.__scopeDialog),{forceMount:r=n.forceMount,...i}=e,a=Yr(ai,e.__scopeDialog);return(0,A.jsx)(fn,{present:r||a.open,children:a.modal?(0,A.jsx)(si,{...i,ref:t}):(0,A.jsx)(ci,{...i,ref:t})})},`DialogContent`)),si=C.forwardRef(Wr(function(e,t){let n=Yr(ai,e.__scopeDialog),r=C.useRef(null),i=Fe(t,n.contentRef,r);return C.useEffect(()=>{let e=r.current;if(e)return Hr(e)},[]),(0,A.jsx)(li,{...e,ref:i,trapFocus:n.open,disableOutsidePointerEvents:n.open,onCloseAutoFocus:Ee(e.onCloseAutoFocus,e=>{e.preventDefault(),n.triggerRef.current?.focus()}),onPointerDownOutside:Ee(e.onPointerDownOutside,e=>{let t=e.detail.originalEvent,n=t.button===0&&t.ctrlKey===!0;(t.button===2||n)&&e.preventDefault()}),onFocusOutside:Ee(e.onFocusOutside,e=>e.preventDefault())})},`DialogContentModal`)),ci=C.forwardRef(Wr(function(e,t){let n=Yr(ai,e.__scopeDialog),r=C.useRef(!1),i=C.useRef(!1);return(0,A.jsx)(li,{...e,ref:t,trapFocus:!1,disableOutsidePointerEvents:!1,onCloseAutoFocus:t=>{e.onCloseAutoFocus?.(t),t.defaultPrevented||(r.current||n.triggerRef.current?.focus(),t.preventDefault()),r.current=!1,i.current=!1},onInteractOutside:t=>{e.onInteractOutside?.(t),t.defaultPrevented||(r.current=!0,t.detail.originalEvent.type===`pointerdown`&&(i.current=!0));let a=t.target;n.triggerRef.current?.contains(a)&&t.preventDefault(),t.detail.originalEvent.type===`focusin`&&i.current&&t.preventDefault()}})},`DialogContentNonModal`)),li=C.forwardRef(Wr(function(e,t){let{__scopeDialog:n,trapFocus:r,onOpenAutoFocus:i,onCloseAutoFocus:a,...o}=e,s=Yr(ai,n);return Cn(),(0,A.jsx)(A.Fragment,{children:(0,A.jsx)(Jt,{asChild:!0,loop:!0,trapped:r,onMountAutoFocus:i,onUnmountAutoFocus:a,children:(0,A.jsx)(It,{role:`dialog`,id:s.contentId,"aria-describedby":s.descriptionPresent?s.descriptionId:void 0,"aria-labelledby":s.titlePresent?s.titleId:void 0,"data-state":gi(s.open),...o,ref:t,deferPointerDownOutside:!0,onDismiss:()=>s.onOpenChange(!1)})})})},`DialogContentImpl`)),ui=`DialogTitle`,di=C.forwardRef(Wr(function(e,t){let{__scopeDialog:n,...r}=e,i=Yr(ui,n),{setTitleCount:a}=i;return He(()=>(a(e=>e+1),()=>a(e=>e-1)),[a]),(0,A.jsx)(Tt.h2,{id:i.titleId,...r,ref:t})},`DialogTitle`)),fi=`DialogDescription`,pi=C.forwardRef(Wr(function(e,t){let{__scopeDialog:n,...r}=e,i=Yr(fi,n),{setDescriptionCount:a}=i;return He(()=>(a(e=>e+1),()=>a(e=>e-1)),[a]),(0,A.jsx)(Tt.p,{id:i.descriptionId,...r,ref:t})},`DialogDescription`)),mi=`DialogClose`,hi=C.forwardRef(Wr(function(e,t){let{__scopeDialog:n,...r}=e,i=Yr(mi,n);return(0,A.jsx)(Tt.button,{type:`button`,...r,ref:t,onClick:Ee(e.onClick,()=>i.onOpenChange(!1))})},`DialogClose`));function gi(e){return e?`open`:`closed`}Wr(gi,`getState`);function _i(...e){return e.filter(Boolean).join(` `)}function vi({className:e,...t}){return(0,A.jsx)(`button`,{className:_i(`ui-button`,e),...t})}function yi({className:e,...t}){return(0,A.jsx)(`span`,{className:_i(`ui-badge`,e),...t})}function bi({open:e,onOpenChange:t,title:n,description:r,children:i}){return(0,A.jsx)(Xr,{open:e,onOpenChange:t,children:(0,A.jsxs)(ei,{children:[(0,A.jsx)(ni,{className:`sheet-overlay`}),(0,A.jsxs)(oi,{className:`sheet-content`,children:[(0,A.jsxs)(`div`,{className:`sheet-head`,children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(di,{children:n}),r?(0,A.jsx)(pi,{children:r}):null]}),(0,A.jsx)(hi,{asChild:!0,children:(0,A.jsx)(vi,{"aria-label":`关闭面板`,className:`icon-button`,children:(0,A.jsx)(me,{size:18})})})]}),i]})]})})}function xi({title:e,detail:t}){return(0,A.jsxs)(`div`,{className:`empty-state`,children:[(0,A.jsx)(`strong`,{children:e}),t?(0,A.jsx)(`p`,{children:t}):null]})}var Si=[`codex`,`claude`,`pi`],Ci={overview:`概览`,conversation:`对话`,configuration:`配置`,reminders:`提醒`,workspace:`工作区`,logs:`日志`},wi=window.__LARKIN_DASHBOARD__||{packageVersion:`dev`,dashboardVersion:`dev`,buildFingerprint:``,csrfCapability:``},Ti=class extends Error{body;constructor(e,t){super(e),this.body=t}};async function Ei(e,t={}){let n=await fetch(e,{cache:`no-store`,...t});if(!n.ok){let e=await n.json().catch(()=>({}));throw new Ti(e.error||`HTTP ${n.status}`,e)}return n.json()}function Di(e,t){if(!(e instanceof Ti)||!e.body.readiness)return e instanceof Error?e.message:t;let n=e.body.readiness;return[n.reason||e.message,n.nextAction?`下一步:${n.nextAction}`:null].filter(Boolean).join(`;`)}async function Oi(e){return Ei(`/api/config`,{method:`PATCH`,headers:{"Content-Type":`application/json`,"X-Larkin-CSRF":wi.csrfCapability},body:JSON.stringify(e)})}function ki(e,t={}){return Ei(e,{...t,headers:{...t.headers,"X-Larkin-CSRF":wi.csrfCapability}})}function Ai(e){return e==null||!Number.isFinite(e)?`暂无`:e<60?`${e}s 前`:e<3600?`${Math.floor(e/60)}m 前`:e<86400?`${Math.floor(e/3600)}h 前`:`${Math.floor(e/86400)}d 前`}function ji(e){let t=new Date(String(e||``));return Number.isFinite(t.getTime())?t.toLocaleString(`zh-CN`,{hour12:!1}):`未知时间`}function Mi(e){return Number.isFinite(Number(e))?Number(e).toLocaleString(`en-US`):`—`}function Ni(e){return e.issue?`异常`:e.lastActivity?.state?String(e.lastActivity.state):e.running?`空闲`:`离线`}function Pi(){let[e,t]=(0,C.useState)(null),[n,r]=(0,C.useState)(null),[i,a]=(0,C.useState)(!0),[o,s]=(0,C.useState)(!1),c=(0,C.useRef)(Se()),l=(0,C.useRef)(null),u=(0,C.useRef)(null),d=(0,C.useCallback)(async()=>{u.current?.abort();let e=new AbortController;u.current=e;let n=c.current.issue();try{let i=await Ei(`/api/status`,{signal:e.signal});if(!c.current.accepts(n))return;if(wi.buildFingerprint&&i.buildFingerprint&&i.buildFingerprint!==wi.buildFingerprint){window.location.reload();return}t(i),r(null),s(!1)}catch(t){if(e.signal.aborted||!c.current.accepts(n))return;r(t instanceof Error?t.message:String(t)),s(!0)}finally{c.current.accepts(n)&&a(!1)}},[]);return(0,C.useEffect)(()=>{let e=!0,t=async()=>{await d(),e&&(l.current=window.setTimeout(t,3e3))};return t(),()=>{e=!1,l.current!==null&&window.clearTimeout(l.current),u.current?.abort()}},[d]),{data:e,error:n,loading:i,stale:o,retry:d}}function Fi({agent:e}){let t=(e.displayName||e.name||e.agentId).slice(0,2).toUpperCase(),[n,r]=(0,C.useState)(!1);(0,C.useEffect)(()=>r(!1),[e.agentId,e.bot?.hasAvatar]);let i=e.bot?.hasAvatar&&!n;return(0,A.jsx)(`span`,{className:`agent-avatar`,"aria-hidden":`true`,children:i?(0,A.jsx)(`img`,{src:`/api/avatar/${encodeURIComponent(e.agentId)}`,alt:``,onError:()=>r(!0)}):t})}function Ii({agents:e,selectedId:t,onSelect:n,compact:r=!1}){let[i,a]=(0,C.useState)(``),o=(0,C.useMemo)(()=>be(e,i),[e,i]),s=(0,C.useRef)([]),c=(e,t)=>{if(!o.length)return;let n=t===0?e:(e+t+o.length)%o.length;s.current[n]?.focus()};return(0,A.jsxs)(`div`,{className:_i(`sidebar-inner`,r&&`compact-sidebar`),children:[(0,A.jsxs)(`label`,{className:`agent-search`,children:[(0,A.jsx)(de,{size:15,"aria-hidden":`true`}),(0,A.jsx)(`span`,{className:`sr-only`,children:`搜索 Agent`}),(0,A.jsx)(`input`,{value:i,onChange:e=>a(e.target.value),placeholder:`搜索 Agent…`})]}),(0,A.jsxs)(`div`,{className:`agent-list`,role:`listbox`,"aria-label":`Agent 列表`,children:[o.map((e,r)=>(0,A.jsxs)(`button`,{ref:e=>{s.current[r]=e},type:`button`,role:`option`,"aria-selected":e.agentId===t,className:_i(`agent-list-item`,e.agentId===t&&`selected`),onClick:()=>n(e.agentId),onKeyDown:e=>{e.key===`ArrowDown`&&(e.preventDefault(),c(r,1)),e.key===`ArrowUp`&&(e.preventDefault(),c(r,-1)),e.key===`Home`&&(e.preventDefault(),c(0,0)),e.key===`End`&&(e.preventDefault(),c(o.length-1,0))},children:[(0,A.jsx)(Fi,{agent:e}),(0,A.jsxs)(`span`,{className:`agent-list-copy`,children:[(0,A.jsx)(`strong`,{children:e.displayName||e.name}),(0,A.jsxs)(`small`,{children:[e.runtime,` · `,e.model,e.runtimeReadiness?` · ${e.runtimeReadiness.state}`:``]}),(0,A.jsxs)(`span`,{className:`status-line`,children:[(0,A.jsx)(ie,{size:10}),` `,e.connection.state,` · `,Ni(e)]})]}),e.issue?(0,A.jsx)(k,{size:15,className:`danger`,"aria-label":`异常`}):(0,A.jsx)(re,{size:15,"aria-hidden":`true`})]},e.agentId)),o.length?null:(0,A.jsx)(xi,{title:`没有匹配的 Agent`,detail:`可按名称或 App ID 搜索`})]})]})}function Li({open:e,onOpenChange:t,onSaved:n}){let[r,i]=(0,C.useState)(`require`),[a,o]=(0,C.useState)(`require`),[s,c]=(0,C.useState)(!1),[l,u]=(0,C.useState)(null),d=a!==r;return(0,C.useEffect)(()=>{if(!e)return;let t=new AbortController;return c(!0),ki(`/api/config`,{signal:t.signal}).then(e=>{i(e.mentionPolicy),o(e.mentionPolicy),u(null)}).catch(e=>{t.signal.aborted||u(e.message)}).finally(()=>{t.signal.aborted||c(!1)}),()=>t.abort()},[e]),(0,A.jsx)(bi,{open:e,onOpenChange:e=>{!e&&d&&!window.confirm(`全局设置尚未保存,确定放弃草稿吗?`)||t(e)},title:`全局设置`,description:`只管理所有 Agent 共同继承的默认值;高级操作仍使用 CLI。`,children:(0,A.jsxs)(`div`,{className:`settings-form`,children:[(0,A.jsxs)(`label`,{children:[(0,A.jsx)(`span`,{children:`真人群消息默认策略`}),(0,A.jsxs)(`select`,{value:a,onChange:e=>o(e.target.value),disabled:s,children:[(0,A.jsx)(`option`,{value:`require`,children:`require · 群内需要 @`}),(0,A.jsx)(`option`,{value:`free`,children:`free · 群内无需 @`})]})]}),(0,A.jsx)(`p`,{className:`field-help`,children:`未单独设置的 Agent 和群会使用这个值。机器人消息仍必须精确 @ 当前 Agent。`}),(0,A.jsxs)(`div`,{className:`form-actions`,children:[(0,A.jsx)(vi,{onClick:()=>o(r),disabled:!d||s,children:`放弃草稿`}),(0,A.jsx)(vi,{className:`primary`,onClick:async()=>{c(!0);try{let e=await Oi({operation:`set-global-mention`,value:a});i(a),u(`已保存 · ${e.applyState} · ${e.revision.slice(0,20)}…`),n()}catch(e){u(e instanceof Error?e.message:String(e))}finally{c(!1)}},disabled:!d||s,children:s?`保存中…`:`保存全局设置`})]}),l?(0,A.jsx)(`p`,{role:`status`,className:`feedback`,children:l}):null]})})}function Ri({config:e,onSave:t,disabled:n}){let[r,i]=(0,C.useState)(``),[a,o]=(0,C.useState)(``),[s,c]=(0,C.useState)(`require`),l=e.knownChats.filter(e=>e.kind===`group`&&e.override!==`inherit`).filter(e=>{let t=r.trim().toLocaleLowerCase();return!t||e.chatId.toLocaleLowerCase().includes(t)||String(e.displayName||`未解析群名`).toLocaleLowerCase().includes(t)});return(0,A.jsxs)(`section`,{className:`group-policy-section`,"aria-labelledby":`group-policy-title`,children:[(0,A.jsxs)(`div`,{className:`section-heading`,children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`h3`,{id:`group-policy-title`,children:`群策略`}),(0,A.jsx)(`p`,{children:`这里只显示为当前 Agent 单独设置过消息策略的群。`})]}),(0,A.jsxs)(`label`,{className:`table-search`,children:[(0,A.jsx)(de,{size:14}),(0,A.jsx)(`span`,{className:`sr-only`,children:`搜索群`}),(0,A.jsx)(`input`,{value:r,onChange:e=>i(e.target.value),placeholder:`搜索群名或 chat_id`})]})]}),(0,A.jsxs)(`div`,{className:`policy-table-wrap`,children:[(0,A.jsxs)(`table`,{className:`policy-table`,children:[(0,A.jsx)(`thead`,{children:(0,A.jsxs)(`tr`,{children:[(0,A.jsx)(`th`,{children:`群`}),(0,A.jsx)(`th`,{children:`消息策略`}),(0,A.jsx)(`th`,{children:`操作`})]})}),(0,A.jsx)(`tbody`,{children:l.map(e=>(0,A.jsxs)(`tr`,{children:[(0,A.jsxs)(`td`,{children:[(0,A.jsx)(`strong`,{children:e.displayName||e.chatId}),e.displayName?(0,A.jsx)(`code`,{children:e.chatId}):(0,A.jsx)(`small`,{children:`群名暂时不可用`})]}),(0,A.jsx)(`td`,{children:(0,A.jsxs)(`select`,{"aria-label":`${e.displayName||e.chatId} 消息策略`,value:e.override,disabled:n,onChange:n=>void t(e.chatId,n.target.value),children:[(0,A.jsx)(`option`,{value:`require`,children:`需要 @`}),(0,A.jsx)(`option`,{value:`free`,children:`无需 @`})]})}),(0,A.jsx)(`td`,{children:(0,A.jsx)(vi,{disabled:n,onClick:()=>void t(e.chatId,`inherit`),children:`移除特别配置`})})]},e.chatId))})]}),l.length?null:(0,A.jsx)(xi,{title:r?`没有匹配的群`:`还没有单独配置的群`,detail:`新增后,Larkin 会自动解析并缓存群名。`})]}),(0,A.jsxs)(`div`,{className:`chat-add`,children:[(0,A.jsxs)(`label`,{children:[(0,A.jsx)(`span`,{children:`完整 chat_id`}),(0,A.jsx)(`input`,{value:a,onChange:e=>o(e.target.value),placeholder:`oc_QAConfigChat1`})]}),(0,A.jsxs)(`label`,{children:[(0,A.jsx)(`span`,{children:`消息策略`}),(0,A.jsxs)(`select`,{value:s,onChange:e=>c(e.target.value),children:[(0,A.jsx)(`option`,{value:`require`,children:`需要 @`}),(0,A.jsx)(`option`,{value:`free`,children:`无需 @`})]})]}),(0,A.jsx)(vi,{disabled:n||!/^oc_[A-Za-z0-9_-]+$/.test(a),onClick:()=>void t(a,s).then(()=>o(``)),children:`保存群策略`})]})]})}function zi(e){return[`Readiness ${e.state}`,e.reason,e.nextAction].filter(Boolean).join(` · `)}function Bi({agentId:e,readiness:t,onDirtyChange:n,refreshKey:r}){let[i,a]=(0,C.useState)(null),[o,s]=(0,C.useState)({}),[c,l]=(0,C.useState)({}),[u,d]=(0,C.useState)(!0),[f,p]=(0,C.useState)(null),[m,h]=(0,C.useState)(null),g=(0,C.useRef)(Se()),_=(0,C.useRef)(Se()),v=!xe(o,c);(0,C.useEffect)(()=>n(v),[v,n]),(0,C.useEffect)(()=>{let e=e=>{v&&e.preventDefault()};return window.addEventListener(`beforeunload`,e),()=>window.removeEventListener(`beforeunload`,e)},[v]);let y=(0,C.useCallback)(async(t=!1)=>{let n=g.current.issue();d(!0);try{let r=await ki(`/api/config?agent=${encodeURIComponent(e)}`);if(!g.current.accepts(n))return;let i=r.agents[0];if(!i)throw Error(`配置投影中没有当前 Agent`);let o={runtime:i.runtimeOption||i.runtime,model:i.model,effort:i.effort||`default`,mention:i.mention.override};a(r),s(o),(!t||!v)&&l(o)}catch(e){g.current.accepts(n)&&p(e instanceof Error?e.message:String(e))}finally{g.current.accepts(n)&&d(!1)}},[e,v]);(0,C.useEffect)(()=>{y(!1)},[e]),(0,C.useEffect)(()=>{r>0&&y(!0)},[r]);let b=i?.agents[0],x=(e,t)=>l(n=>({...n,[e]:t})),S=String(c.runtime||b?.runtime||``),w=String(c.model||b?.model||`default`);(0,C.useEffect)(()=>{if(h({runtime:S,status:`loading`,models:[]}),!Si.includes(S)){h({runtime:S,status:`error`,models:[]});return}let t=_.current.issue(),n=new AbortController;return ki(`/api/models/${S}?agent=${encodeURIComponent(e)}`,{signal:n.signal}).then(e=>{_.current.accepts(t)&&h({runtime:S,status:`ready`,models:e.models})}).catch(e=>{!n.signal.aborted&&_.current.accepts(t)&&(h({runtime:S,status:`error`,models:[]}),p(`${S} 模型列表暂时不可用:${e instanceof Error?e.message:String(e)}`))}),()=>n.abort()},[e,S]);let ee=m?.runtime===S&&m.status===`ready`,te=m?.runtime===S?m.status:`loading`,T=ee?m.models:[],E=`${w} · 当前配置(模型目录${te===`error`?`不可用`:`加载中`})`,ne=ee?T.some(e=>e.id===w)?T:[{id:w,label:`${w} · 当前配置`},...T]:[{id:w,label:E}],re=ee&&w!=="default"&&T.find(e=>e.id===w)?.supportedReasoningEfforts||[],ie=c.runtime!==o.runtime||c.model!==o.model||c.effort!==o.effort,ae=()=>Ei(`/api/config/apply`,{method:`POST`,headers:{"Content-Type":`application/json`,"X-Larkin-CSRF":wi.csrfCapability},body:JSON.stringify({agentId:e})}),oe=async()=>{if(b){d(!0);try{let t=[];c.runtime===o.runtime?c.model!==o.model&&t.push({operation:`set-agent-model`,agentId:e,model:c.model}):t.push({operation:`set-agent-runtime`,agentId:e,runtime:c.runtime,model:c.model}),c.effort!==o.effort&&t.push({operation:`set-agent-effort`,agentId:e,effort:c.effort}),c.mention!==o.mention&&t.push({operation:`set-agent-mention`,agentId:e,value:c.mention});let n=null;for(let e of t)n=await Oi(e);if(ie)try{await ae(),p(`配置已保存并应用`)}catch(e){p(`配置已保存但未应用:${Di(e,`稍后重试`)}`)}else p(n?`配置已保存`:`没有需要保存的修改`);await y(!1)}catch(e){p(Di(e,e instanceof Error?e.message:String(e)))}finally{d(!1)}}},se=async()=>{d(!0);try{await ae(),p(`已应用保存的运行配置`),await y(!0)}catch(e){p(`配置保持已保存但未应用:${Di(e,`稍后重试`)}`)}finally{d(!1)}},ce=async(t,n)=>{d(!0);try{let r=await Oi({operation:`set-chat-mention`,agentId:e,chatId:t,value:n});p(`群策略已保存 · ${r.applyState}`),await y(!0)}catch(e){p(e instanceof Error?e.message:String(e))}finally{d(!1)}};if(!b&&u)return(0,A.jsx)(xi,{title:`加载 Agent 配置…`});if(!b)return(0,A.jsx)(xi,{title:`配置不可用`,detail:f||`请重试`});let D=b.apply.applyState===`pending`?`待应用`:b.apply.applyState===`applied`?`已应用`:`状态未知`;return(0,A.jsxs)(`div`,{className:`configuration-page`,children:[(0,A.jsxs)(`section`,{className:`config-section`,children:[(0,A.jsxs)(`div`,{className:`section-heading`,children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`h3`,{children:`Agent 配置`}),(0,A.jsxs)(`p`,{children:[`只作用于 `,e,`;运行配置会在安全时机自动应用,Agent 正忙时会保留待处理。`]})]}),(0,A.jsx)(yi,{className:b.apply.applyState===`pending`?`warning`:`success`,children:D})]}),(0,A.jsxs)(`p`,{className:`cli-guidance`,children:[`这里只提供常用微调。更多配置可以直接告诉当前 Agent,让它运行 `,(0,A.jsx)(`code`,{children:`larkin config --help`}),` 后完成。`]}),t?(0,A.jsx)(`p`,{className:`field-help`,children:zi(t)}):null,(0,A.jsxs)(`div`,{className:`config-grid`,children:[(0,A.jsxs)(`label`,{children:[(0,A.jsx)(`span`,{children:`Runtime`}),(0,A.jsx)(`select`,{value:S,disabled:u,onChange:e=>{x(`runtime`,e.target.value),x(`model`,`default`),x(`effort`,`default`)},children:(i?.runtimeOptions||Si).map(e=>(0,A.jsx)(`option`,{value:e,children:e},e))})]}),(0,A.jsxs)(`label`,{children:[(0,A.jsx)(`span`,{children:`Model`}),(0,A.jsx)(`select`,{value:w,disabled:u||!ee,onChange:e=>{x(`model`,e.target.value),e.target.value==="default"&&x(`effort`,`default`)},children:ne.map(e=>(0,A.jsx)(`option`,{value:e.id,children:e.label||e.id},e.id))})]}),(0,A.jsxs)(`label`,{children:[(0,A.jsx)(`span`,{children:`Effort`}),(0,A.jsxs)(`select`,{value:String(c.effort||`default`),disabled:u||!ee||w==="default"||!re.length,onChange:e=>x(`effort`,e.target.value),children:[(0,A.jsx)(`option`,{value:`default`,children:`default · 不指定`}),re.map(e=>(0,A.jsx)(`option`,{value:e,children:e},e))]})]}),(0,A.jsxs)(`label`,{children:[(0,A.jsx)(`span`,{children:`群消息策略`}),(0,A.jsxs)(`select`,{value:String(c.mention||`inherit`),disabled:u,onChange:e=>x(`mention`,e.target.value),children:[(0,A.jsx)(`option`,{value:`inherit`,children:`跟随全局设置`}),(0,A.jsx)(`option`,{value:`require`,children:`需要 @`}),(0,A.jsx)(`option`,{value:`free`,children:`无需 @`})]})]})]}),v||b.apply.applyState===`pending`?(0,A.jsxs)(`div`,{className:`form-actions`,children:[v?(0,A.jsx)(vi,{disabled:u,onClick:()=>l(o),children:`放弃草稿`}):null,v?(0,A.jsx)(vi,{className:`primary`,disabled:u,onClick:oe,children:u?`处理中…`:ie?`保存并应用`:`保存 Agent 配置`}):(0,A.jsxs)(vi,{className:`primary`,disabled:u,onClick:se,children:[(0,A.jsx)(ue,{size:14}),` 应用已保存配置`]})]}):null,f?(0,A.jsx)(`p`,{role:`status`,className:`feedback`,children:f}):null]}),(0,A.jsx)(Ri,{config:b,onSave:ce,disabled:u})]})}function M({agent:e}){let t=e.session?.usage||{},n=e.session?.compaction||{};return(0,A.jsxs)(`div`,{className:`overview-page`,children:[(0,A.jsxs)(`div`,{className:`metrics-band`,"aria-label":`Agent 运行指标`,children:[(0,A.jsxs)(`section`,{className:`metric-stat`,children:[(0,A.jsx)(`div`,{className:`metric-icon`,children:(0,A.jsx)(ie,{})}),(0,A.jsx)(`span`,{children:`连接`}),(0,A.jsx)(`strong`,{children:e.connection.state}),(0,A.jsx)(`small`,{children:e.connection.reason})]}),(0,A.jsxs)(`section`,{className:`metric-stat`,children:[(0,A.jsx)(`div`,{className:`metric-icon`,children:(0,A.jsx)(E,{})}),(0,A.jsx)(`span`,{children:`执行状态`}),(0,A.jsx)(`strong`,{children:Ni(e)}),(0,A.jsx)(`small`,{children:e.lastActivity?Ai(e.lastActivity.ageSec):`尚无活动`})]}),(0,A.jsxs)(`section`,{className:`metric-stat`,children:[(0,A.jsx)(`div`,{className:`metric-icon`,children:(0,A.jsx)(le,{})}),(0,A.jsx)(`span`,{children:`最近消息`}),(0,A.jsx)(`strong`,{children:e.lastDeliver?.from||`暂无`}),(0,A.jsx)(`small`,{children:e.lastDeliver?`${e.lastDeliver.target||``} · ${Ai(e.lastDeliver.ageSec)}`:`尚无消息记录`})]}),(0,A.jsxs)(`section`,{className:`metric-stat`,children:[(0,A.jsx)(`div`,{className:`metric-icon`,children:(0,A.jsx)(ce,{})}),(0,A.jsx)(`span`,{children:`上下文`}),(0,A.jsx)(`strong`,{children:t.contextPercent==null?`${e.session?.turns||0} turns`:`${Math.round(Number(t.contextPercent))}%`}),(0,A.jsx)(`small`,{children:e.session?`session ${e.session.id.slice(0,12)}…`:`尚未建立 session`})]}),(0,A.jsxs)(`section`,{className:`metric-stat`,children:[(0,A.jsx)(`div`,{className:`metric-icon`,children:(0,A.jsx)(ce,{})}),(0,A.jsx)(`span`,{children:`累计 Token`}),(0,A.jsx)(`strong`,{children:Mi(t.cumulativeTokens)}),(0,A.jsx)(`small`,{children:t.available?`完整 session 累计`:t.reason||`暂无用量`})]}),(0,A.jsxs)(`section`,{className:`metric-stat`,children:[(0,A.jsx)(`div`,{className:`metric-icon`,children:(0,A.jsx)(E,{})}),(0,A.jsx)(`span`,{children:`最近一轮用量`}),(0,A.jsx)(`strong`,{children:Mi(t.latestTokens)}),(0,A.jsx)(`small`,{children:`输入、缓存与输出合计`})]}),(0,A.jsxs)(`section`,{className:`metric-stat`,children:[(0,A.jsx)(`div`,{className:`metric-icon`,children:(0,A.jsx)(ue,{})}),(0,A.jsx)(`span`,{children:`Compaction`}),(0,A.jsx)(`strong`,{children:Mi(n.count)}),(0,A.jsx)(`small`,{children:n.active?`正在压缩上下文`:n.lastFinishedAt?`最近 ${ji(n.lastFinishedAt)}`:`尚无压缩记录`})]})]}),(0,A.jsxs)(`div`,{className:`overview-sections`,children:[(0,A.jsxs)(`section`,{className:`content-section wide`,children:[(0,A.jsxs)(`div`,{className:`section-heading`,children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`h3`,{children:`最近动态`}),(0,A.jsx)(`p`,{children:`当前 Agent 的消息、工具和状态转换。`})]}),(0,A.jsx)(yi,{children:e.feed.length})]}),(0,A.jsx)(N,{items:e.feed.slice(0,10)})]}),(0,A.jsxs)(`section`,{className:`content-section`,children:[(0,A.jsx)(`h3`,{children:`运行摘要`}),(0,A.jsxs)(`dl`,{className:`facts`,children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`dt`,{children:`Runtime`}),(0,A.jsx)(`dd`,{children:e.runtime})]}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`dt`,{children:`Readiness`}),(0,A.jsx)(`dd`,{children:e.runtimeReadiness?`${e.runtimeReadiness.state}${e.runtimeReadiness.version?` · ${e.runtimeReadiness.version}`:``}${e.runtimeReadiness.executable?` · ${e.runtimeReadiness.executable}`:``}${e.runtimeReadiness.reason?` · ${e.runtimeReadiness.reason}`:``}${e.runtimeReadiness.nextAction?` · ${e.runtimeReadiness.nextAction}`:``}`:`unknown`})]}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`dt`,{children:`Model`}),(0,A.jsx)(`dd`,{children:e.model})]}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`dt`,{children:`Effort`}),(0,A.jsx)(`dd`,{children:e.effort||`default`})]}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`dt`,{children:`入站`}),(0,A.jsx)(`dd`,{children:e.inbound.state})]}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`dt`,{children:`提醒`}),(0,A.jsx)(`dd`,{children:e.activeReminders})]}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`dt`,{children:`指示灯`}),(0,A.jsx)(`dd`,{children:e.eyeIndicator.stuck?`疑似卡住`:`${e.eyeIndicator.pendingCount} pending`})]})]})]})]})]})}function N({items:e}){if(!e.length)return(0,A.jsx)(xi,{title:`还没有活动记录`});let t=e=>e.kind===`error`||e.state===`error`?`state-error`:e.kind===`deliver`?`state-deliver`:[`working`,`thinking`,`tool`].includes(String(e.state))?`state-active`:[`idle`,`online`].includes(String(e.state))?`state-idle`:`state-unknown`;return(0,A.jsx)(`ol`,{className:`timeline`,children:e.map((e,n)=>(0,A.jsxs)(`li`,{children:[(0,A.jsx)(`span`,{className:_i(`timeline-dot`,t(e))}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`strong`,{children:e.kind===`deliver`?`收到消息`:e.kind===`error`?`错误`:e.state||`活动`}),(0,A.jsx)(`p`,{children:e.text||e.detail||[e.from,e.target].filter(Boolean).join(` → `)||e.tool||`状态已更新`}),(0,A.jsx)(`time`,{children:ji(e.at)})]})]},`${e.at}-${n}`))})}function Vi({agent:e}){return e.conversation.length?(0,A.jsx)(`div`,{className:`conversation-list`,children:e.conversation.map((t,n)=>{let r=t.direction===`out`?`已发送`:t.wake?`入站 · 已唤醒`:`旁听 · 未唤醒`;return(0,A.jsxs)(`article`,{className:_i(`conversation-item`,t.direction===`out`?`outbound`:`inbound`,t.direction===`in`&&!t.wake&&`listening`),children:[(0,A.jsxs)(`header`,{children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(yi,{className:t.direction===`in`&&!t.wake?`warning`:t.direction===`out`?`accent`:`success`,children:r}),(0,A.jsx)(`strong`,{children:t.from||(t.direction===`out`?e.displayName:`未知发送者`)})]}),(0,A.jsx)(`time`,{children:ji(t.at)})]}),(0,A.jsx)(`p`,{children:t.text||`[非文本消息]`}),t.target?(0,A.jsx)(`small`,{children:t.target}):null]},`${t.at}-${n}`)})}):(0,A.jsx)(xi,{title:`还没有对话摘录`,detail:`Host 更新本地 conversation projection 后会显示在这里。`})}function Hi({agent:e}){if(!e.remindersList.length)return(0,A.jsx)(xi,{title:`还没有提醒`});let t={scheduled:`待执行`,pending:`待执行`,fired:`已完成`,canceled:`已取消`,cancelled:`已取消`,failed:`失败`};return(0,A.jsx)(`div`,{className:`reminder-list`,children:e.remindersList.map((e,n)=>{let r=e.status||`scheduled`,i=[`fired`,`canceled`,`cancelled`].includes(r);return(0,A.jsxs)(`article`,{className:_i(`status-${r===`cancelled`?`canceled`:r}`,i&&`done`),children:[(0,A.jsx)(ne,{size:16}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`strong`,{children:e.title||`未命名提醒`}),(0,A.jsxs)(`p`,{children:[ji(e.fireAt),e.repeat?` · 重复`:``]})]}),(0,A.jsx)(yi,{className:[`scheduled`,`pending`].includes(r)?`warning`:r===`fired`?`success`:r===`failed`?`danger-badge`:``,children:t[r]||r})]},`${e.fireAt}-${n}`)})})}function Ui({agentId:e}){let[t,n]=(0,C.useState)(null),[r,i]=(0,C.useState)(null),[a,o]=(0,C.useState)(!0),[s,c]=(0,C.useState)(null),l=(0,C.useRef)(Se()),u=(0,C.useCallback)(async t=>{let r=l.current.issue();o(!0);try{let a=await Ei(`/api/workspace?agent=${encodeURIComponent(e)}&path=${encodeURIComponent(t)}`);if(!l.current.accepts(r))return;a.kind===`directory`?(n(a),i(null)):i(a),c(null)}catch(e){l.current.accepts(r)&&c(e instanceof Error?e.message:String(e))}finally{l.current.accepts(r)&&o(!1)}},[e]);(0,C.useEffect)(()=>{u(``)},[u]);let d=t?.path.split(`/`).filter(Boolean)||[];return(0,A.jsxs)(`div`,{className:`workspace-browser`,children:[(0,A.jsxs)(`div`,{className:`workspace-side`,children:[(0,A.jsxs)(`nav`,{className:`breadcrumbs`,"aria-label":`工作区路径`,children:[(0,A.jsx)(`button`,{onClick:()=>void u(``),children:`workspace`}),d.map((e,t)=>(0,A.jsxs)(`span`,{children:[(0,A.jsx)(re,{size:12}),(0,A.jsx)(`button`,{onClick:()=>void u(d.slice(0,t+1).join(`/`)),children:e})]},`${e}-${t}`))]}),(0,A.jsxs)(`div`,{className:`workspace-list`,role:`region`,"aria-label":`工作区目录`,children:[t?.entries.map(e=>(0,A.jsxs)(`button`,{onClick:()=>void u(e.path),children:[e.kind===`directory`?(0,A.jsx)(se,{size:15}):(0,A.jsx)(oe,{size:15}),(0,A.jsx)(`span`,{children:e.name}),(0,A.jsx)(`small`,{children:e.kind===`file`?`${e.size} B`:`目录`})]},e.path)),!a&&t&&!t.entries.length?(0,A.jsx)(xi,{title:`空目录`}):null]})]}),(0,A.jsx)(`div`,{className:`workspace-preview`,role:`region`,"aria-label":`文件预览`,children:a?(0,A.jsx)(xi,{title:`读取工作区…`}):s?(0,A.jsx)(xi,{title:`工作区读取失败`,detail:s}):r?(0,A.jsxs)(A.Fragment,{children:[(0,A.jsxs)(`header`,{children:[(0,A.jsx)(`strong`,{children:r.name}),(0,A.jsx)(`small`,{children:r.truncated?`仅预览前 1 MB`:`${r.size} B`})]}),r.binary?(0,A.jsx)(xi,{title:`二进制文件不可预览`}):(0,A.jsx)(`pre`,{children:r.content})]}):(0,A.jsx)(xi,{title:`只读工作区`,detail:`选择文件进行预览`})})]})}function Wi({agent:e}){return(0,A.jsxs)(`section`,{className:`logs-section`,children:[(0,A.jsxs)(`div`,{className:`section-heading`,children:[(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`h3`,{children:`结构化日志`}),(0,A.jsx)(`p`,{children:`最近 30 条本地状态投影;不暴露原始日志文件或路径。`})]}),(0,A.jsx)(yi,{children:e.feed.length})]}),(0,A.jsx)(N,{items:e.feed}),e.recentErrors.length?(0,A.jsxs)(`section`,{className:`error-stack`,children:[(0,A.jsx)(`h4`,{children:`最近错误`}),e.recentErrors.map((e,t)=>(0,A.jsxs)(`div`,{children:[(0,A.jsx)(ae,{size:14}),(0,A.jsx)(`span`,{children:e.text||e.message||`未知错误`}),(0,A.jsx)(`time`,{children:ji(e.at)})]},`${e.at}-${t}`))]}):null]})}function Gi({agent:e}){let t=e.session?.usage||{},n=e.session?.compaction||{},r=t.contextPercent==null?`上下文 ${e.session?.turns||0} turns`:`上下文 ${Math.round(Number(t.contextPercent))}% · ${Mi(t.latestTokens)} / ${Mi(t.contextWindow)}`;return(0,A.jsxs)(`header`,{className:`agent-header`,children:[(0,A.jsxs)(`div`,{className:`agent-title`,children:[(0,A.jsx)(Fi,{agent:e}),(0,A.jsxs)(`div`,{children:[(0,A.jsx)(`p`,{children:e.agentId}),(0,A.jsx)(`h1`,{children:e.displayName||e.name})]})]}),(0,A.jsxs)(`div`,{className:`agent-header-summary`,children:[(0,A.jsx)(yi,{className:e.connection.state===`connected`?`success`:e.issue?`danger-badge`:``,children:e.connection.state}),(0,A.jsx)(`span`,{children:e.runtime}),(0,A.jsx)(`span`,{children:e.model}),(0,A.jsx)(`span`,{children:e.effort||`default effort`}),(0,A.jsx)(`span`,{children:r}),(0,A.jsxs)(`span`,{children:[`累计 `,Mi(t.cumulativeTokens),` tokens`]}),(0,A.jsxs)(`span`,{children:[`最近一轮 `,Mi(t.latestTokens),` tokens`]}),(0,A.jsxs)(`span`,{children:[`Compact `,Mi(n.count),` 次 · `,n.active?`active`:`idle`]}),(0,A.jsxs)(`span`,{children:[`最近消息 `,e.lastDeliver?Ai(e.lastDeliver.ageSec):`暂无`]}),(0,A.jsx)(`span`,{children:e.lastActivity?.detail||Ni(e)})]})]})}function Ki(){let e=Pi(),t=(0,C.useMemo)(()=>_e(window.location.search),[]),[n,r]=(0,C.useState)(t.agentId),[i,a]=(0,C.useState)(t.tab),[o,s]=(0,C.useState)(!1),[c,l]=(0,C.useState)(!1),[u,d]=(0,C.useState)(0),[f,p]=(0,C.useState)(!1),[m,h]=(0,C.useState)(null),g=(0,C.useRef)(new Map),_=e.data?.agents||[],v=e.data?.packageVersion||wi.packageVersion,y=_.find(e=>e.agentId===n)||null,b=(0,C.useCallback)((e,t)=>{let n=`${e}:${t}`,r=window.scrollY;g.current.set(n,r);try{sessionStorage.setItem(`larkin-dashboard-scroll:${n}`,String(r))}catch{}},[]),x=(0,C.useCallback)(e=>{if(g.current.has(e))return g.current.get(e)||0;try{let t=Number(sessionStorage.getItem(`larkin-dashboard-scroll:${e}`));return Number.isFinite(t)&&t>=0?t:0}catch{return 0}},[]),S=(0,C.useCallback)((e,t,o=!1)=>{n&&b(n,i);let s=o?`replaceState`:`pushState`;window.history[s](null,``,ve(e,t)),r(e),a(t)},[b,n,i]),w=()=>!f||window.confirm(`Agent 配置尚未保存,确定放弃草稿吗?`),ee=e=>{w()&&(p(!1),S(e,i),l(!1))},te=e=>{e!==`configuration`&&!w()||(e!==`configuration`&&p(!1),S(n,e))};return(0,C.useEffect)(()=>{if(!e.data)return;let t=ye(n,e.data.agents);t!==n&&(h(n?`原 Agent 已不存在,已切换到第一个可用 Agent。`:null),S(t,i,!0))},[e.data,n,i,S]),(0,C.useEffect)(()=>{let e=()=>{let e=_e(window.location.search);if(f&&!window.confirm(`Agent 配置尚未保存,确定离开吗?`)){window.history.pushState(null,``,ve(n,i));return}n&&b(n,i),p(!1),r(e.agentId),a(e.tab)};return window.addEventListener(`popstate`,e),()=>window.removeEventListener(`popstate`,e)},[f,b,n,i]),(0,C.useLayoutEffect)(()=>{if(!n)return;let e=`${n}:${i}`,t=x(e);window.scrollY!==t&&window.scrollTo({top:t,behavior:`auto`})},[x,n,i]),(0,A.jsxs)(`div`,{className:_i(`app-shell`,i===`workspace`&&`workspace-app-active`),children:[(0,A.jsxs)(`aside`,{className:`desktop-sidebar`,children:[(0,A.jsxs)(`div`,{className:`brand`,children:[(0,A.jsx)(`img`,{src:`/assets/larkin-mark.svg`,alt:``}),(0,A.jsxs)(`strong`,{children:[`Larkin `,(0,A.jsxs)(`span`,{className:`brand-version`,children:[`v`,v]})]})]}),(0,A.jsx)(Ii,{agents:_,selectedId:n,onSelect:ee}),(0,A.jsx)(`footer`,{children:e.data?.daemon.running?`${_.length} Agents · daemon online`:`daemon offline`})]}),(0,A.jsxs)(`main`,{className:_i(`workspace-shell`,i===`workspace`&&`workspace-route-active`),children:[(0,A.jsxs)(`div`,{className:`app-topbar`,children:[(0,A.jsx)(vi,{className:`mobile-menu`,"aria-label":`打开 Agent 导航`,onClick:()=>l(!0),children:(0,A.jsx)(O,{size:18})}),(0,A.jsxs)(`div`,{children:[(0,A.jsxs)(`strong`,{children:[`Larkin `,(0,A.jsxs)(`span`,{className:`brand-version`,children:[`v`,v]})]}),(0,A.jsx)(`span`,{children:e.data?.daemon.running?`运行中`:`未运行`}),e.stale?(0,A.jsx)(yi,{className:`warning`,children:`状态陈旧`}):null]}),(0,A.jsxs)(vi,{onClick:()=>s(!0),children:[(0,A.jsx)(fe,{size:15}),` 全局设置`]})]}),e.error?(0,A.jsxs)(`div`,{className:`stale-banner`,role:`alert`,children:[(0,A.jsx)(k,{size:15}),`状态刷新失败,保留最后一次数据:`,e.error,(0,A.jsx)(vi,{onClick:()=>void e.retry(),children:`重试`})]}):null,m?(0,A.jsxs)(`div`,{className:`notice`,role:`status`,children:[m,(0,A.jsx)(vi,{"aria-label":`关闭提示`,onClick:()=>h(null),children:`×`})]}):null,e.loading&&!e.data?(0,A.jsxs)(`div`,{className:`page-loading`,children:[(0,A.jsx)(ue,{className:`spin`}),`加载 Agent 工作台…`]}):y?(0,A.jsxs)(A.Fragment,{children:[(0,A.jsx)(Gi,{agent:y}),(0,A.jsx)(`nav`,{className:`agent-tabs`,"aria-label":`${y.displayName} 内容页签`,role:`tablist`,children:ge.map(e=>(0,A.jsxs)(`button`,{type:`button`,role:`tab`,"aria-selected":i===e,className:i===e?`active`:``,onClick:()=>te(e),children:[e===`overview`?(0,A.jsx)(ce,{}):e===`conversation`?(0,A.jsx)(le,{}):e===`configuration`?(0,A.jsx)(pe,{}):e===`reminders`?(0,A.jsx)(ne,{}):e===`workspace`?(0,A.jsx)(se,{}):(0,A.jsx)(D,{}),Ci[e]]},e))}),(0,A.jsxs)(`div`,{className:_i(`agent-content`,i===`workspace`&&`workspace-active`),children:[(0,A.jsx)(`section`,{role:`tabpanel`,hidden:i!==`overview`,children:(0,A.jsx)(M,{agent:y})}),(0,A.jsx)(`section`,{role:`tabpanel`,hidden:i!==`conversation`,children:(0,A.jsx)(Vi,{agent:y})}),(0,A.jsx)(`section`,{role:`tabpanel`,hidden:i!==`configuration`,children:(0,A.jsx)(Bi,{agentId:y.agentId,readiness:y.runtimeReadiness??null,onDirtyChange:p,refreshKey:u})}),(0,A.jsx)(`section`,{role:`tabpanel`,hidden:i!==`reminders`,children:(0,A.jsx)(Hi,{agent:y})}),(0,A.jsx)(`section`,{className:`workspace-tab-panel`,role:`tabpanel`,hidden:i!==`workspace`,children:(0,A.jsx)(Ui,{agentId:y.agentId})}),(0,A.jsx)(`section`,{role:`tabpanel`,hidden:i!==`logs`,children:(0,A.jsx)(Wi,{agent:y})})]},y.agentId)]}):(0,A.jsx)(xi,{title:`还没有配置任何 Agent`,detail:`先运行 larkin setup。`})]}),(0,A.jsx)(Li,{open:o,onOpenChange:s,onSaved:()=>d(e=>e+1)}),(0,A.jsx)(bi,{open:c,onOpenChange:l,title:`选择 Agent`,description:`搜索、查看状态并切换当前工作区。`,children:(0,A.jsx)(Ii,{compact:!0,agents:_,selectedId:n,onSelect:ee})})]})}var qi=document.getElementById(`root`);if(!qi)throw Error(`dashboard root is missing`);(0,he.createRoot)(qi).render((0,A.jsx)(C.StrictMode,{children:(0,A.jsx)(Ki,{})}));
|