larkin 0.4.27 → 0.4.29
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/dist/app/agent-cli.mjs +4 -2
- package/dist/app/agent-config.mjs +45 -29
- package/dist/app/cli.mjs +16 -6
- package/dist/app/local-control.mjs +16 -3
- package/dist/app/pi-auth-cli.mjs +227 -17
- package/dist/app/runtime-model-directory.mjs +3 -2
- package/dist/app/runtime-process.mjs +42 -5
- package/dist/app/setup.mjs +15 -14
- package/dist/dashboard/dashboard-config-controller.mjs +145 -13
- package/dist/dashboard/dashboard-view-model.mjs +3 -2
- package/dist/dashboard/web/assets/dashboard.css +1 -1
- package/dist/dashboard/web/assets/dashboard.js +15 -15
- package/dist/feishu/host-shell.cjs +68 -16
- package/dist/feishu/host-shell.mjs +69 -17
- package/dist/platform/config.cjs +67 -16
- package/dist/platform/config.mjs +57 -16
- package/dist/runtime/pi-official-auth.cjs +594 -0
- package/dist/runtime/pi-official-auth.mjs +53 -0
- package/dist/runtime/pi-provider-config.cjs +26 -3
- package/dist/runtime/pi-provider-config.mjs +22 -2
- package/dist/runtime/pi-provider-login.mjs +240 -0
- package/dist/runtime/runtime-adapters.mjs +24 -4
- package/dist/runtime/runtime-host.cjs +215 -16
- package/dist/runtime/runtime-host.mjs +216 -17
- package/dist/runtime/runtime-model-catalog.cjs +4 -3
- package/dist/runtime/runtime-model-catalog.mjs +4 -3
- package/dist/runtime/runtime-readiness.cjs +123 -3
- package/dist/runtime/runtime-readiness.mjs +116 -4
- package/dist/runtime/user-runtime.cjs +51 -0
- package/dist/runtime/user-runtime.mjs +41 -0
- package/dist/setup/bot-register.mjs +3 -3
- package/dist/setup/setup-agent-choice.mjs +10 -9
- package/dist/setup/setup-bind.mjs +2 -2
- package/package.json +1 -1
|
@@ -6,22 +6,58 @@ import { ContextPromptBuilder } from "../agent/context-prompt.mjs";
|
|
|
6
6
|
import { createNativeRuntimeAdapter } from "../runtime/runtime-adapters.mjs";
|
|
7
7
|
import { createRuntimeHost } from "../runtime/runtime-host.mjs";
|
|
8
8
|
import { createAgentStateStore } from "../agent/agent-state-store.mjs";
|
|
9
|
-
import { loadConfig, markConfigApplied, runtimeConfigSignature } from "../platform/config.mjs";
|
|
9
|
+
import { loadConfig, markConfigApplied, runtimeConfigSignature, withConfigMutationLock, withConfigMutationLockAsync, } from "../platform/config.mjs";
|
|
10
10
|
import { traceProcessBoundary } from "../platform/process-boundary-trace.mjs";
|
|
11
11
|
import { createAgentControlServer, requestSupervisorAgentUpsert } from "./local-control.mjs";
|
|
12
|
-
import { hydrateRuntimeAgent, syncAgentProfile } from "./runtime-agent-config.mjs";
|
|
12
|
+
import { hydrateRuntimeAgent, syncAgentProfile, } from "./runtime-agent-config.mjs";
|
|
13
13
|
import { loadTelemetryConfig } from "../platform/telemetry-config.mjs";
|
|
14
14
|
import { telemetrySingleton } from "../platform/telemetry-tracing.mjs";
|
|
15
15
|
import { packageVersion } from "../platform/build-info.mjs";
|
|
16
|
-
|
|
16
|
+
function readRuntimeAgent(env, agentId, expectedSignature) {
|
|
17
17
|
const loaded = loadConfig(env);
|
|
18
18
|
const stored = loaded.config.agents[agentId];
|
|
19
19
|
if (!stored)
|
|
20
20
|
throw new Error(`Agent ${agentId} 不存在于 canonical config`);
|
|
21
|
+
if (expectedSignature) {
|
|
22
|
+
const current = runtimeConfigSignature(loaded.config, agentId);
|
|
23
|
+
if (current !== expectedSignature) {
|
|
24
|
+
throw new Error("配置在 apply 期间发生变化;未热加载已切换的 Agent");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return { loaded, stored };
|
|
28
|
+
}
|
|
29
|
+
function hydrateAndSyncRuntimeAgent(env, loaded, stored, dependencies) {
|
|
21
30
|
const agent = hydrateRuntimeAgent(loaded.configDir, stored);
|
|
22
31
|
syncAgentProfile(agent, { ...env, LARKIN_CONFIG_DIR: loaded.configDir }, dependencies);
|
|
23
32
|
return agent;
|
|
24
33
|
}
|
|
34
|
+
export function loadAndSyncRuntimeAgent(env, agentId, dependencies = {}, options = {}) {
|
|
35
|
+
const snapshot = readRuntimeAgent(env, agentId, options.expectedSignature);
|
|
36
|
+
options.afterCanonicalValidate?.();
|
|
37
|
+
if (!options.expectedSignature) {
|
|
38
|
+
return hydrateAndSyncRuntimeAgent(env, snapshot.loaded, snapshot.stored, dependencies);
|
|
39
|
+
}
|
|
40
|
+
return withConfigMutationLock(env, () => {
|
|
41
|
+
const locked = readRuntimeAgent(env, agentId, options.expectedSignature);
|
|
42
|
+
return hydrateAndSyncRuntimeAgent(env, locked.loaded, locked.stored, dependencies);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/** 签名校验贯穿实际 Host upsert;并发 config mutation 不能热挂载已失效的 snapshot。 */
|
|
46
|
+
export async function applyRuntimeAgentUpsert(env, agentId, dependencies = {}, options = {}, upsert = () => undefined) {
|
|
47
|
+
const snapshot = readRuntimeAgent(env, agentId, options.expectedSignature);
|
|
48
|
+
options.afterCanonicalValidate?.();
|
|
49
|
+
if (!options.expectedSignature) {
|
|
50
|
+
const agent = hydrateAndSyncRuntimeAgent(env, snapshot.loaded, snapshot.stored, dependencies);
|
|
51
|
+
await upsert(agent);
|
|
52
|
+
return agent;
|
|
53
|
+
}
|
|
54
|
+
return withConfigMutationLockAsync(env, async () => {
|
|
55
|
+
const locked = readRuntimeAgent(env, agentId, options.expectedSignature);
|
|
56
|
+
const agent = hydrateAndSyncRuntimeAgent(env, locked.loaded, locked.stored, dependencies);
|
|
57
|
+
await upsert(agent);
|
|
58
|
+
return agent;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
25
61
|
export async function markConfigAppliedAfterRuntimeReady(env, runningAgents, runtimeReady) {
|
|
26
62
|
await runtimeReady;
|
|
27
63
|
try {
|
|
@@ -100,10 +136,11 @@ export async function main(env = process.env, overrides = {}) {
|
|
|
100
136
|
larkinHome: env.LARKIN_HOME,
|
|
101
137
|
authorityToken: env.LARKIN_CONTROL_AUTHORIZATION,
|
|
102
138
|
async upsert(request) {
|
|
103
|
-
const agent =
|
|
139
|
+
const agent = await applyRuntimeAgentUpsert(env, request.agentId, {}, {
|
|
140
|
+
...(request.expectedSignature ? { expectedSignature: request.expectedSignature } : {}),
|
|
141
|
+
}, (candidate) => hostShell.upsertAgent(candidate));
|
|
104
142
|
// Only the selected profile is synchronized; active profiles and their directory
|
|
105
143
|
// are never quarantined or rebuilt during hot attach.
|
|
106
|
-
await hostShell.upsertAgent(agent);
|
|
107
144
|
const tracked = await requestSupervisorAgentUpsert({
|
|
108
145
|
larkinHome: env.LARKIN_HOME, agentId: agent.agentId, operationId: request.operationId,
|
|
109
146
|
});
|
package/dist/app/setup.mjs
CHANGED
|
@@ -8,6 +8,7 @@ import readline from "node:readline/promises";
|
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
9
|
import * as larkinConfig from "../platform/config.mjs";
|
|
10
10
|
import { PI_PROVIDER_PRESETS } from "../runtime/pi-provider-config.mjs";
|
|
11
|
+
import { fromUserRuntime, isUserRuntime } from "../runtime/user-runtime.mjs";
|
|
11
12
|
const PI_PROVIDER_IDS = PI_PROVIDER_PRESETS.map((p) => p.id).join(" | ") + " | custom";
|
|
12
13
|
import { acquireProcessLock, readProcessState } from "../platform/process-state.mjs";
|
|
13
14
|
import { requestAgentUpsert } from "./local-control.mjs";
|
|
@@ -35,18 +36,18 @@ if (has("--comment-subscription")) {
|
|
|
35
36
|
// 默认应用级评论订阅:平台验证的应用订阅让该应用可见文档的全部评论进入 Agent Inbox。
|
|
36
37
|
const commentSubscription = "application";
|
|
37
38
|
const OPT = { runtime: flag("--runtime") || null, commentSubscription, start: true, help: has("--help") || has("-h"), nonInteractive: !Boolean(process.stdin.isTTY) };
|
|
38
|
-
// runtime 枚举归一:builtin-pi(默认)/
|
|
39
|
-
const RUNTIME_ENUM = ["builtin-pi", "
|
|
39
|
+
// runtime 枚举归一:builtin-pi(默认)/ pi / codex / claude → 内部 (runtime, distribution)
|
|
40
|
+
const RUNTIME_ENUM = ["builtin-pi", "pi", "codex", "claude"];
|
|
40
41
|
function normalizeRuntime(value) {
|
|
41
|
-
const
|
|
42
|
-
if (
|
|
42
|
+
const raw = value || "builtin-pi";
|
|
43
|
+
if (raw === "external-pi") {
|
|
44
|
+
console.error("external-pi 已改名为 pi");
|
|
45
|
+
return fromUserRuntime("pi");
|
|
46
|
+
}
|
|
47
|
+
if (!isUserRuntime(raw) || !RUNTIME_ENUM.includes(raw)) {
|
|
43
48
|
die(`未知 runtime \`${value}\`;可选:${RUNTIME_ENUM.join(" | ")}`);
|
|
44
49
|
}
|
|
45
|
-
|
|
46
|
-
return { runtime: "pi", distribution: "builtin" };
|
|
47
|
-
if (chosen === "external-pi")
|
|
48
|
-
return { runtime: "pi", distribution: "external" };
|
|
49
|
-
return { runtime: chosen };
|
|
50
|
+
return fromUserRuntime(raw);
|
|
50
51
|
}
|
|
51
52
|
const normalizedRuntime = normalizeRuntime(OPT.runtime);
|
|
52
53
|
// 参数化路径:显式 --runtime、无 TTY(Agent 驱动)、或任何 provider 参数。
|
|
@@ -59,12 +60,12 @@ if (!OPT.help && parameterized && normalizedRuntime.distribution === "builtin")
|
|
|
59
60
|
const b = flag("--base-url");
|
|
60
61
|
const k = flag("--api-key");
|
|
61
62
|
if (!p && !b)
|
|
62
|
-
die(`builtin-pi 需要 --provider <id>(${PI_PROVIDER_IDS})或 --base-url;或 --runtime
|
|
63
|
+
die(`builtin-pi 需要 --provider <id>(${PI_PROVIDER_IDS})或 --base-url;或 --runtime pi 用已有 pi`);
|
|
63
64
|
if (!k)
|
|
64
|
-
die("builtin-pi 需要 --api-key;或 --runtime
|
|
65
|
+
die("builtin-pi 需要 --api-key;或 --runtime pi 用已有登录");
|
|
65
66
|
}
|
|
66
67
|
if (!OPT.help && normalizedRuntime.distribution === "external" && (flag("--provider") || flag("--api-key") || flag("--base-url"))) {
|
|
67
|
-
die("
|
|
68
|
+
die("pi 使用已有 pi 环境,不接受 --provider/--api-key/--base-url");
|
|
68
69
|
}
|
|
69
70
|
if (OPT.help) {
|
|
70
71
|
say(`larkin setup — Create or connect a Feishu (Lark) bot, then configure and attach its Agent
|
|
@@ -74,7 +75,7 @@ Usage:
|
|
|
74
75
|
larkin setup --provider <id> --api-key <key> 指定内置 Pi provider(无需交互)
|
|
75
76
|
|
|
76
77
|
Options:
|
|
77
|
-
--runtime <runtime> Agent runtime 枚举:builtin-pi(默认,内置 Pi)|
|
|
78
|
+
--runtime <runtime> Agent runtime 枚举:builtin-pi(默认,内置 Pi)| pi | codex | claude
|
|
78
79
|
--provider <id> 内置 Pi provider:deepseek | kimi | minimax | zhipu | openai |
|
|
79
80
|
anthropic | gemini | groq | cerebras | xai | fireworks |
|
|
80
81
|
together | mistral | openrouter | kimi-coding | qwen-cn | custom
|
|
@@ -96,7 +97,7 @@ daemon + dashboard supervisor used by larkin start.
|
|
|
96
97
|
|
|
97
98
|
Interactive terminals without flags keep the guided flow (browser bot selection + runtime choice).
|
|
98
99
|
Non-interactive (Agent-driven) runs default to builtin-pi and require --provider/--api-key (or
|
|
99
|
-
--runtime
|
|
100
|
+
--runtime pi to reuse an existing pi login).`);
|
|
100
101
|
process.exit(0);
|
|
101
102
|
}
|
|
102
103
|
function runForeground(mode, args) {
|
|
@@ -8,6 +8,9 @@ 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
10
|
import { ownedPiCatalogAgentDir, piCatalogCommandSpec } from "../runtime/pi-provider-config.mjs";
|
|
11
|
+
import { RUNTIME_OPTIONS, piCatalogDistributionForUserRuntime, toUserRuntime } from "../runtime/user-runtime.mjs";
|
|
12
|
+
import { configureBuiltinPiProvider, listBuiltinPiProviderCatalog, logoutBuiltinPiProvider, sanitizeProviderLoginError, } from "../runtime/pi-provider-login.mjs";
|
|
13
|
+
import { createOfficialPiCredentialRuntime, officialPiAuthStatus, } from "../runtime/pi-official-auth.mjs";
|
|
11
14
|
function pruneCache(cache, expired, maxEntries) {
|
|
12
15
|
for (const [key, value] of cache)
|
|
13
16
|
if (expired(value))
|
|
@@ -169,9 +172,38 @@ export function createPiModelDirectoryResolver(options = {}) {
|
|
|
169
172
|
const cache = new Map();
|
|
170
173
|
const failures = new Map();
|
|
171
174
|
const inFlight = new Map();
|
|
175
|
+
const generations = new Map();
|
|
176
|
+
// 单调序号:targeted 后再 global 时,in-flight 的 started 不能与新 generation 相等。
|
|
177
|
+
let seq = 0;
|
|
178
|
+
let baseline = 0;
|
|
179
|
+
const generationOf = (agentId) => Math.max(baseline, generations.get(agentId) ?? 0);
|
|
180
|
+
const dropPrefixed = (store, agentId) => {
|
|
181
|
+
if (!agentId) {
|
|
182
|
+
store.clear();
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const prefix = `${agentId}\u0000`;
|
|
186
|
+
for (const key of store.keys())
|
|
187
|
+
if (key.startsWith(prefix))
|
|
188
|
+
store.delete(key);
|
|
189
|
+
};
|
|
172
190
|
return {
|
|
191
|
+
invalidate(agentId) {
|
|
192
|
+
dropPrefixed(cache, agentId);
|
|
193
|
+
dropPrefixed(failures, agentId);
|
|
194
|
+
dropPrefixed(inFlight, agentId);
|
|
195
|
+
seq += 1;
|
|
196
|
+
if (!agentId) {
|
|
197
|
+
baseline = seq;
|
|
198
|
+
generations.clear();
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
generations.set(agentId, seq);
|
|
202
|
+
}
|
|
203
|
+
},
|
|
173
204
|
async resolve(input) {
|
|
174
205
|
const key = [input.agentId, input.cwd, input.agentDir, input.command ?? "", ...(input.commandArgs ?? [])].join("\u0000");
|
|
206
|
+
const started = generationOf(input.agentId);
|
|
175
207
|
pruneCache(cache, (entry) => now() >= entry.expiresAt, 64);
|
|
176
208
|
pruneCache(failures, (entry) => now() >= entry.expiresAt, 64);
|
|
177
209
|
const cached = cache.get(key);
|
|
@@ -195,17 +227,23 @@ export function createPiModelDirectoryResolver(options = {}) {
|
|
|
195
227
|
id, label, ...(contextWindow ? { contextWindow } : {}), supportedReasoningEfforts, ...(defaultReasoningEffort ? { defaultReasoningEffort } : {}),
|
|
196
228
|
})),
|
|
197
229
|
];
|
|
198
|
-
|
|
199
|
-
|
|
230
|
+
if (generationOf(input.agentId) === started) {
|
|
231
|
+
failures.delete(key);
|
|
232
|
+
cache.set(key, { expiresAt: now() + ttlMs, value: models });
|
|
233
|
+
}
|
|
200
234
|
return models;
|
|
201
235
|
}
|
|
202
236
|
catch (error) {
|
|
203
|
-
|
|
237
|
+
if (generationOf(input.agentId) === started)
|
|
238
|
+
failures.set(key, { expiresAt: now() + negativeTtlMs });
|
|
204
239
|
throw error;
|
|
205
240
|
}
|
|
206
241
|
})();
|
|
207
242
|
inFlight.set(key, pending);
|
|
208
|
-
void pending.finally(() =>
|
|
243
|
+
void pending.finally(() => {
|
|
244
|
+
if (inFlight.get(key) === pending)
|
|
245
|
+
inFlight.delete(key);
|
|
246
|
+
}).catch(() => undefined);
|
|
209
247
|
}
|
|
210
248
|
return await pending;
|
|
211
249
|
},
|
|
@@ -382,13 +420,13 @@ function dashboardMutation(value) {
|
|
|
382
420
|
return { kind: operation, agentId, model: String(value.model || "") };
|
|
383
421
|
return { kind: "set-agent-effort", agentId, effort: value.effort === null || value.effort === "default" ? null : String(value.effort || "") };
|
|
384
422
|
}
|
|
385
|
-
export function createDashboardConfigController({ csrfCapability, env = process.env, requestUpsert = requestAgentUpsert, chatDirectoryResolver = createChatDirectoryResolver(), claudeModelDirectoryResolver = createClaudeModelDirectoryResolver(), codexModelDirectoryResolver = createCodexModelDirectoryResolver(), piModelDirectoryResolver = createPiModelDirectoryResolver(), }) {
|
|
386
|
-
const resolvePiModelDirectory = async (agentId) => {
|
|
423
|
+
export function createDashboardConfigController({ csrfCapability, env = process.env, requestUpsert = requestAgentUpsert, chatDirectoryResolver = createChatDirectoryResolver(), claudeModelDirectoryResolver = createClaudeModelDirectoryResolver(), codexModelDirectoryResolver = createCodexModelDirectoryResolver(), piModelDirectoryResolver = createPiModelDirectoryResolver(), configureProvider = configureBuiltinPiProvider, logoutProvider = logoutBuiltinPiProvider, listProviderCatalog = listBuiltinPiProviderCatalog, loadProviderStatus = async (configDir, agentId) => officialPiAuthStatus(await createOfficialPiCredentialRuntime(configDir, agentId)), }) {
|
|
424
|
+
const resolvePiModelDirectory = async (agentId, userRuntime) => {
|
|
387
425
|
const { config, configDir } = loadConfig(env);
|
|
388
426
|
const agent = config.agents[agentId];
|
|
389
427
|
if (!agent)
|
|
390
428
|
throw new Error("unknown agent");
|
|
391
|
-
const catalogCommand = piCatalogCommandSpec(
|
|
429
|
+
const catalogCommand = piCatalogCommandSpec(piCatalogDistributionForUserRuntime(userRuntime), env);
|
|
392
430
|
return await piModelDirectoryResolver.resolve({
|
|
393
431
|
agentId,
|
|
394
432
|
cwd: agent.workspaceDir,
|
|
@@ -402,8 +440,8 @@ export function createDashboardConfigController({ csrfCapability, env = process.
|
|
|
402
440
|
const agent = config.agents[agentId];
|
|
403
441
|
if (!agent)
|
|
404
442
|
throw new Error("unknown agent");
|
|
405
|
-
if (runtime === "pi")
|
|
406
|
-
return await resolvePiModelDirectory(agentId);
|
|
443
|
+
if (runtime === "pi" || runtime === "builtin-pi")
|
|
444
|
+
return await resolvePiModelDirectory(agentId, runtime);
|
|
407
445
|
if (runtime === "codex")
|
|
408
446
|
return await codexModelDirectoryResolver.resolve({ agentId, cwd: agent.workspaceDir, env });
|
|
409
447
|
if (runtime === "claude")
|
|
@@ -420,7 +458,9 @@ export function createDashboardConfigController({ csrfCapability, env = process.
|
|
|
420
458
|
const agent = config.agents[mutation.agentId];
|
|
421
459
|
if (!agent)
|
|
422
460
|
throw new Error("unknown agent");
|
|
423
|
-
const runtime = mutation.kind === "set-agent-runtime"
|
|
461
|
+
const runtime = mutation.kind === "set-agent-runtime"
|
|
462
|
+
? mutation.runtime
|
|
463
|
+
: toUserRuntime(agent.runtime, agent.piDistribution);
|
|
424
464
|
const model = mutation.kind === "set-agent-runtime" ? mutation.model || "default"
|
|
425
465
|
: mutation.kind === "set-agent-model" ? mutation.model : agent.model;
|
|
426
466
|
if (mutation.kind === "set-agent-effort" && mutation.effort === null)
|
|
@@ -440,18 +480,22 @@ export function createDashboardConfigController({ csrfCapability, env = process.
|
|
|
440
480
|
if (requestUrl.pathname === "/api/config" && req.method === "GET") {
|
|
441
481
|
try {
|
|
442
482
|
assertPrivateReadRequest(req, csrfCapability);
|
|
443
|
-
json(res, 200, {
|
|
483
|
+
json(res, 200, {
|
|
484
|
+
...await sanitizedView(env, chatDirectoryResolver, requestUrl.searchParams.get("agent") || undefined, requestUrl.searchParams.get("chat") || undefined),
|
|
485
|
+
runtimeModels: loadRuntimeModels(),
|
|
486
|
+
runtimeOptions: [...RUNTIME_OPTIONS],
|
|
487
|
+
});
|
|
444
488
|
}
|
|
445
489
|
catch (error) {
|
|
446
490
|
json(res, error instanceof Error && /host|capability/.test(error.message) ? 403 : 500, { error: "configuration unavailable" });
|
|
447
491
|
}
|
|
448
492
|
return true;
|
|
449
493
|
}
|
|
450
|
-
if (requestUrl.pathname === "/api/models/pi" && req.method === "GET") {
|
|
494
|
+
if ((requestUrl.pathname === "/api/models/pi" || requestUrl.pathname === "/api/models/builtin-pi") && req.method === "GET") {
|
|
451
495
|
try {
|
|
452
496
|
assertPrivateReadRequest(req, csrfCapability);
|
|
453
497
|
const agentId = requestUrl.searchParams.get("agent") || "";
|
|
454
|
-
const models = await resolvePiModelDirectory(agentId);
|
|
498
|
+
const models = await resolvePiModelDirectory(agentId, requestUrl.pathname === "/api/models/builtin-pi" ? "builtin-pi" : "pi");
|
|
455
499
|
json(res, 200, { models });
|
|
456
500
|
}
|
|
457
501
|
catch (error) {
|
|
@@ -504,6 +548,94 @@ export function createDashboardConfigController({ csrfCapability, env = process.
|
|
|
504
548
|
}
|
|
505
549
|
return true;
|
|
506
550
|
}
|
|
551
|
+
if (requestUrl.pathname === "/api/pi-auth/providers" && req.method === "GET") {
|
|
552
|
+
try {
|
|
553
|
+
assertPrivateReadRequest(req, csrfCapability);
|
|
554
|
+
json(res, 200, { providers: listProviderCatalog() });
|
|
555
|
+
}
|
|
556
|
+
catch (error) {
|
|
557
|
+
json(res, error instanceof Error && /host|capability/.test(error.message) ? 403 : 500, { error: "provider catalog unavailable" });
|
|
558
|
+
}
|
|
559
|
+
return true;
|
|
560
|
+
}
|
|
561
|
+
if (requestUrl.pathname === "/api/pi-auth/status" && req.method === "GET") {
|
|
562
|
+
try {
|
|
563
|
+
assertPrivateReadRequest(req, csrfCapability);
|
|
564
|
+
const agentId = requestUrl.searchParams.get("agent") || "";
|
|
565
|
+
const { config, configDir } = loadConfig(env);
|
|
566
|
+
const agent = config.agents[agentId];
|
|
567
|
+
if (!agent || agent.runtime !== "pi" || agent.piDistribution !== "builtin")
|
|
568
|
+
throw new Error("unknown agent");
|
|
569
|
+
const credentials = await loadProviderStatus(configDir, agentId);
|
|
570
|
+
json(res, 200, { agentId, model: agent.model, credentials });
|
|
571
|
+
}
|
|
572
|
+
catch (error) {
|
|
573
|
+
json(res, error instanceof Error && /host|capability/.test(error.message) ? 403 : 500, { error: "provider status unavailable" });
|
|
574
|
+
}
|
|
575
|
+
return true;
|
|
576
|
+
}
|
|
577
|
+
if (requestUrl.pathname === "/api/pi-auth/login" && req.method === "POST") {
|
|
578
|
+
let secret = "";
|
|
579
|
+
try {
|
|
580
|
+
assertWriteRequest(req, csrfCapability);
|
|
581
|
+
const body = await boundedJson(req);
|
|
582
|
+
const allowed = ["agentId", "preset", "apiKey", "model", "baseUrl"];
|
|
583
|
+
if (Object.keys(body).some((key) => !allowed.includes(key)))
|
|
584
|
+
throw new Error("unsupported field");
|
|
585
|
+
const agentId = String(body.agentId || "");
|
|
586
|
+
const preset = String(body.preset || "");
|
|
587
|
+
const apiKey = typeof body.apiKey === "string" ? body.apiKey : "";
|
|
588
|
+
secret = apiKey;
|
|
589
|
+
if (!/^cli_[A-Za-z0-9]+$/.test(agentId) || !preset)
|
|
590
|
+
throw new Error("invalid login request");
|
|
591
|
+
const { config } = loadConfig(env);
|
|
592
|
+
const agent = config.agents[agentId];
|
|
593
|
+
if (!agent || agent.runtime !== "pi" || agent.piDistribution !== "builtin")
|
|
594
|
+
throw new Error("Agent is not builtin Pi");
|
|
595
|
+
const result = await configureProvider({
|
|
596
|
+
agentId,
|
|
597
|
+
preset,
|
|
598
|
+
apiKey,
|
|
599
|
+
...(typeof body.model === "string" ? { model: body.model } : {}),
|
|
600
|
+
...(typeof body.baseUrl === "string" ? { baseUrl: body.baseUrl } : {}),
|
|
601
|
+
env,
|
|
602
|
+
});
|
|
603
|
+
piModelDirectoryResolver.invalidate?.(agentId);
|
|
604
|
+
json(res, 200, {
|
|
605
|
+
ok: true,
|
|
606
|
+
agentId: result.agentId,
|
|
607
|
+
provider: result.provider,
|
|
608
|
+
preset: result.preset,
|
|
609
|
+
model: result.model,
|
|
610
|
+
credentialType: result.credentialType,
|
|
611
|
+
applyState: result.applyState,
|
|
612
|
+
...(result.applyError ? { applyError: sanitizeProviderLoginError(result.applyError, secret || undefined) } : {}),
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
catch (error) {
|
|
616
|
+
json(res, 400, { error: sanitizeProviderLoginError(error, secret || undefined) });
|
|
617
|
+
}
|
|
618
|
+
return true;
|
|
619
|
+
}
|
|
620
|
+
if (requestUrl.pathname === "/api/pi-auth/logout" && req.method === "POST") {
|
|
621
|
+
try {
|
|
622
|
+
assertWriteRequest(req, csrfCapability);
|
|
623
|
+
const body = await boundedJson(req);
|
|
624
|
+
if (Object.keys(body).sort().join(",") !== "agentId,provider")
|
|
625
|
+
throw new Error("invalid logout request");
|
|
626
|
+
const agentId = String(body.agentId || "");
|
|
627
|
+
const provider = String(body.provider || "");
|
|
628
|
+
if (!/^cli_[A-Za-z0-9]+$/.test(agentId))
|
|
629
|
+
throw new Error("invalid logout request");
|
|
630
|
+
const result = await logoutProvider({ agentId, providerId: provider, env });
|
|
631
|
+
piModelDirectoryResolver.invalidate?.(agentId);
|
|
632
|
+
json(res, 200, { ok: true, agentId: result.agentId, provider: result.provider });
|
|
633
|
+
}
|
|
634
|
+
catch (error) {
|
|
635
|
+
json(res, 400, { error: sanitizeProviderLoginError(error) });
|
|
636
|
+
}
|
|
637
|
+
return true;
|
|
638
|
+
}
|
|
507
639
|
if (requestUrl.pathname === "/api/config/apply" && req.method === "POST") {
|
|
508
640
|
try {
|
|
509
641
|
assertWriteRequest(req, csrfCapability);
|
|
@@ -13,6 +13,7 @@ import { collectWorkspaceEntry as collectTypedWorkspaceEntry } from "./dashboard
|
|
|
13
13
|
import { buildFingerprint, packageVersion } from "../platform/build-info.mjs";
|
|
14
14
|
import * as larkinConfig from "../platform/config.mjs";
|
|
15
15
|
import { ownedPiCatalogAgentDir, piCatalogCommandSpec } from "../runtime/pi-provider-config.mjs";
|
|
16
|
+
import { toUserRuntime } from "../runtime/user-runtime.mjs";
|
|
16
17
|
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
17
18
|
const ROOT = path.resolve(HERE, "../..");
|
|
18
19
|
export const PACKAGE_VERSION = packageVersion(ROOT);
|
|
@@ -502,7 +503,7 @@ async function collectAgentStatus(a, configDir, daemonStartedAt, piModelResolver
|
|
|
502
503
|
agentId: a.agentId,
|
|
503
504
|
name: a.name,
|
|
504
505
|
displayName: (botIdentity && botIdentity.name) || a.name,
|
|
505
|
-
runtime: a.runtime,
|
|
506
|
+
runtime: toUserRuntime(a.runtime, a.piDistribution),
|
|
506
507
|
model: status.session?.runtime === a.runtime && status.session?.model ? String(status.session.model) : a.model,
|
|
507
508
|
effort: status.session?.runtime === a.runtime && status.session?.reasoningEffort ? String(status.session.reasoningEffort) : a.effort || null,
|
|
508
509
|
runtimeReadiness,
|
|
@@ -526,7 +527,7 @@ async function collectAgentStatus(a, configDir, daemonStartedAt, piModelResolver
|
|
|
526
527
|
sessions: agentState.sessions || {},
|
|
527
528
|
session: sessionId ? {
|
|
528
529
|
id: sessionId,
|
|
529
|
-
runtime: a.runtime,
|
|
530
|
+
runtime: toUserRuntime(a.runtime, a.piDistribution),
|
|
530
531
|
startedAt: usage.startedAt || (status.session?.id === sessionId ? status.session.startedAt : null) || null,
|
|
531
532
|
ageSec: ageSec(usage.startedAt || (status.session?.id === sessionId ? status.session.startedAt : null)),
|
|
532
533
|
lastTurnAt: status.session?.lastTurnAt || null,
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
|
|
2
|
-
@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.hidden{display:none}}:root{--paper:#f4f0e8;--panel:#fbf8f1;--ink:#201c18;--subtle:#6e675e;--faint:#989084;--line:#ddd5c7;--accent:#a3402c;--accent-soft:#f2e3dc;--success:#2d6a4f;--warning:#9a6700;--danger:#a3402c;--shadow:0 14px 44px #33281f14;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light;font-synthesis:none;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}@media (prefers-color-scheme:dark){:root{--paper:#181513;--panel:#211d1a;--ink:#eee7dc;--subtle:#aaa195;--faint:#766d63;--line:#37302a;--accent:#d17862;--accent-soft:#3a2420;--success:#75b798;--warning:#e0ad55;--shadow:0 14px 44px #0000003d;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}}*{box-sizing:border-box}html,body,#root{min-height:100%}html{background:var(--paper);overflow-x:clip}body{background:var(--paper);color:var(--ink);margin:0;overflow-x:clip}button,input,select{font:inherit}button,select{cursor:pointer}button:disabled,select:disabled,input:disabled{cursor:not-allowed;opacity:.55}[hidden]{display:none!important}:focus-visible{outline:3px solid var(--accent)}@supports (color:color-mix(in lab, red, red)){:focus-visible{outline:3px solid color-mix(in srgb, var(--accent) 40%, transparent)}}:focus-visible{outline-offset:2px}.sr-only{clip:rect(0, 0, 0, 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.app-shell{grid-template-columns:292px minmax(0,1fr);min-height:100vh;display:grid}.app-shell.workspace-app-active{height:100dvh;min-height:0;overflow:hidden}.desktop-sidebar{border-right:1px solid var(--line);background:var(--panel);flex-direction:column;min-width:0;height:100vh;display:flex;position:sticky;top:0}@supports (color:color-mix(in lab, red, red)){.desktop-sidebar{background:color-mix(in srgb, var(--panel) 94%, transparent)}}.brand{border-bottom:1px solid var(--line);align-items:center;gap:12px;height:78px;padding:18px 22px;display:flex}.brand img{width:38px;height:38px}.brand strong{color:var(--accent);letter-spacing:-.03em;font:600 22px Georgia,serif}.brand-version{color:var(--faint);letter-spacing:0;white-space:nowrap;font:600 10px ui-monospace,monospace}.desktop-sidebar footer{border-top:1px solid var(--line);color:var(--faint);padding:13px 18px;font-size:11px}.sidebar-inner{flex-direction:column;flex:1;min-height:0;padding:14px 12px;display:flex}.agent-search,.table-search{border:1px solid var(--line);background:var(--paper);color:var(--faint);border-radius:9px;align-items:center;gap:8px;display:flex}.agent-search{margin-bottom:12px;padding:9px 11px}.agent-search input,.table-search input{width:100%;min-width:0;color:var(--ink);background:0 0;border:0;outline:0}.agent-list{align-content:start;gap:6px;min-height:0;display:grid;overflow-y:auto}.agent-list-item{width:100%;min-width:0;color:var(--subtle);text-align:left;background:0 0;border:1px solid #0000;border-radius:11px;grid-template-columns:42px minmax(0,1fr) 16px;align-items:center;gap:10px;padding:10px;display:grid}.agent-list-item:hover{background:var(--ink)}@supports (color:color-mix(in lab, red, red)){.agent-list-item:hover{background:color-mix(in srgb, var(--ink) 4%, transparent)}}.agent-list-item:hover{color:var(--ink)}.agent-list-item.selected{border-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.agent-list-item.selected{border-color:color-mix(in srgb, var(--accent) 42%, var(--line))}}.agent-list-item.selected{background:var(--accent-soft);color:var(--ink)}.agent-list-copy{gap:1px;min-width:0;display:grid}.agent-list-copy strong,.agent-list-copy small,.status-line{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.agent-list-copy strong{font-size:13px}.agent-list-copy small{color:var(--faint);font-size:10.5px}.status-line{color:var(--subtle);align-items:center;gap:4px;font-size:10px;display:flex}.agent-avatar{border:1px solid var(--line);background:var(--accent);border-radius:50%;flex:none;place-items:center;width:42px;height:42px;display:grid;position:relative;overflow:hidden}@supports (color:color-mix(in lab, red, red)){.agent-avatar{background:color-mix(in srgb, var(--accent) 12%, var(--panel))}}.agent-avatar{color:var(--accent);font:700 13px Georgia,serif}.agent-avatar img{object-fit:cover;width:100%;height:100%;display:block}.danger{color:var(--danger)}.workspace-shell{flex-direction:column;min-width:0;min-height:100vh;display:flex}.workspace-shell.workspace-route-active{height:100dvh;min-height:0;overflow:hidden}.workspace-route-active>.app-topbar,.workspace-route-active>.agent-header,.workspace-route-active>.agent-tabs,.workspace-route-active>.stale-banner,.workspace-route-active>.notice{flex:none}.app-topbar{z-index:20;border-bottom:1px solid var(--line);background:var(--paper);justify-content:space-between;align-items:center;gap:16px;height:64px;padding:0 28px;display:flex;position:sticky;top:0}@supports (color:color-mix(in lab, red, red)){.app-topbar{background:color-mix(in srgb, var(--paper) 94%, transparent)}}.app-topbar{-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px)}.app-topbar>div{align-items:center;gap:10px;min-width:0;display:flex}.app-topbar>div>strong{color:var(--accent);font:600 19px Georgia,serif;display:none}.app-topbar>div>span{color:var(--subtle);font-size:12px}.mobile-menu{display:none!important}.ui-button{border:1px solid var(--line);background:var(--panel);min-height:34px;color:var(--ink);border-radius:8px;justify-content:center;align-items:center;gap:7px;padding:7px 11px;font-size:12px;font-weight:600;display:inline-flex}.ui-button:hover{border-color:var(--accent);background:var(--accent-soft)}.ui-button.primary{border-color:var(--accent);background:var(--accent);color:#fff}.ui-button.icon-button{width:36px;padding:0}.ui-badge{border:1px solid var(--line);color:var(--subtle);background:var(--ink);border-radius:999px;align-items:center;padding:2px 8px;display:inline-flex}@supports (color:color-mix(in lab, red, red)){.ui-badge{background:color-mix(in srgb, var(--ink) 3%, var(--panel))}}.ui-badge{white-space:nowrap;font-size:10.5px;font-weight:600}.ui-badge.success{border-color:var(--success)}@supports (color:color-mix(in lab, red, red)){.ui-badge.success{border-color:color-mix(in srgb, var(--success) 55%, var(--line))}}.ui-badge.success{color:var(--success)}.ui-badge.warning{border-color:var(--warning)}@supports (color:color-mix(in lab, red, red)){.ui-badge.warning{border-color:color-mix(in srgb, var(--warning) 55%, var(--line))}}.ui-badge.warning{color:var(--warning)}.ui-badge.accent,.ui-badge.danger-badge{border-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.ui-badge.accent,.ui-badge.danger-badge{border-color:color-mix(in srgb, var(--accent) 55%, var(--line))}}.ui-badge.accent,.ui-badge.danger-badge{color:var(--accent)}.stale-banner,.notice{border:1px solid var(--warning);align-items:center;gap:8px;margin:16px 28px 0;display:flex}@supports (color:color-mix(in lab, red, red)){.stale-banner,.notice{border:1px solid color-mix(in srgb, var(--warning) 50%, var(--line))}}.stale-banner,.notice{background:var(--warning);border-radius:9px;padding:8px 11px}@supports (color:color-mix(in lab, red, red)){.stale-banner,.notice{background:color-mix(in srgb, var(--warning) 7%, var(--panel))}}.stale-banner,.notice{color:var(--warning);font-size:12px}.stale-banner .ui-button,.notice .ui-button{min-height:28px;margin-left:auto;padding-block:4px}.notice{border-color:var(--line);background:var(--panel);color:var(--subtle)}.agent-header{z-index:15;background:var(--paper);justify-content:space-between;align-items:center;gap:28px;min-width:0;padding:24px 30px 18px;display:flex;position:sticky;top:64px}@supports (color:color-mix(in lab, red, red)){.agent-header{background:color-mix(in srgb, var(--paper) 96%, transparent)}}.agent-header{-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px)}.agent-title{align-items:center;gap:13px;min-width:0;display:flex}.agent-title .agent-avatar{width:52px;height:52px}.agent-title div{min-width:0}.agent-title p{text-overflow:ellipsis;color:var(--faint);margin:0;font:10px ui-monospace,monospace;overflow:hidden}.agent-title h1{text-overflow:ellipsis;white-space:nowrap;letter-spacing:-.025em;margin:1px 0 0;font:600 clamp(23px,3vw,34px) Georgia,serif;overflow:hidden}.agent-header-summary{min-width:0;max-width:62%;color:var(--subtle);flex-wrap:wrap;justify-content:flex-end;gap:6px 14px;font-size:11.5px;display:flex}.agent-tabs{z-index:14;border-bottom:1px solid var(--line);background:var(--paper);gap:2px;padding:0 30px;display:flex;position:sticky;top:158px}@supports (color:color-mix(in lab, red, red)){.agent-tabs{background:color-mix(in srgb, var(--paper) 96%, transparent)}}.agent-tabs{scrollbar-width:thin;overflow-x:auto}.agent-tabs button{color:var(--subtle);background:0 0;border:0;border-bottom:2px solid #0000;flex:none;align-items:center;gap:7px;padding:11px 14px 9px;font-size:12px;font-weight:600;display:inline-flex}.agent-tabs button svg{width:14px;height:14px}.agent-tabs button:hover{color:var(--ink)}.agent-tabs button.active{color:var(--accent);border-bottom-color:var(--accent)}.agent-content{min-width:0;padding:24px 30px 64px}.agent-content>section{min-width:0}.agent-content.workspace-active{flex:1 1 0;height:auto;min-height:0;padding-bottom:24px;display:flex;overflow:hidden}.workspace-tab-panel{flex:1;min-height:0;display:flex}.overview-page{gap:28px;display:grid}.metrics-band{border-block:1px solid var(--line);grid-template-columns:repeat(4,minmax(0,1fr));min-width:0;display:grid}.metric-stat{flex-direction:column;min-width:0;min-height:126px;padding:16px 14px;display:flex}.metric-stat:not(:last-child){border-right:1px solid var(--line)}.metric-stat{border-bottom:1px solid var(--line)}.metric-stat:nth-child(4n){border-right:0}.metric-stat:nth-last-child(-n+3){border-bottom:0}.metric-stat>span{color:var(--faint);letter-spacing:.08em;text-transform:uppercase;margin-top:10px;font-size:9.5px;font-weight:700}.metric-stat>strong{text-overflow:ellipsis;margin-top:3px;font:600 18px Georgia,serif;overflow:hidden}.metric-stat>small{color:var(--subtle);margin-top:auto;font-size:10px}.metric-icon{width:20px;height:20px;color:var(--accent);place-items:center;display:grid}.metric-icon svg{width:15px;height:15px}.overview-sections{grid-template-columns:minmax(0,3fr) minmax(220px,1fr);gap:28px;min-width:0;display:grid}.content-section,.config-section,.group-policy-section,.logs-section{border-block:1px solid var(--line);min-width:0;padding:18px 0}.content-section h3,.config-section h3,.group-policy-section h3,.logs-section h3{margin:0;font:600 17px Georgia,serif}.section-heading{justify-content:space-between;align-items:flex-start;gap:16px;min-width:0;margin-bottom:14px;display:flex}.section-heading p{color:var(--subtle);margin:2px 0 0;font-size:11px}.facts{gap:0;margin:14px 0 0;display:grid}.facts div{border-top:1px solid var(--line);justify-content:space-between;align-items:baseline;gap:16px;padding:9px 0;display:flex}.facts dt{color:var(--subtle);font-size:11px}.facts dd{text-overflow:ellipsis;min-width:0;margin:0;font-size:12px;font-weight:600;overflow:hidden}.timeline{gap:0;margin:0;padding:0;list-style:none;display:grid}.timeline li{grid-template-columns:14px minmax(0,1fr);gap:10px;padding:8px 0;display:grid;position:relative}.timeline li:not(:last-child):before{content:"";background:var(--line);width:1px;position:absolute;top:21px;bottom:-7px;left:5px}.timeline-dot{z-index:1;border:2px solid var(--panel);background:var(--subtle);width:11px;height:11px;box-shadow:0 0 0 1px var(--line);border-radius:50%;margin-top:4px;position:relative}.timeline-dot.state-active{background:var(--warning)}.timeline-dot.state-idle{background:var(--success)}.timeline-dot.state-deliver{background:#3977b8}.timeline-dot.state-error{background:var(--danger)}.timeline-dot.state-unknown{background:var(--faint)}.timeline strong{font-size:11.5px}.timeline p{color:var(--subtle);overflow-wrap:anywhere;margin:1px 0;font-size:11px}.timeline time,.error-stack time{color:var(--faint);font-size:9.5px}.conversation-list,.reminder-list{border-top:1px solid var(--line);gap:0;max-width:900px;display:grid}.conversation-item,.reminder-list article{border:0;border-bottom:1px solid var(--line);background:0 0;padding:14px 10px}.conversation-item.outbound{border-left:3px solid var(--accent)}.conversation-item.inbound{border-left:3px solid var(--success)}.conversation-item.listening{border-left-color:var(--warning)}.conversation-item header{justify-content:space-between;gap:16px;display:flex}.conversation-item header>div{align-items:center;gap:8px;display:flex}.conversation-item header strong{font-size:12px}.conversation-item time,.conversation-item small{color:var(--faint);font-size:10px}.conversation-item p{white-space:pre-wrap;overflow-wrap:anywhere;margin:7px 0 0;font:13px/1.65 Georgia,serif}.reminder-list article{grid-template-columns:20px minmax(0,1fr) auto;align-items:center;gap:10px;display:grid}.reminder-list article.status-scheduled,.reminder-list article.status-pending{border-left:3px solid var(--warning)}.reminder-list article.status-fired{border-left:3px solid var(--success)}.reminder-list article.status-canceled{border-left:3px solid var(--faint)}.reminder-list article.status-failed{border-left:3px solid var(--danger)}.reminder-list article.done{opacity:.7;text-decoration:line-through}.reminder-list strong{font-size:12px}.reminder-list p{color:var(--subtle);margin:2px 0 0;font-size:10.5px}.configuration-page{gap:18px;display:grid}.cli-guidance{border-left:2px solid var(--accent);color:var(--subtle);margin:0 0 14px;padding:6px 10px;font-size:11px;line-height:1.55}.cli-guidance code{color:var(--ink);overflow-wrap:anywhere;font:600 10.5px ui-monospace,monospace}.config-grid{grid-template-columns:repeat(4,minmax(120px,1fr));gap:12px;display:grid}.config-grid label,.settings-form label,.chat-add label{min-width:0;color:var(--subtle);gap:5px;font-size:11px;font-weight:600;display:grid}.config-grid select,.config-grid input,.settings-form select,.chat-add select,.chat-add input,.policy-table select{border:1px solid var(--line);background:var(--paper);width:100%;min-width:0;min-height:37px;color:var(--ink);border-radius:8px;padding:7px 9px;font-size:12px}.config-grid input:disabled{color:var(--subtle)}.form-actions{flex-wrap:wrap;justify-content:flex-end;gap:8px;margin-top:16px;display:flex}.feedback{color:var(--subtle);margin:10px 0 0;font-size:11px}.table-search{min-width:min(300px,42vw);padding:7px 9px}.policy-table-wrap{width:100%;overflow-x:auto}.policy-table{border-collapse:collapse;width:100%;font-size:11px}.policy-table th{color:var(--faint);text-align:left;letter-spacing:.06em;text-transform:uppercase;font-size:9.5px}.policy-table th,.policy-table td{border-bottom:1px solid var(--line);vertical-align:middle;min-width:120px;padding:10px 8px}.policy-table th:first-child,.policy-table td:first-child{min-width:190px}.policy-table th:last-child,.policy-table td:last-child{min-width:150px}.policy-table td strong,.policy-table td code{display:block}.policy-table td code{color:var(--faint);margin-top:2px;font-size:9.5px}.policy-table td small{color:var(--faint);margin-top:2px;font-size:9.5px;display:block}.chat-add{grid-template-columns:minmax(190px,1fr) 140px auto;align-items:end;gap:9px;margin-top:14px;display:grid}.workspace-browser{border-block:1px solid var(--line);background:0 0;flex:1;grid-template-columns:minmax(240px,32%) minmax(0,1fr);min-width:0;min-height:0;display:grid;overflow:hidden}.workspace-side{border-right:1px solid var(--line);flex-direction:column;min-width:0;min-height:0;display:flex}.breadcrumbs{border-bottom:1px solid var(--line);white-space:nowrap;align-items:center;gap:3px;min-height:42px;padding:7px 10px;display:flex;overflow-x:auto}.breadcrumbs span{align-items:center;display:inline-flex}.breadcrumbs button{color:var(--accent);background:0 0;border:0;font-size:10.5px}.workspace-list{overscroll-behavior:contain;scrollbar-gutter:stable;flex:1 1 0;min-height:0;padding:6px;overflow:auto}.workspace-list>button{width:100%;min-width:0;color:var(--ink);text-align:left;background:0 0;border:0;border-radius:7px;grid-template-columns:18px minmax(0,1fr) auto;align-items:center;gap:7px;padding:7px 8px;font-size:11.5px;display:grid}.workspace-list>button:hover{background:var(--accent-soft)}.workspace-list>button span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.workspace-list>button small{color:var(--faint);font-size:9.5px}.workspace-preview{overscroll-behavior:contain;scrollbar-gutter:stable;min-width:0;min-height:0;overflow:auto}.workspace-preview>header{border-bottom:1px solid var(--line);background:var(--panel);justify-content:space-between;gap:12px;padding:11px 14px;display:flex;position:sticky;top:0}.workspace-preview header small{color:var(--faint)}.workspace-preview pre{white-space:pre-wrap;overflow-wrap:anywhere;margin:0;padding:16px;font:11.5px/1.65 ui-monospace,monospace}.logs-section{max-width:920px}.error-stack{border-top:1px solid var(--line);margin-top:18px;padding-top:14px}.error-stack h4{margin:0 0 8px;font-size:12px}.error-stack>div{color:var(--danger);grid-template-columns:16px minmax(0,1fr) auto;align-items:center;gap:8px;padding:7px 0;font-size:11px;display:grid}.empty-state{min-width:0;min-height:120px;color:var(--subtle);text-align:center;align-content:center;place-items:center;padding:20px;display:grid}.empty-state strong{color:var(--ink);font:600 15px Georgia,serif}.empty-state p{max-width:460px;margin:4px 0 0;font-size:11px}.page-loading{min-height:50vh;color:var(--subtle);justify-content:center;align-items:center;gap:10px;display:flex}.spin{animation:1s linear infinite spin}@keyframes spin{to{transform:rotate(360deg)}}.sheet-overlay{z-index:50;background:#14100d7a;animation:.15s ease-out fade-in;position:fixed;inset:0}.sheet-content{z-index:51;border-left:1px solid var(--line);background:var(--panel);width:min(440px,94vw);max-width:100%;color:var(--ink);box-shadow:var(--shadow);padding:22px;animation:.2s ease-out slide-in;position:fixed;inset:0 0 0 auto;overflow-y:auto}.sheet-head{border-bottom:1px solid var(--line);justify-content:space-between;align-items:flex-start;gap:16px;padding-bottom:18px;display:flex}.sheet-head h2{margin:0;font:600 24px Georgia,serif}.sheet-head p{color:var(--subtle);margin:4px 0 0;font-size:11.5px}.settings-form{padding-top:18px}.field-help{color:var(--subtle);font-size:11px}.compact-sidebar{padding:16px 0}@keyframes fade-in{0%{opacity:0}}@keyframes slide-in{0%{opacity:.5;transform:translate(24px)}}@media (width>=1600px){.metrics-band{grid-template-columns:repeat(7,minmax(0,1fr))}.metrics-band .metric-stat{border-right:1px solid var(--line);border-bottom:0}.metrics-band .metric-stat:last-child{border-right:0}}@media (width<=1100px){.config-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (width<=760px){.app-shell{display:block}.app-shell.workspace-app-active{height:auto;min-height:100vh;overflow:visible}.desktop-sidebar{display:none}.mobile-menu{display:inline-flex!important}.app-topbar{height:58px;padding:0 14px}.app-topbar>div>strong{display:inline}.agent-header{padding:17px 16px 12px;display:block;top:58px}.agent-header-summary{justify-content:flex-start;max-width:none;margin-top:12px}.agent-tabs{padding:0 8px;top:150px}.agent-tabs button{padding-inline:10px}.agent-content{padding:16px 14px 48px}.metrics-band{grid-template-columns:repeat(2,minmax(0,1fr))}.metrics-band .metric-stat{border-right:1px solid var(--line);border-bottom:1px solid var(--line);min-height:116px;padding:13px 10px}.metric-stat:nth-child(2n){border-right:0}.metric-stat:nth-last-child(-n+1){border-bottom:0}.overview-sections{grid-template-columns:1fr;gap:22px}.config-grid{grid-template-columns:1fr}.section-heading{display:block}.section-heading>.ui-badge,.section-heading>.table-search{margin-top:9px}.table-search{width:100%;min-width:0}.policy-table{display:block}.policy-table thead{clip:rect(0, 0, 0, 0);width:1px;height:1px;position:absolute;overflow:hidden}.policy-table tbody{border-top:1px solid var(--line);gap:0;display:grid}.policy-table tr{border:0;border-bottom:1px solid var(--line);gap:8px;min-width:0;padding:12px 0;display:grid}.policy-table td,.policy-table td:first-child,.policy-table td:last-child{border:0;min-width:0;padding:0}.policy-table td:before{color:var(--faint);text-transform:uppercase;margin-bottom:3px;font-size:9px;display:block}.policy-table td:nth-child(2):before{content:"消息策略"}.policy-table td:nth-child(3):before{content:"操作"}.chat-add{grid-template-columns:1fr}.workspace-shell,.workspace-shell.workspace-route-active{height:auto;min-height:100vh;display:block;overflow:visible}.agent-content.workspace-active{height:auto;min-height:0;display:block;overflow:visible}.workspace-tab-panel{display:block}.workspace-browser{grid-template-columns:1fr;height:auto;min-height:0;overflow:hidden}.workspace-side{border-right:0;border-bottom:1px solid var(--line);height:min(300px,42dvh)}.workspace-preview{height:min(520px,58dvh);min-height:280px}.workspace-list,.workspace-preview{overscroll-behavior:auto}.stale-banner,.notice{margin-inline:14px}}@media (width<=420px){.metrics-band{grid-template-columns:repeat(2,minmax(0,1fr))}.metrics-band .metric-stat{min-height:94px}.metrics-band .metric-stat:last-child{border-bottom:0;border-right:0;grid-column:1/-1}.agent-header-summary span:nth-of-type(n+4),.app-topbar>div>span{display:none}}@media (prefers-reduced-motion:reduce){*,:before,:after{scroll-behavior:auto!important;transition-duration:.01ms!important;animation-duration:.01ms!important;animation-iteration-count:1!important}}
|
|
2
|
+
@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.hidden{display:none}}:root{--paper:#f4f0e8;--panel:#fbf8f1;--ink:#201c18;--subtle:#6e675e;--faint:#989084;--line:#ddd5c7;--accent:#a3402c;--accent-soft:#f2e3dc;--success:#2d6a4f;--warning:#9a6700;--danger:#a3402c;--shadow:0 14px 44px #33281f14;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light;font-synthesis:none;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}@media (prefers-color-scheme:dark){:root{--paper:#181513;--panel:#211d1a;--ink:#eee7dc;--subtle:#aaa195;--faint:#766d63;--line:#37302a;--accent:#d17862;--accent-soft:#3a2420;--success:#75b798;--warning:#e0ad55;--shadow:0 14px 44px #0000003d;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}}*{box-sizing:border-box}html,body,#root{min-height:100%}html{background:var(--paper);overflow-x:clip}body{background:var(--paper);color:var(--ink);margin:0;overflow-x:clip}button,input,select{font:inherit}button,select{cursor:pointer}button:disabled,select:disabled,input:disabled{cursor:not-allowed;opacity:.55}[hidden]{display:none!important}:focus-visible{outline:3px solid var(--accent)}@supports (color:color-mix(in lab, red, red)){:focus-visible{outline:3px solid color-mix(in srgb, var(--accent) 40%, transparent)}}:focus-visible{outline-offset:2px}.sr-only{clip:rect(0, 0, 0, 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.app-shell{grid-template-columns:292px minmax(0,1fr);min-height:100vh;display:grid}.app-shell.workspace-app-active{height:100dvh;min-height:0;overflow:hidden}.desktop-sidebar{border-right:1px solid var(--line);background:var(--panel);flex-direction:column;min-width:0;height:100vh;display:flex;position:sticky;top:0}@supports (color:color-mix(in lab, red, red)){.desktop-sidebar{background:color-mix(in srgb, var(--panel) 94%, transparent)}}.brand{border-bottom:1px solid var(--line);align-items:center;gap:12px;height:78px;padding:18px 22px;display:flex}.brand img{width:38px;height:38px}.brand strong{color:var(--accent);letter-spacing:-.03em;font:600 22px Georgia,serif}.brand-version{color:var(--faint);letter-spacing:0;white-space:nowrap;font:600 10px ui-monospace,monospace}.desktop-sidebar footer{border-top:1px solid var(--line);color:var(--faint);padding:13px 18px;font-size:11px}.sidebar-inner{flex-direction:column;flex:1;min-height:0;padding:14px 12px;display:flex}.agent-search,.table-search{border:1px solid var(--line);background:var(--paper);color:var(--faint);border-radius:9px;align-items:center;gap:8px;display:flex}.agent-search{margin-bottom:12px;padding:9px 11px}.agent-search input,.table-search input{width:100%;min-width:0;color:var(--ink);background:0 0;border:0;outline:0}.agent-list{align-content:start;gap:6px;min-height:0;display:grid;overflow-y:auto}.agent-list-item{width:100%;min-width:0;color:var(--subtle);text-align:left;background:0 0;border:1px solid #0000;border-radius:11px;grid-template-columns:42px minmax(0,1fr) 16px;align-items:center;gap:10px;padding:10px;display:grid}.agent-list-item:hover{background:var(--ink)}@supports (color:color-mix(in lab, red, red)){.agent-list-item:hover{background:color-mix(in srgb, var(--ink) 4%, transparent)}}.agent-list-item:hover{color:var(--ink)}.agent-list-item.selected{border-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.agent-list-item.selected{border-color:color-mix(in srgb, var(--accent) 42%, var(--line))}}.agent-list-item.selected{background:var(--accent-soft);color:var(--ink)}.agent-list-copy{gap:1px;min-width:0;display:grid}.agent-list-copy strong,.agent-list-copy small,.status-line{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.agent-list-copy strong{font-size:13px}.agent-list-copy small{color:var(--faint);font-size:10.5px}.status-line{color:var(--subtle);align-items:center;gap:4px;font-size:10px;display:flex}.agent-avatar{border:1px solid var(--line);background:var(--accent);border-radius:50%;flex:none;place-items:center;width:42px;height:42px;display:grid;position:relative;overflow:hidden}@supports (color:color-mix(in lab, red, red)){.agent-avatar{background:color-mix(in srgb, var(--accent) 12%, var(--panel))}}.agent-avatar{color:var(--accent);font:700 13px Georgia,serif}.agent-avatar img{object-fit:cover;width:100%;height:100%;display:block}.danger{color:var(--danger)}.workspace-shell{flex-direction:column;min-width:0;min-height:100vh;display:flex}.workspace-shell.workspace-route-active{height:100dvh;min-height:0;overflow:hidden}.workspace-route-active>.app-topbar,.workspace-route-active>.agent-header,.workspace-route-active>.agent-tabs,.workspace-route-active>.stale-banner,.workspace-route-active>.notice{flex:none}.app-topbar{z-index:20;border-bottom:1px solid var(--line);background:var(--paper);justify-content:space-between;align-items:center;gap:16px;height:64px;padding:0 28px;display:flex;position:sticky;top:0}@supports (color:color-mix(in lab, red, red)){.app-topbar{background:color-mix(in srgb, var(--paper) 94%, transparent)}}.app-topbar{-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px)}.app-topbar>div{align-items:center;gap:10px;min-width:0;display:flex}.app-topbar>div>strong{color:var(--accent);font:600 19px Georgia,serif;display:none}.app-topbar>div>span{color:var(--subtle);font-size:12px}.mobile-menu{display:none!important}.ui-button{border:1px solid var(--line);background:var(--panel);min-height:34px;color:var(--ink);border-radius:8px;justify-content:center;align-items:center;gap:7px;padding:7px 11px;font-size:12px;font-weight:600;display:inline-flex}.ui-button:hover{border-color:var(--accent);background:var(--accent-soft)}.ui-button.primary{border-color:var(--accent);background:var(--accent);color:#fff}.ui-button.icon-button{width:36px;padding:0}.ui-badge{border:1px solid var(--line);color:var(--subtle);background:var(--ink);border-radius:999px;align-items:center;padding:2px 8px;display:inline-flex}@supports (color:color-mix(in lab, red, red)){.ui-badge{background:color-mix(in srgb, var(--ink) 3%, var(--panel))}}.ui-badge{white-space:nowrap;font-size:10.5px;font-weight:600}.ui-badge.success{border-color:var(--success)}@supports (color:color-mix(in lab, red, red)){.ui-badge.success{border-color:color-mix(in srgb, var(--success) 55%, var(--line))}}.ui-badge.success{color:var(--success)}.ui-badge.warning{border-color:var(--warning)}@supports (color:color-mix(in lab, red, red)){.ui-badge.warning{border-color:color-mix(in srgb, var(--warning) 55%, var(--line))}}.ui-badge.warning{color:var(--warning)}.ui-badge.accent,.ui-badge.danger-badge{border-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.ui-badge.accent,.ui-badge.danger-badge{border-color:color-mix(in srgb, var(--accent) 55%, var(--line))}}.ui-badge.accent,.ui-badge.danger-badge{color:var(--accent)}.stale-banner,.notice{border:1px solid var(--warning);align-items:center;gap:8px;margin:16px 28px 0;display:flex}@supports (color:color-mix(in lab, red, red)){.stale-banner,.notice{border:1px solid color-mix(in srgb, var(--warning) 50%, var(--line))}}.stale-banner,.notice{background:var(--warning);border-radius:9px;padding:8px 11px}@supports (color:color-mix(in lab, red, red)){.stale-banner,.notice{background:color-mix(in srgb, var(--warning) 7%, var(--panel))}}.stale-banner,.notice{color:var(--warning);font-size:12px}.stale-banner .ui-button,.notice .ui-button{min-height:28px;margin-left:auto;padding-block:4px}.notice{border-color:var(--line);background:var(--panel);color:var(--subtle)}.agent-header{z-index:15;background:var(--paper);justify-content:space-between;align-items:center;gap:28px;min-width:0;padding:24px 30px 18px;display:flex;position:sticky;top:64px}@supports (color:color-mix(in lab, red, red)){.agent-header{background:color-mix(in srgb, var(--paper) 96%, transparent)}}.agent-header{-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px)}.agent-title{align-items:center;gap:13px;min-width:0;display:flex}.agent-title .agent-avatar{width:52px;height:52px}.agent-title div{min-width:0}.agent-title p{text-overflow:ellipsis;color:var(--faint);margin:0;font:10px ui-monospace,monospace;overflow:hidden}.agent-title h1{text-overflow:ellipsis;white-space:nowrap;letter-spacing:-.025em;margin:1px 0 0;font:600 clamp(23px,3vw,34px) Georgia,serif;overflow:hidden}.agent-header-summary{min-width:0;max-width:62%;color:var(--subtle);flex-wrap:wrap;justify-content:flex-end;gap:6px 14px;font-size:11.5px;display:flex}.agent-tabs{z-index:14;border-bottom:1px solid var(--line);background:var(--paper);gap:2px;padding:0 30px;display:flex;position:sticky;top:158px}@supports (color:color-mix(in lab, red, red)){.agent-tabs{background:color-mix(in srgb, var(--paper) 96%, transparent)}}.agent-tabs{scrollbar-width:thin;overflow-x:auto}.agent-tabs button{color:var(--subtle);background:0 0;border:0;border-bottom:2px solid #0000;flex:none;align-items:center;gap:7px;padding:11px 14px 9px;font-size:12px;font-weight:600;display:inline-flex}.agent-tabs button svg{width:14px;height:14px}.agent-tabs button:hover{color:var(--ink)}.agent-tabs button.active{color:var(--accent);border-bottom-color:var(--accent)}.agent-content{min-width:0;padding:24px 30px 64px}.agent-content>section{min-width:0}.agent-content.workspace-active{flex:1 1 0;height:auto;min-height:0;padding-bottom:24px;display:flex;overflow:hidden}.workspace-tab-panel{flex:1;min-height:0;display:flex}.overview-page{gap:28px;display:grid}.metrics-band{border-block:1px solid var(--line);grid-template-columns:repeat(4,minmax(0,1fr));min-width:0;display:grid}.metric-stat{flex-direction:column;min-width:0;min-height:126px;padding:16px 14px;display:flex}.metric-stat:not(:last-child){border-right:1px solid var(--line)}.metric-stat{border-bottom:1px solid var(--line)}.metric-stat:nth-child(4n){border-right:0}.metric-stat:nth-last-child(-n+3){border-bottom:0}.metric-stat>span{color:var(--faint);letter-spacing:.08em;text-transform:uppercase;margin-top:10px;font-size:9.5px;font-weight:700}.metric-stat>strong{text-overflow:ellipsis;margin-top:3px;font:600 18px Georgia,serif;overflow:hidden}.metric-stat>small{color:var(--subtle);margin-top:auto;font-size:10px}.metric-icon{width:20px;height:20px;color:var(--accent);place-items:center;display:grid}.metric-icon svg{width:15px;height:15px}.overview-sections{grid-template-columns:minmax(0,3fr) minmax(220px,1fr);gap:28px;min-width:0;display:grid}.content-section,.config-section,.group-policy-section,.logs-section{border-block:1px solid var(--line);min-width:0;padding:18px 0}.content-section h3,.config-section h3,.group-policy-section h3,.logs-section h3{margin:0;font:600 17px Georgia,serif}.section-heading{justify-content:space-between;align-items:flex-start;gap:16px;min-width:0;margin-bottom:14px;display:flex}.section-heading p{color:var(--subtle);margin:2px 0 0;font-size:11px}.facts{gap:0;margin:14px 0 0;display:grid}.facts div{border-top:1px solid var(--line);justify-content:space-between;align-items:baseline;gap:16px;padding:9px 0;display:flex}.facts dt{color:var(--subtle);font-size:11px}.facts dd{text-overflow:ellipsis;min-width:0;margin:0;font-size:12px;font-weight:600;overflow:hidden}.timeline{gap:0;margin:0;padding:0;list-style:none;display:grid}.timeline li{grid-template-columns:14px minmax(0,1fr);gap:10px;padding:8px 0;display:grid;position:relative}.timeline li:not(:last-child):before{content:"";background:var(--line);width:1px;position:absolute;top:21px;bottom:-7px;left:5px}.timeline-dot{z-index:1;border:2px solid var(--panel);background:var(--subtle);width:11px;height:11px;box-shadow:0 0 0 1px var(--line);border-radius:50%;margin-top:4px;position:relative}.timeline-dot.state-active{background:var(--warning)}.timeline-dot.state-idle{background:var(--success)}.timeline-dot.state-deliver{background:#3977b8}.timeline-dot.state-error{background:var(--danger)}.timeline-dot.state-unknown{background:var(--faint)}.timeline strong{font-size:11.5px}.timeline p{color:var(--subtle);overflow-wrap:anywhere;margin:1px 0;font-size:11px}.timeline time,.error-stack time{color:var(--faint);font-size:9.5px}.conversation-list,.reminder-list{border-top:1px solid var(--line);gap:0;max-width:900px;display:grid}.conversation-item,.reminder-list article{border:0;border-bottom:1px solid var(--line);background:0 0;padding:14px 10px}.conversation-item.outbound{border-left:3px solid var(--accent)}.conversation-item.inbound{border-left:3px solid var(--success)}.conversation-item.listening{border-left-color:var(--warning)}.conversation-item header{justify-content:space-between;gap:16px;display:flex}.conversation-item header>div{align-items:center;gap:8px;display:flex}.conversation-item header strong{font-size:12px}.conversation-item time,.conversation-item small{color:var(--faint);font-size:10px}.conversation-item p{white-space:pre-wrap;overflow-wrap:anywhere;margin:7px 0 0;font:13px/1.65 Georgia,serif}.reminder-list article{grid-template-columns:20px minmax(0,1fr) auto;align-items:center;gap:10px;display:grid}.reminder-list article.status-scheduled,.reminder-list article.status-pending{border-left:3px solid var(--warning)}.reminder-list article.status-fired{border-left:3px solid var(--success)}.reminder-list article.status-canceled{border-left:3px solid var(--faint)}.reminder-list article.status-failed{border-left:3px solid var(--danger)}.reminder-list article.done{opacity:.7;text-decoration:line-through}.reminder-list strong{font-size:12px}.reminder-list p{color:var(--subtle);margin:2px 0 0;font-size:10.5px}.configuration-page{gap:18px;display:grid}.cli-guidance{border-left:2px solid var(--accent);color:var(--subtle);margin:0 0 14px;padding:6px 10px;font-size:11px;line-height:1.55}.cli-guidance code{color:var(--ink);overflow-wrap:anywhere;font:600 10.5px ui-monospace,monospace}.config-grid{grid-template-columns:repeat(4,minmax(120px,1fr));gap:12px;display:grid}.provider-grid{grid-template-columns:repeat(2,minmax(160px,1fr))}.provider-status{color:var(--subtle);margin:0 0 12px;font-size:11px;line-height:1.5}.provider-logout{margin-top:12px}.config-grid label,.settings-form label,.chat-add label{min-width:0;color:var(--subtle);gap:5px;font-size:11px;font-weight:600;display:grid}.config-grid select,.config-grid input,.settings-form select,.chat-add select,.chat-add input,.policy-table select{border:1px solid var(--line);background:var(--paper);width:100%;min-width:0;min-height:37px;color:var(--ink);border-radius:8px;padding:7px 9px;font-size:12px}.config-grid input:disabled{color:var(--subtle)}.form-actions{flex-wrap:wrap;justify-content:flex-end;gap:8px;margin-top:16px;display:flex}.feedback{color:var(--subtle);margin:10px 0 0;font-size:11px}.table-search{min-width:min(300px,42vw);padding:7px 9px}.policy-table-wrap{width:100%;overflow-x:auto}.policy-table{border-collapse:collapse;width:100%;font-size:11px}.policy-table th{color:var(--faint);text-align:left;letter-spacing:.06em;text-transform:uppercase;font-size:9.5px}.policy-table th,.policy-table td{border-bottom:1px solid var(--line);vertical-align:middle;min-width:120px;padding:10px 8px}.policy-table th:first-child,.policy-table td:first-child{min-width:190px}.policy-table th:last-child,.policy-table td:last-child{min-width:150px}.policy-table td strong,.policy-table td code{display:block}.policy-table td code{color:var(--faint);margin-top:2px;font-size:9.5px}.policy-table td small{color:var(--faint);margin-top:2px;font-size:9.5px;display:block}.chat-add{grid-template-columns:minmax(190px,1fr) 140px auto;align-items:end;gap:9px;margin-top:14px;display:grid}.workspace-browser{border-block:1px solid var(--line);background:0 0;flex:1;grid-template-columns:minmax(240px,32%) minmax(0,1fr);min-width:0;min-height:0;display:grid;overflow:hidden}.workspace-side{border-right:1px solid var(--line);flex-direction:column;min-width:0;min-height:0;display:flex}.breadcrumbs{border-bottom:1px solid var(--line);white-space:nowrap;align-items:center;gap:3px;min-height:42px;padding:7px 10px;display:flex;overflow-x:auto}.breadcrumbs span{align-items:center;display:inline-flex}.breadcrumbs button{color:var(--accent);background:0 0;border:0;font-size:10.5px}.workspace-list{overscroll-behavior:contain;scrollbar-gutter:stable;flex:1 1 0;min-height:0;padding:6px;overflow:auto}.workspace-list>button{width:100%;min-width:0;color:var(--ink);text-align:left;background:0 0;border:0;border-radius:7px;grid-template-columns:18px minmax(0,1fr) auto;align-items:center;gap:7px;padding:7px 8px;font-size:11.5px;display:grid}.workspace-list>button:hover{background:var(--accent-soft)}.workspace-list>button span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.workspace-list>button small{color:var(--faint);font-size:9.5px}.workspace-preview{overscroll-behavior:contain;scrollbar-gutter:stable;min-width:0;min-height:0;overflow:auto}.workspace-preview>header{border-bottom:1px solid var(--line);background:var(--panel);justify-content:space-between;gap:12px;padding:11px 14px;display:flex;position:sticky;top:0}.workspace-preview header small{color:var(--faint)}.workspace-preview pre{white-space:pre-wrap;overflow-wrap:anywhere;margin:0;padding:16px;font:11.5px/1.65 ui-monospace,monospace}.logs-section{max-width:920px}.error-stack{border-top:1px solid var(--line);margin-top:18px;padding-top:14px}.error-stack h4{margin:0 0 8px;font-size:12px}.error-stack>div{color:var(--danger);grid-template-columns:16px minmax(0,1fr) auto;align-items:center;gap:8px;padding:7px 0;font-size:11px;display:grid}.empty-state{min-width:0;min-height:120px;color:var(--subtle);text-align:center;align-content:center;place-items:center;padding:20px;display:grid}.empty-state strong{color:var(--ink);font:600 15px Georgia,serif}.empty-state p{max-width:460px;margin:4px 0 0;font-size:11px}.page-loading{min-height:50vh;color:var(--subtle);justify-content:center;align-items:center;gap:10px;display:flex}.spin{animation:1s linear infinite spin}@keyframes spin{to{transform:rotate(360deg)}}.sheet-overlay{z-index:50;background:#14100d7a;animation:.15s ease-out fade-in;position:fixed;inset:0}.sheet-content{z-index:51;border-left:1px solid var(--line);background:var(--panel);width:min(440px,94vw);max-width:100%;color:var(--ink);box-shadow:var(--shadow);padding:22px;animation:.2s ease-out slide-in;position:fixed;inset:0 0 0 auto;overflow-y:auto}.sheet-head{border-bottom:1px solid var(--line);justify-content:space-between;align-items:flex-start;gap:16px;padding-bottom:18px;display:flex}.sheet-head h2{margin:0;font:600 24px Georgia,serif}.sheet-head p{color:var(--subtle);margin:4px 0 0;font-size:11.5px}.settings-form{padding-top:18px}.field-help{color:var(--subtle);font-size:11px}.compact-sidebar{padding:16px 0}@keyframes fade-in{0%{opacity:0}}@keyframes slide-in{0%{opacity:.5;transform:translate(24px)}}@media (width>=1600px){.metrics-band{grid-template-columns:repeat(7,minmax(0,1fr))}.metrics-band .metric-stat{border-right:1px solid var(--line);border-bottom:0}.metrics-band .metric-stat:last-child{border-right:0}}@media (width<=1100px){.config-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (width<=760px){.app-shell{display:block}.app-shell.workspace-app-active{height:auto;min-height:100vh;overflow:visible}.desktop-sidebar{display:none}.mobile-menu{display:inline-flex!important}.app-topbar{height:58px;padding:0 14px}.app-topbar>div>strong{display:inline}.agent-header{padding:17px 16px 12px;display:block;top:58px}.agent-header-summary{justify-content:flex-start;max-width:none;margin-top:12px}.agent-tabs{padding:0 8px;top:150px}.agent-tabs button{padding-inline:10px}.agent-content{padding:16px 14px 48px}.metrics-band{grid-template-columns:repeat(2,minmax(0,1fr))}.metrics-band .metric-stat{border-right:1px solid var(--line);border-bottom:1px solid var(--line);min-height:116px;padding:13px 10px}.metric-stat:nth-child(2n){border-right:0}.metric-stat:nth-last-child(-n+1){border-bottom:0}.overview-sections{grid-template-columns:1fr;gap:22px}.config-grid{grid-template-columns:1fr}.section-heading{display:block}.section-heading>.ui-badge,.section-heading>.table-search{margin-top:9px}.table-search{width:100%;min-width:0}.policy-table{display:block}.policy-table thead{clip:rect(0, 0, 0, 0);width:1px;height:1px;position:absolute;overflow:hidden}.policy-table tbody{border-top:1px solid var(--line);gap:0;display:grid}.policy-table tr{border:0;border-bottom:1px solid var(--line);gap:8px;min-width:0;padding:12px 0;display:grid}.policy-table td,.policy-table td:first-child,.policy-table td:last-child{border:0;min-width:0;padding:0}.policy-table td:before{color:var(--faint);text-transform:uppercase;margin-bottom:3px;font-size:9px;display:block}.policy-table td:nth-child(2):before{content:"消息策略"}.policy-table td:nth-child(3):before{content:"操作"}.chat-add{grid-template-columns:1fr}.workspace-shell,.workspace-shell.workspace-route-active{height:auto;min-height:100vh;display:block;overflow:visible}.agent-content.workspace-active{height:auto;min-height:0;display:block;overflow:visible}.workspace-tab-panel{display:block}.workspace-browser{grid-template-columns:1fr;height:auto;min-height:0;overflow:hidden}.workspace-side{border-right:0;border-bottom:1px solid var(--line);height:min(300px,42dvh)}.workspace-preview{height:min(520px,58dvh);min-height:280px}.workspace-list,.workspace-preview{overscroll-behavior:auto}.stale-banner,.notice{margin-inline:14px}}@media (width<=420px){.metrics-band{grid-template-columns:repeat(2,minmax(0,1fr))}.metrics-band .metric-stat{min-height:94px}.metrics-band .metric-stat:last-child{border-bottom:0;border-right:0;grid-column:1/-1}.agent-header-summary span:nth-of-type(n+4),.app-topbar>div>span{display:none}}@media (prefers-reduced-motion:reduce){*,:before,:after{scroll-behavior:auto!important;transition-duration:.01ms!important;animation-duration:.01ms!important;animation-iteration-count:1!important}}
|
|
3
3
|
/*$vite$:1*/
|