@qlingzzy/qling 1.0.0 → 1.1.1
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 +158 -0
- package/README.en.md +83 -18
- package/README.md +19 -9
- package/dist/agent/main-loop.d.ts +120 -0
- package/dist/agent/main-loop.d.ts.map +1 -0
- package/dist/agent/main-loop.js +279 -0
- package/dist/agent/subtask-parallel.d.ts +29 -0
- package/dist/agent/subtask-parallel.d.ts.map +1 -0
- package/dist/agent/subtask-parallel.js +107 -0
- package/dist/agent/subtask.d.ts +13 -0
- package/dist/agent/subtask.d.ts.map +1 -1
- package/dist/agent/subtask.js +79 -24
- package/dist/agent/system-prompt.d.ts +39 -0
- package/dist/agent/system-prompt.d.ts.map +1 -0
- package/dist/agent/system-prompt.js +89 -0
- package/dist/agent/tool-orchestrator.d.ts +66 -0
- package/dist/agent/tool-orchestrator.d.ts.map +1 -0
- package/dist/agent/tool-orchestrator.js +355 -0
- package/dist/agent-loop.d.ts +29 -16
- package/dist/agent-loop.d.ts.map +1 -1
- package/dist/agent-loop.js +262 -807
- package/dist/agents/roles.d.ts +57 -0
- package/dist/agents/roles.d.ts.map +1 -0
- package/dist/agents/roles.js +198 -0
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +17 -3
- package/dist/commands/claude-style.d.ts.map +1 -1
- package/dist/commands/claude-style.js +19 -10
- package/dist/commands/help.d.ts.map +1 -1
- package/dist/commands/help.js +3 -2
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +6 -0
- package/dist/commands/mode.d.ts +16 -0
- package/dist/commands/mode.d.ts.map +1 -0
- package/dist/commands/mode.js +67 -0
- package/dist/commands/recover.d.ts +3 -0
- package/dist/commands/recover.d.ts.map +1 -0
- package/dist/commands/recover.js +69 -0
- package/dist/commands/runtime.d.ts +2 -0
- package/dist/commands/runtime.d.ts.map +1 -1
- package/dist/commands/runtime.js +2 -0
- package/dist/commands/trace.d.ts +3 -0
- package/dist/commands/trace.d.ts.map +1 -0
- package/dist/commands/trace.js +45 -0
- package/dist/commands/verify.js +2 -2
- package/dist/config-report.d.ts +0 -1
- package/dist/config-report.d.ts.map +1 -1
- package/dist/config-report.js +1 -2
- package/dist/config.d.ts +0 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +0 -1
- package/dist/context-report.d.ts +13 -7
- package/dist/context-report.d.ts.map +1 -1
- package/dist/context-report.js +64 -61
- package/dist/context-tool-hygiene.d.ts +36 -0
- package/dist/context-tool-hygiene.d.ts.map +1 -0
- package/dist/context-tool-hygiene.js +125 -0
- package/dist/dashboard/client.d.ts +2 -0
- package/dist/dashboard/client.d.ts.map +1 -0
- package/dist/dashboard/client.js +305 -0
- package/dist/dashboard/model.d.ts +13 -0
- package/dist/dashboard/model.d.ts.map +1 -0
- package/dist/dashboard/model.js +112 -0
- package/dist/dashboard/page.d.ts +3 -0
- package/dist/dashboard/page.d.ts.map +1 -0
- package/dist/dashboard/page.js +204 -0
- package/dist/dashboard/types.d.ts +63 -0
- package/dist/dashboard/types.d.ts.map +1 -0
- package/dist/dashboard/types.js +1 -0
- package/dist/dashboard-server.d.ts +24 -4
- package/dist/dashboard-server.d.ts.map +1 -1
- package/dist/dashboard-server.js +397 -302
- package/dist/discovery-registry.d.ts +17 -3
- package/dist/discovery-registry.d.ts.map +1 -1
- package/dist/discovery-registry.js +78 -3
- package/dist/doctor.d.ts +8 -0
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +116 -0
- package/dist/eval/llm-tasks.d.ts +5 -0
- package/dist/eval/llm-tasks.d.ts.map +1 -0
- package/dist/eval/llm-tasks.js +125 -0
- package/dist/eval/repo-tasks.d.ts +12 -0
- package/dist/eval/repo-tasks.d.ts.map +1 -0
- package/dist/eval/repo-tasks.js +220 -0
- package/dist/eval/runner.d.ts +3 -1
- package/dist/eval/runner.d.ts.map +1 -1
- package/dist/eval/runner.js +23 -4
- package/dist/eval/tasks.d.ts.map +1 -1
- package/dist/eval/tasks.js +186 -0
- package/dist/eval/types.d.ts +8 -5
- package/dist/eval/types.d.ts.map +1 -1
- package/dist/execution/event-bus.d.ts +44 -0
- package/dist/execution/event-bus.d.ts.map +1 -0
- package/dist/execution/event-bus.js +76 -0
- package/dist/execution/failure-classifier.d.ts +11 -0
- package/dist/execution/failure-classifier.d.ts.map +1 -0
- package/dist/execution/failure-classifier.js +66 -0
- package/dist/execution/progress-detector.d.ts +3 -0
- package/dist/execution/progress-detector.d.ts.map +1 -0
- package/dist/execution/progress-detector.js +23 -0
- package/dist/execution/recovery-controller.d.ts +24 -0
- package/dist/execution/recovery-controller.d.ts.map +1 -0
- package/dist/execution/recovery-controller.js +114 -0
- package/dist/execution/recovery-messages.d.ts +24 -0
- package/dist/execution/recovery-messages.d.ts.map +1 -0
- package/dist/execution/recovery-messages.js +48 -0
- package/dist/execution/recovery-metrics.d.ts +16 -0
- package/dist/execution/recovery-metrics.d.ts.map +1 -0
- package/dist/execution/recovery-metrics.js +73 -0
- package/dist/execution/recovery-strategy-planner.d.ts +6 -0
- package/dist/execution/recovery-strategy-planner.d.ts.map +1 -0
- package/dist/execution/recovery-strategy-planner.js +24 -0
- package/dist/execution/run-trace-store.d.ts +29 -0
- package/dist/execution/run-trace-store.d.ts.map +1 -0
- package/dist/execution/run-trace-store.js +140 -0
- package/dist/execution/staged-verifier.d.ts +33 -0
- package/dist/execution/staged-verifier.d.ts.map +1 -0
- package/dist/execution/staged-verifier.js +39 -0
- package/dist/execution/types.d.ts +58 -0
- package/dist/execution/types.d.ts.map +1 -0
- package/dist/execution/types.js +1 -0
- package/dist/execution/verification-loop.d.ts +58 -0
- package/dist/execution/verification-loop.d.ts.map +1 -0
- package/dist/execution/verification-loop.js +195 -0
- package/dist/execution/verification-stages.d.ts +17 -0
- package/dist/execution/verification-stages.d.ts.map +1 -0
- package/dist/execution/verification-stages.js +102 -0
- package/dist/help-topics.d.ts.map +1 -1
- package/dist/help-topics.js +11 -0
- package/dist/index.js +0 -8
- package/dist/lsp/ts-service.d.ts +36 -0
- package/dist/lsp/ts-service.d.ts.map +1 -0
- package/dist/lsp/ts-service.js +291 -0
- package/dist/memory/lifecycle.d.ts +19 -0
- package/dist/memory/lifecycle.d.ts.map +1 -0
- package/dist/memory/lifecycle.js +53 -0
- package/dist/memory.d.ts +0 -16
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +0 -36
- package/dist/metrics/collector.d.ts +7 -0
- package/dist/metrics/collector.d.ts.map +1 -1
- package/dist/metrics/collector.js +60 -0
- package/dist/mission/manager.d.ts +1 -0
- package/dist/mission/manager.d.ts.map +1 -1
- package/dist/mission/manager.js +9 -0
- package/dist/mission/progress-notify.d.ts +39 -0
- package/dist/mission/progress-notify.d.ts.map +1 -0
- package/dist/mission/progress-notify.js +386 -0
- package/dist/pipeline/hooks.d.ts +1 -1
- package/dist/pipeline/hooks.d.ts.map +1 -1
- package/dist/pipeline/hooks.js +1 -0
- package/dist/pipeline/sections.d.ts +8 -4
- package/dist/pipeline/sections.d.ts.map +1 -1
- package/dist/pipeline/sections.js +70 -27
- package/dist/pipeline/verification.d.ts +1 -0
- package/dist/pipeline/verification.d.ts.map +1 -1
- package/dist/pipeline/verification.js +10 -7
- package/dist/providers/llm-client.d.ts +38 -0
- package/dist/providers/llm-client.d.ts.map +1 -0
- package/dist/providers/llm-client.js +105 -0
- package/dist/sdk.d.ts +1 -0
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +1 -0
- package/dist/session/durable-session-supervisor.d.ts.map +1 -1
- package/dist/session/durable-session-supervisor.js +13 -6
- package/dist/session/session-persistence.d.ts +29 -0
- package/dist/session/session-persistence.d.ts.map +1 -0
- package/dist/session/session-persistence.js +45 -0
- package/dist/session/session-scheduler.d.ts +8 -1
- package/dist/session/session-scheduler.d.ts.map +1 -1
- package/dist/session/session-scheduler.js +33 -4
- package/dist/session-task-report.d.ts +1 -0
- package/dist/session-task-report.d.ts.map +1 -1
- package/dist/session-task-report.js +2 -1
- package/dist/shortcuts.d.ts.map +1 -1
- package/dist/shortcuts.js +1 -0
- package/dist/skills/registry.d.ts.map +1 -1
- package/dist/skills/registry.js +10 -0
- package/dist/skills/security-scan.d.ts +15 -0
- package/dist/skills/security-scan.d.ts.map +1 -0
- package/dist/skills/security-scan.js +95 -0
- package/dist/skills/types.d.ts +2 -0
- package/dist/skills/types.d.ts.map +1 -1
- package/dist/statusline.d.ts +3 -3
- package/dist/statusline.d.ts.map +1 -1
- package/dist/statusline.js +9 -17
- package/dist/token-usage.d.ts +27 -0
- package/dist/token-usage.d.ts.map +1 -0
- package/dist/token-usage.js +107 -0
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +5 -3
- package/dist/tools/browser-act-session.d.ts +48 -0
- package/dist/tools/browser-act-session.d.ts.map +1 -0
- package/dist/tools/browser-act-session.js +168 -0
- package/dist/tools/browser-act.d.ts +14 -0
- package/dist/tools/browser-act.d.ts.map +1 -0
- package/dist/tools/browser-act.js +297 -0
- package/dist/tools/code-symbols.d.ts +35 -0
- package/dist/tools/code-symbols.d.ts.map +1 -0
- package/dist/tools/code-symbols.js +257 -0
- package/dist/tools/index.d.ts +4 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +22 -2
- package/dist/tools/lsp.d.ts +13 -0
- package/dist/tools/lsp.d.ts.map +1 -0
- package/dist/tools/lsp.js +136 -0
- package/dist/tools/patch.d.ts +5 -0
- package/dist/tools/patch.d.ts.map +1 -1
- package/dist/tools/patch.js +25 -4
- package/dist/tools/search.d.ts +7 -0
- package/dist/tools/search.d.ts.map +1 -1
- package/dist/tools/search.js +20 -3
- package/dist/tools/skill.d.ts +2 -0
- package/dist/tools/skill.d.ts.map +1 -1
- package/dist/tools/skill.js +47 -14
- package/dist/tools/subtask.d.ts +3 -1
- package/dist/tools/subtask.d.ts.map +1 -1
- package/dist/tools/subtask.js +151 -56
- package/dist/tui/shell.d.ts +12 -0
- package/dist/tui/shell.d.ts.map +1 -1
- package/dist/tui/shell.js +36 -3
- package/dist/tui/streaming-repl.d.ts +1 -0
- package/dist/tui/streaming-repl.d.ts.map +1 -1
- package/dist/tui/streaming-repl.js +27 -4
- package/dist/tui/streaming-tui.d.ts +10 -0
- package/dist/tui/streaming-tui.d.ts.map +1 -1
- package/dist/tui/streaming-tui.js +70 -12
- package/dist/types.d.ts +0 -8
- package/dist/types.d.ts.map +1 -1
- package/dist/workflow-runtime.d.ts.map +1 -1
- package/dist/workflow-runtime.js +10 -2
- package/dist/workflow-types.d.ts +2 -0
- package/dist/workflow-types.d.ts.map +1 -1
- package/docs/install.md +46 -12
- package/docs/skills.md +56 -7
- package/docs/web-routing.md +83 -0
- package/package.json +18 -4
- package/scripts/dep-layers.mjs +275 -0
- package/scripts/eval-llm.mjs +27 -0
- package/scripts/eval-recovery.mjs +101 -0
- package/scripts/eval-tasks.mjs +20 -0
- package/scripts/validate-packaging.mjs +57 -0
- package/skills/examples/README.md +23 -0
- package/skills/examples/add-function/SKILL.md +31 -0
- package/skills/examples/fix-failing-test/SKILL.md +32 -0
- package/skills/examples/pr-summary/SKILL.md +34 -0
- package/skills/lifecycle-build/SKILL.md +22 -0
- package/skills/lifecycle-plan/SKILL.md +32 -0
- package/skills/lifecycle-review/SKILL.md +25 -0
- package/skills/lifecycle-ship/SKILL.md +22 -0
- package/skills/lifecycle-spec/SKILL.md +24 -0
- package/skills/lifecycle-test/SKILL.md +21 -0
- package/skills/opencli/SKILL.md +222 -0
- package/skills/qling.md +14 -3
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
const ACTIVE = new Set(["running", "blocked", "queued", "paused"]);
|
|
2
|
+
let snapshot = null;
|
|
3
|
+
let selectedId = "";
|
|
4
|
+
let selectedKind = "";
|
|
5
|
+
let kindFilter = "all";
|
|
6
|
+
let statusFilter = "all";
|
|
7
|
+
let search = "";
|
|
8
|
+
let etag = "";
|
|
9
|
+
let activeRequest = null;
|
|
10
|
+
let refreshTimer = null;
|
|
11
|
+
let retryDelay = 3000;
|
|
12
|
+
let toastTimer = null;
|
|
13
|
+
function byId(id) {
|
|
14
|
+
const node = document.getElementById(id);
|
|
15
|
+
if (!node)
|
|
16
|
+
throw new Error(`dashboard element missing: ${id}`);
|
|
17
|
+
return node;
|
|
18
|
+
}
|
|
19
|
+
function node(tag, className, text) {
|
|
20
|
+
const el = document.createElement(tag);
|
|
21
|
+
if (className)
|
|
22
|
+
el.className = className;
|
|
23
|
+
if (text !== undefined)
|
|
24
|
+
el.textContent = text;
|
|
25
|
+
return el;
|
|
26
|
+
}
|
|
27
|
+
function formatTime(value) {
|
|
28
|
+
if (!value)
|
|
29
|
+
return "—";
|
|
30
|
+
return new Intl.DateTimeFormat("zh-CN", {
|
|
31
|
+
hour: "2-digit", minute: "2-digit", second: "2-digit",
|
|
32
|
+
}).format(value);
|
|
33
|
+
}
|
|
34
|
+
function relativeTime(value) {
|
|
35
|
+
if (!value)
|
|
36
|
+
return "—";
|
|
37
|
+
const seconds = Math.max(0, Math.floor((Date.now() - value) / 1000));
|
|
38
|
+
if (seconds < 60)
|
|
39
|
+
return `${seconds}s 前`;
|
|
40
|
+
if (seconds < 3600)
|
|
41
|
+
return `${Math.floor(seconds / 60)}m 前`;
|
|
42
|
+
if (seconds < 86400)
|
|
43
|
+
return `${Math.floor(seconds / 3600)}h 前`;
|
|
44
|
+
return `${Math.floor(seconds / 86400)}d 前`;
|
|
45
|
+
}
|
|
46
|
+
function statusLabel(status) {
|
|
47
|
+
return { running: "运行中", queued: "等待", blocked: "阻塞", paused: "暂停", succeeded: "完成", failed: "失败", canceled: "取消" }[status] ?? status;
|
|
48
|
+
}
|
|
49
|
+
function kindLabel(kind) {
|
|
50
|
+
return { mission: "MISSION", loop: "LOOP", workflow: "WORKFLOW" }[kind] ?? kind;
|
|
51
|
+
}
|
|
52
|
+
function filteredTasks() {
|
|
53
|
+
if (!snapshot)
|
|
54
|
+
return [];
|
|
55
|
+
const query = search.toLowerCase();
|
|
56
|
+
return snapshot.tasks.filter((task) => {
|
|
57
|
+
if (kindFilter !== "all" && task.kind !== kindFilter)
|
|
58
|
+
return false;
|
|
59
|
+
if (statusFilter === "active" && !ACTIVE.has(task.status))
|
|
60
|
+
return false;
|
|
61
|
+
if (statusFilter === "failed" && task.status !== "failed")
|
|
62
|
+
return false;
|
|
63
|
+
return !query || `${task.title} ${task.description} ${task.id} ${task.sessionId ?? ""}`.toLowerCase().includes(query);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function renderSummary() {
|
|
67
|
+
if (!snapshot)
|
|
68
|
+
return;
|
|
69
|
+
byId("summary-total").textContent = String(snapshot.summary.total);
|
|
70
|
+
byId("summary-running").textContent = String(snapshot.summary.running);
|
|
71
|
+
byId("summary-queued").textContent = String(snapshot.summary.queued + snapshot.summary.paused);
|
|
72
|
+
byId("summary-blocked").textContent = String(snapshot.summary.blocked);
|
|
73
|
+
byId("summary-failed").textContent = String(snapshot.summary.failed);
|
|
74
|
+
byId("updated-at").textContent = `同步于 ${formatTime(snapshot.generatedAt)}`;
|
|
75
|
+
byId("source-label").textContent = snapshot.runtime.daemonHealthy ? "DAEMON" : "LOCAL";
|
|
76
|
+
byId("runtime-label").textContent = snapshot.runtime.ready ? "运行时就绪" : "等待运行时";
|
|
77
|
+
byId("runtime-signal").classList.toggle("ready", snapshot.runtime.ready);
|
|
78
|
+
byId("permission-label").textContent = `权限 ${snapshot.runtime.permissionMode}`;
|
|
79
|
+
}
|
|
80
|
+
function renderTasks() {
|
|
81
|
+
const list = byId("task-list");
|
|
82
|
+
list.replaceChildren();
|
|
83
|
+
list.classList.remove("skeleton-stack");
|
|
84
|
+
list.setAttribute("aria-busy", "false");
|
|
85
|
+
const tasks = filteredTasks();
|
|
86
|
+
byId("visible-count").textContent = `${tasks.length} 项`;
|
|
87
|
+
if (tasks.length === 0) {
|
|
88
|
+
list.append(node("div", "empty-copy", "当前筛选下没有任务。可在 TUI 使用 /mission 或 /loop 创建。"));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
for (const task of tasks) {
|
|
92
|
+
const row = node("button", `task-row${task.id === selectedId ? " selected" : ""}`);
|
|
93
|
+
row.type = "button";
|
|
94
|
+
row.dataset.taskId = task.id;
|
|
95
|
+
row.dataset.taskKind = task.kind;
|
|
96
|
+
row.setAttribute("aria-pressed", String(task.id === selectedId));
|
|
97
|
+
const line = node("span", `status-line ${task.status}`);
|
|
98
|
+
line.setAttribute("aria-hidden", "true");
|
|
99
|
+
const copy = node("span", "task-copy");
|
|
100
|
+
const meta = node("span", "task-meta");
|
|
101
|
+
meta.append(node("span", "", kindLabel(task.kind)), node("span", "", statusLabel(task.status)), node("span", "", task.source.toUpperCase()));
|
|
102
|
+
copy.append(meta, node("span", "task-title", task.title), node("span", "task-description", task.description || "无补充说明"));
|
|
103
|
+
row.append(line, copy, node("time", "task-time", relativeTime(task.updatedAt)));
|
|
104
|
+
row.addEventListener("click", () => void selectTask(task));
|
|
105
|
+
list.append(row);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function renderActivity() {
|
|
109
|
+
const list = byId("activity-list");
|
|
110
|
+
list.replaceChildren();
|
|
111
|
+
const activity = snapshot?.activity ?? [];
|
|
112
|
+
if (activity.length === 0) {
|
|
113
|
+
list.append(node("li", "muted", "暂无本地活动指标"));
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
for (const event of activity) {
|
|
117
|
+
const item = node("li");
|
|
118
|
+
item.append(node("time", "", formatTime(event.ts)), node("span", "activity-type", event.type), node("span", "", summarizeData(event.data)));
|
|
119
|
+
list.append(item);
|
|
120
|
+
}
|
|
121
|
+
byId("activity-boundary").textContent = snapshot?.boundary.activityTruncated ? "已按 1 MiB 边界截断" : `最近 ${activity.length} 条`;
|
|
122
|
+
}
|
|
123
|
+
function summarizeData(data) {
|
|
124
|
+
return Object.entries(data).slice(0, 4).map(([key, value]) => `${key}=${String(value).slice(0, 60)}`).join(" · ") || "本地事件";
|
|
125
|
+
}
|
|
126
|
+
async function selectTask(task) {
|
|
127
|
+
selectedId = task.id;
|
|
128
|
+
selectedKind = task.kind;
|
|
129
|
+
renderTasks();
|
|
130
|
+
const pane = byId("detail-pane");
|
|
131
|
+
pane.classList.add("open");
|
|
132
|
+
const empty = byId("detail-empty");
|
|
133
|
+
const content = byId("detail-content");
|
|
134
|
+
empty.hidden = true;
|
|
135
|
+
content.hidden = false;
|
|
136
|
+
content.replaceChildren(node("p", "muted", "正在读取本地详情…"));
|
|
137
|
+
try {
|
|
138
|
+
const response = await fetch(`/api/tasks/${encodeURIComponent(task.kind)}/${encodeURIComponent(task.id)}`);
|
|
139
|
+
if (!response.ok)
|
|
140
|
+
throw new Error(`详情请求失败 (${response.status})`);
|
|
141
|
+
renderDetail(await response.json());
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
content.replaceChildren(node("p", "error-copy", error instanceof Error ? error.message : String(error)));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function renderDetail(detail) {
|
|
148
|
+
const task = detail.task;
|
|
149
|
+
const content = byId("detail-content");
|
|
150
|
+
content.replaceChildren();
|
|
151
|
+
const close = node("button", "icon-button detail-close", "关闭");
|
|
152
|
+
close.type = "button";
|
|
153
|
+
close.addEventListener("click", () => byId("detail-pane").classList.remove("open"));
|
|
154
|
+
content.append(close);
|
|
155
|
+
content.append(node("p", "detail-kicker", `${kindLabel(task.kind)} / ${statusLabel(task.status)} / ${task.source.toUpperCase()}`));
|
|
156
|
+
const title = node("h2", "detail-title", task.title);
|
|
157
|
+
content.append(title, node("p", "detail-description", task.description || "无补充说明"));
|
|
158
|
+
const stats = node("div", "detail-grid");
|
|
159
|
+
const values = [
|
|
160
|
+
["更新时间", formatTime(task.updatedAt)],
|
|
161
|
+
["会话", task.sessionId ?? "—"],
|
|
162
|
+
["工具调用", String(task.progress?.toolCalls ?? "—")],
|
|
163
|
+
["轮次", String(task.progress?.turns ?? "—")],
|
|
164
|
+
["Token", String(task.progress?.tokens ?? "—")],
|
|
165
|
+
["下次运行", formatTime(task.nextRunAt)],
|
|
166
|
+
];
|
|
167
|
+
for (const [label, value] of values) {
|
|
168
|
+
const stat = node("div", "detail-stat");
|
|
169
|
+
stat.append(node("span", "", label), node("strong", "", value));
|
|
170
|
+
stats.append(stat);
|
|
171
|
+
}
|
|
172
|
+
content.append(stats);
|
|
173
|
+
if (task.error)
|
|
174
|
+
content.append(node("p", "error-copy", `${task.error.code ? `[${task.error.code}] ` : ""}${task.error.message}`));
|
|
175
|
+
const actions = node("div", "detail-actions");
|
|
176
|
+
for (const action of task.actions) {
|
|
177
|
+
const button = node("button", `action-button ${action === "resume" || action === "retry" ? "primary" : action === "cancel" ? "danger" : ""}`, actionLabel(action));
|
|
178
|
+
button.type = "button";
|
|
179
|
+
button.addEventListener("click", () => void runAction(button, task, action));
|
|
180
|
+
actions.append(button);
|
|
181
|
+
}
|
|
182
|
+
if (task.actions.length)
|
|
183
|
+
content.append(actions);
|
|
184
|
+
const events = node("ol", "event-log");
|
|
185
|
+
for (const event of detail.events.slice(-30).reverse()) {
|
|
186
|
+
const item = node("li");
|
|
187
|
+
item.append(node("time", "", formatTime(Number(event.timestamp))), node("span", "", eventMessage(event)));
|
|
188
|
+
events.append(item);
|
|
189
|
+
}
|
|
190
|
+
if (detail.events.length)
|
|
191
|
+
content.append(node("p", "detail-kicker", "RECENT LOG"), events);
|
|
192
|
+
}
|
|
193
|
+
function eventMessage(event) {
|
|
194
|
+
const data = event.data && typeof event.data === "object" ? event.data : {};
|
|
195
|
+
return String(data.message ?? data.reason ?? data.action ?? event.type ?? "事件");
|
|
196
|
+
}
|
|
197
|
+
function actionLabel(action) {
|
|
198
|
+
return { pause: "暂停", resume: "恢复", cancel: "取消", retry: "重新执行" }[action] ?? action;
|
|
199
|
+
}
|
|
200
|
+
async function runAction(button, task, action) {
|
|
201
|
+
button.disabled = true;
|
|
202
|
+
const previous = button.textContent;
|
|
203
|
+
button.textContent = "处理中…";
|
|
204
|
+
try {
|
|
205
|
+
const response = await fetch(`/api/tasks/${encodeURIComponent(task.kind)}/${encodeURIComponent(task.id)}/${encodeURIComponent(action)}`, { method: "POST" });
|
|
206
|
+
const body = await response.json();
|
|
207
|
+
if (!response.ok)
|
|
208
|
+
throw new Error(body.message ?? `操作失败 (${response.status})`);
|
|
209
|
+
showToast(body.message ?? "操作已完成");
|
|
210
|
+
etag = "";
|
|
211
|
+
await refreshSnapshot(true);
|
|
212
|
+
const current = snapshot?.tasks.find((item) => item.id === selectedId && item.kind === selectedKind);
|
|
213
|
+
if (current)
|
|
214
|
+
await selectTask(current);
|
|
215
|
+
}
|
|
216
|
+
catch (error) {
|
|
217
|
+
showToast(error instanceof Error ? error.message : String(error), true);
|
|
218
|
+
}
|
|
219
|
+
finally {
|
|
220
|
+
button.disabled = false;
|
|
221
|
+
button.textContent = previous;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function showToast(message, error = false) {
|
|
225
|
+
const toast = byId("toast");
|
|
226
|
+
toast.textContent = message;
|
|
227
|
+
toast.classList.toggle("error", error);
|
|
228
|
+
toast.hidden = false;
|
|
229
|
+
if (toastTimer !== null)
|
|
230
|
+
window.clearTimeout(toastTimer);
|
|
231
|
+
toastTimer = window.setTimeout(() => { toast.hidden = true; }, 3200);
|
|
232
|
+
}
|
|
233
|
+
async function refreshSnapshot(force = false) {
|
|
234
|
+
if (document.hidden && !force)
|
|
235
|
+
return;
|
|
236
|
+
activeRequest?.abort();
|
|
237
|
+
activeRequest = new AbortController();
|
|
238
|
+
try {
|
|
239
|
+
const headers = {};
|
|
240
|
+
if (etag && !force)
|
|
241
|
+
headers["If-None-Match"] = etag;
|
|
242
|
+
const response = await fetch("/api/dashboard/snapshot", { headers, signal: activeRequest.signal });
|
|
243
|
+
if (response.status === 304) {
|
|
244
|
+
retryDelay = 3000;
|
|
245
|
+
scheduleRefresh();
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
if (!response.ok)
|
|
249
|
+
throw new Error(`快照请求失败 (${response.status})`);
|
|
250
|
+
etag = response.headers.get("etag") ?? "";
|
|
251
|
+
snapshot = await response.json();
|
|
252
|
+
renderSummary();
|
|
253
|
+
renderTasks();
|
|
254
|
+
renderActivity();
|
|
255
|
+
retryDelay = 3000;
|
|
256
|
+
scheduleRefresh();
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
if (error instanceof DOMException && error.name === "AbortError")
|
|
260
|
+
return;
|
|
261
|
+
byId("runtime-label").textContent = "连接中断";
|
|
262
|
+
showToast(error instanceof Error ? error.message : String(error), true);
|
|
263
|
+
retryDelay = Math.min(30000, retryDelay * 2);
|
|
264
|
+
scheduleRefresh();
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
function scheduleRefresh() {
|
|
268
|
+
if (refreshTimer !== null)
|
|
269
|
+
window.clearTimeout(refreshTimer);
|
|
270
|
+
if (!document.hidden)
|
|
271
|
+
refreshTimer = window.setTimeout(() => void refreshSnapshot(), retryDelay);
|
|
272
|
+
}
|
|
273
|
+
function bindFilters() {
|
|
274
|
+
byId("task-search").addEventListener("input", (event) => {
|
|
275
|
+
search = event.target.value.trim();
|
|
276
|
+
renderTasks();
|
|
277
|
+
});
|
|
278
|
+
document.querySelectorAll("[data-filter-kind]").forEach((button) => button.addEventListener("click", () => {
|
|
279
|
+
kindFilter = button.dataset.filterKind ?? "all";
|
|
280
|
+
document.querySelectorAll("[data-filter-kind]").forEach((item) => item.classList.toggle("active", item === button));
|
|
281
|
+
renderTasks();
|
|
282
|
+
}));
|
|
283
|
+
document.querySelectorAll("[data-filter-status]").forEach((button) => button.addEventListener("click", () => {
|
|
284
|
+
statusFilter = button.dataset.filterStatus ?? "active";
|
|
285
|
+
document.querySelectorAll("[data-filter-status]").forEach((item) => item.classList.toggle("active", item === button));
|
|
286
|
+
renderTasks();
|
|
287
|
+
}));
|
|
288
|
+
}
|
|
289
|
+
byId("refresh-button").addEventListener("click", () => void refreshSnapshot(true));
|
|
290
|
+
document.addEventListener("visibilitychange", () => {
|
|
291
|
+
if (document.hidden) {
|
|
292
|
+
if (refreshTimer !== null)
|
|
293
|
+
window.clearTimeout(refreshTimer);
|
|
294
|
+
activeRequest?.abort();
|
|
295
|
+
}
|
|
296
|
+
else
|
|
297
|
+
void refreshSnapshot(true);
|
|
298
|
+
});
|
|
299
|
+
document.addEventListener("keydown", (event) => {
|
|
300
|
+
if (event.key === "Escape")
|
|
301
|
+
byId("detail-pane").classList.remove("open");
|
|
302
|
+
});
|
|
303
|
+
bindFilters();
|
|
304
|
+
void refreshSnapshot(true);
|
|
305
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { LocalSessionTask } from "../session-task-report.js";
|
|
2
|
+
import type { Mission, MissionStatus } from "../mission/types.js";
|
|
3
|
+
import type { WorkflowCheckpoint } from "../workflow-types.js";
|
|
4
|
+
import type { DashboardTask, DashboardTaskAction } from "./types.js";
|
|
5
|
+
export declare function getMissionActions(status: MissionStatus, daemonHealthy: boolean): DashboardTaskAction[];
|
|
6
|
+
export declare function buildDashboardTasks(options: {
|
|
7
|
+
missions: Mission[];
|
|
8
|
+
loops: LocalSessionTask[];
|
|
9
|
+
workflow: WorkflowCheckpoint | null;
|
|
10
|
+
daemonHealthy: boolean;
|
|
11
|
+
now?: number;
|
|
12
|
+
}): DashboardTask[];
|
|
13
|
+
//# sourceMappingURL=model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/dashboard/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,KAAK,EACV,aAAa,EACb,mBAAmB,EAEpB,MAAM,YAAY,CAAC;AAiBpB,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,aAAa,EACrB,aAAa,EAAE,OAAO,GACrB,mBAAmB,EAAE,CASvB;AA+ED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE;IAC3C,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACpC,aAAa,EAAE,OAAO,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GAAG,aAAa,EAAE,CAYlB"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
const ACTIVE_RANK = {
|
|
2
|
+
running: 0,
|
|
3
|
+
blocked: 1,
|
|
4
|
+
queued: 2,
|
|
5
|
+
paused: 3,
|
|
6
|
+
failed: 10,
|
|
7
|
+
canceled: 11,
|
|
8
|
+
succeeded: 12,
|
|
9
|
+
};
|
|
10
|
+
function summarize(value, limit = 240) {
|
|
11
|
+
const text = String(value ?? "").replace(/\s+/g, " ").trim();
|
|
12
|
+
return text.length <= limit ? text : `${text.slice(0, limit - 1)}…`;
|
|
13
|
+
}
|
|
14
|
+
export function getMissionActions(status, daemonHealthy) {
|
|
15
|
+
if (status === "running" || status === "blocked" || status === "queued") {
|
|
16
|
+
return ["pause", "cancel"];
|
|
17
|
+
}
|
|
18
|
+
if (status === "paused")
|
|
19
|
+
return ["resume", "cancel"];
|
|
20
|
+
if (daemonHealthy && ["succeeded", "failed", "canceled"].includes(status)) {
|
|
21
|
+
return ["retry"];
|
|
22
|
+
}
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
function missionTask(mission, daemonHealthy) {
|
|
26
|
+
return {
|
|
27
|
+
id: mission.id,
|
|
28
|
+
kind: "mission",
|
|
29
|
+
title: summarize(mission.name, 100) || "未命名使命",
|
|
30
|
+
description: summarize(mission.description),
|
|
31
|
+
status: mission.status,
|
|
32
|
+
rawStatus: mission.status,
|
|
33
|
+
source: daemonHealthy ? "daemon" : "local",
|
|
34
|
+
sessionId: mission.sessionId,
|
|
35
|
+
createdAt: mission.createdAt,
|
|
36
|
+
updatedAt: mission.updatedAt,
|
|
37
|
+
startedAt: mission.metrics.startTime,
|
|
38
|
+
endedAt: mission.metrics.endTime,
|
|
39
|
+
progress: {
|
|
40
|
+
turns: mission.metrics.totalTurns,
|
|
41
|
+
tokens: mission.metrics.totalTokens,
|
|
42
|
+
toolCalls: mission.metrics.totalToolCalls,
|
|
43
|
+
},
|
|
44
|
+
error: mission.error
|
|
45
|
+
? { code: mission.error.code, message: summarize(mission.error.message, 300) }
|
|
46
|
+
: undefined,
|
|
47
|
+
actions: getMissionActions(mission.status, daemonHealthy),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function loopStatus(status) {
|
|
51
|
+
if (status === "active")
|
|
52
|
+
return "queued";
|
|
53
|
+
if (status === "completed")
|
|
54
|
+
return "succeeded";
|
|
55
|
+
return status;
|
|
56
|
+
}
|
|
57
|
+
function loopTask(task) {
|
|
58
|
+
const status = loopStatus(task.status);
|
|
59
|
+
return {
|
|
60
|
+
id: task.id,
|
|
61
|
+
kind: "loop",
|
|
62
|
+
title: summarize(task.prompt, 100) || "循环任务",
|
|
63
|
+
description: `每 ${Math.max(1, Math.round(task.intervalMs / 1000))} 秒执行 · ${task.mode}`,
|
|
64
|
+
status,
|
|
65
|
+
rawStatus: task.status,
|
|
66
|
+
source: task.runner === "daemon" ? "daemon" : "session",
|
|
67
|
+
sessionId: task.sessionId,
|
|
68
|
+
createdAt: task.createdAt,
|
|
69
|
+
updatedAt: task.updatedAt,
|
|
70
|
+
startedAt: task.lastRunAt,
|
|
71
|
+
nextRunAt: task.nextRunAt,
|
|
72
|
+
actions: status === "queued" || status === "running" ? ["cancel"] : [],
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function workflowTask(checkpoint) {
|
|
76
|
+
const status = checkpoint.status === "completed"
|
|
77
|
+
? "succeeded"
|
|
78
|
+
: checkpoint.status === "awaiting_approval"
|
|
79
|
+
? "blocked"
|
|
80
|
+
: checkpoint.status;
|
|
81
|
+
return {
|
|
82
|
+
id: checkpoint.runId,
|
|
83
|
+
kind: "workflow",
|
|
84
|
+
title: `Workflow · ${summarize(checkpoint.currentState, 80)}`,
|
|
85
|
+
description: summarize(checkpoint.workflowDefinition?.description ?? checkpoint.workflowId),
|
|
86
|
+
status,
|
|
87
|
+
rawStatus: checkpoint.status,
|
|
88
|
+
source: "local",
|
|
89
|
+
sessionId: checkpoint.sessionId,
|
|
90
|
+
createdAt: checkpoint.history[0]?.timestamp ?? checkpoint.updatedAt,
|
|
91
|
+
updatedAt: checkpoint.updatedAt,
|
|
92
|
+
progress: { toolCalls: checkpoint.completedToolResults.length },
|
|
93
|
+
error: checkpoint.error
|
|
94
|
+
? { message: summarize(checkpoint.error.message, 300) }
|
|
95
|
+
: undefined,
|
|
96
|
+
actions: [],
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
export function buildDashboardTasks(options) {
|
|
100
|
+
const tasks = [
|
|
101
|
+
...options.missions.map((mission) => missionTask(mission, options.daemonHealthy)),
|
|
102
|
+
...options.loops.map(loopTask),
|
|
103
|
+
...(options.workflow ? [workflowTask(options.workflow)] : []),
|
|
104
|
+
];
|
|
105
|
+
return tasks.sort((a, b) => {
|
|
106
|
+
const rank = ACTIVE_RANK[a.status] - ACTIVE_RANK[b.status];
|
|
107
|
+
if (rank !== 0)
|
|
108
|
+
return rank;
|
|
109
|
+
const updated = b.updatedAt - a.updatedAt;
|
|
110
|
+
return updated !== 0 ? updated : a.id.localeCompare(b.id);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare const DASHBOARD_HTML = "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <meta name=\"color-scheme\" content=\"dark\">\n <title>\u8F7B\u7075 \u00B7 \u4EFB\u52A1\u5DE5\u4F5C\u53F0</title>\n <link rel=\"stylesheet\" href=\"/assets/dashboard.css\">\n</head>\n<body>\n <div class=\"shell\">\n <header class=\"topbar\">\n <div class=\"brand-block\">\n <span class=\"brand-mark\" aria-hidden=\"true\">QL</span>\n <div><p class=\"eyebrow\">LOCAL AGENT CONTROL</p><h1>\u8F7B\u7075\u4EFB\u52A1\u5DE5\u4F5C\u53F0</h1></div>\n </div>\n <div class=\"runtime-strip\" aria-live=\"polite\">\n <span class=\"signal\" id=\"runtime-signal\"></span>\n <span id=\"runtime-label\">\u6B63\u5728\u8FDE\u63A5\u672C\u5730\u8FD0\u884C\u65F6</span>\n <span class=\"divider\"></span>\n <span id=\"source-label\">LOCAL</span>\n <button class=\"icon-button\" id=\"refresh-button\" type=\"button\">\u5237\u65B0</button>\n </div>\n </header>\n\n <section class=\"summary-band\" aria-label=\"\u4EFB\u52A1\u6458\u8981\">\n <div class=\"summary-lead\"><span>\u5F53\u524D\u6001\u52BF</span><strong id=\"summary-total\">\u2014</strong></div>\n <div class=\"summary-item\"><span>\u8FD0\u884C</span><strong id=\"summary-running\">\u2014</strong></div>\n <div class=\"summary-item\"><span>\u7B49\u5F85</span><strong id=\"summary-queued\">\u2014</strong></div>\n <div class=\"summary-item\"><span>\u963B\u585E</span><strong id=\"summary-blocked\">\u2014</strong></div>\n <div class=\"summary-item\"><span>\u5931\u8D25</span><strong id=\"summary-failed\">\u2014</strong></div>\n <time id=\"updated-at\">\u5C1A\u672A\u540C\u6B65</time>\n </section>\n\n <main class=\"workbench\">\n <section class=\"task-rail\" aria-labelledby=\"task-heading\">\n <div class=\"section-heading\">\n <div><p class=\"eyebrow\">TASK RAIL</p><h2 id=\"task-heading\">\u4EFB\u52A1\u8F68\u9053</h2></div>\n <span id=\"visible-count\">0 \u9879</span>\n </div>\n <label class=\"search-box\">\n <span aria-hidden=\"true\">\u2315</span>\n <input id=\"task-search\" type=\"search\" placeholder=\"\u641C\u7D22\u4EFB\u52A1\u3001\u4F1A\u8BDD\u6216\u72B6\u6001\" autocomplete=\"off\">\n </label>\n <div class=\"filter-row\" id=\"kind-filters\" aria-label=\"\u4EFB\u52A1\u7C7B\u578B\u7B5B\u9009\">\n <button class=\"filter active\" data-filter-kind=\"all\" type=\"button\">\u5168\u90E8</button>\n <button class=\"filter\" data-filter-kind=\"mission\" type=\"button\">\u4F7F\u547D</button>\n <button class=\"filter\" data-filter-kind=\"loop\" type=\"button\">\u5FAA\u73AF</button>\n <button class=\"filter\" data-filter-kind=\"workflow\" type=\"button\">\u5DE5\u4F5C\u6D41</button>\n </div>\n <div class=\"filter-row\" id=\"status-filters\" aria-label=\"\u4EFB\u52A1\u72B6\u6001\u7B5B\u9009\">\n <button class=\"filter active\" data-filter-status=\"all\" type=\"button\">\u6D3B\u8DC3\u4F18\u5148</button>\n <button class=\"filter\" data-filter-status=\"active\" type=\"button\">\u4EC5\u6D3B\u8DC3</button>\n <button class=\"filter\" data-filter-status=\"failed\" type=\"button\">\u4EC5\u5931\u8D25</button>\n </div>\n <div class=\"task-list skeleton-stack\" id=\"task-list\" aria-live=\"polite\" aria-busy=\"true\">\n <div class=\"skeleton\"></div><div class=\"skeleton\"></div><div class=\"skeleton\"></div>\n </div>\n </section>\n\n <aside class=\"detail-pane\" id=\"detail-pane\" aria-label=\"\u4EFB\u52A1\u8BE6\u60C5\">\n <div class=\"detail-empty\" id=\"detail-empty\">\n <span class=\"crosshair\" aria-hidden=\"true\">\uFF0B</span>\n <h2 id=\"detail-heading\">\u9009\u62E9\u4E00\u9879\u4EFB\u52A1</h2>\n <p>\u67E5\u770B\u6267\u884C\u6765\u6E90\u3001\u8FDB\u5EA6\u3001\u65E5\u5FD7\u548C\u5F53\u524D\u53EF\u7528\u64CD\u4F5C\u3002</p>\n </div>\n <div class=\"detail-content\" id=\"detail-content\" hidden></div>\n </aside>\n </main>\n\n <section class=\"activity-panel\" aria-labelledby=\"activity-heading\">\n <div class=\"section-heading\"><div><p class=\"eyebrow\">RECENT SIGNALS</p><h2 id=\"activity-heading\">\u6700\u8FD1\u6D3B\u52A8</h2></div><span id=\"activity-boundary\">\u6700\u591A 20 \u6761</span></div>\n <ol id=\"activity-list\" class=\"activity-list\"><li class=\"muted\">\u7B49\u5F85\u672C\u5730\u6307\u6807\u2026</li></ol>\n </section>\n\n <footer class=\"boundary-bar\">\n <span>\u4EC5\u76D1\u542C 127.0.0.1</span><span>\u4EFB\u52A1\u6B63\u6587\u4E0D\u5916\u4F20</span><span id=\"permission-label\">\u6743\u9650 \u2014</span>\n </footer>\n </div>\n <div id=\"toast\" class=\"toast\" role=\"status\" aria-live=\"polite\" hidden></div>\n <script type=\"module\" src=\"/assets/dashboard.js\"></script>\n</body>\n</html>";
|
|
2
|
+
export declare const DASHBOARD_CSS = "\n:root {\n --ink: #dce8e2; --muted: #81928b; --dim: #53635d;\n --ground: #0b100e; --surface: #111815; --raised: #17201c;\n --line: #28372f; --line-strong: #3b5046; --accent: #63d5a2;\n --running: #63d5a2; --queued: #d6b865; --blocked: #df9665;\n --failed: #e27676; --paused: #8ca7d8; --radius: 3px;\n}\n* { box-sizing: border-box; }\nbody { margin: 0; min-height: 100vh; color: var(--ink); background: var(--ground); font-family: \"Aptos\", \"Microsoft YaHei UI\", sans-serif; }\nbody::before { content: \"\"; position: fixed; inset: 0; pointer-events: none; opacity: .25; background-image: linear-gradient(var(--line) 1px, transparent 1px), linear-gradient(90deg, var(--line) 1px, transparent 1px); background-size: 48px 48px; mask-image: linear-gradient(to bottom, black, transparent 72%); }\nbutton, input { font: inherit; }\nbutton { color: inherit; }\n.shell { position: relative; width: min(1540px, 100%); margin: 0 auto; padding: clamp(18px, 3vw, 42px); }\n.topbar { display: flex; align-items: center; justify-content: space-between; gap: 24px; padding-bottom: 22px; border-bottom: 1px solid var(--line-strong); }\n.brand-block { display: flex; align-items: center; gap: 14px; }\n.brand-mark { display: grid; place-items: center; width: 44px; aspect-ratio: 1; border: 1px solid var(--accent); color: var(--accent); font: 700 13px/1 \"Cascadia Code\", monospace; letter-spacing: .12em; transform: rotate(-3deg); }\n.eyebrow { margin: 0 0 4px; color: var(--accent); font: 600 10px/1.2 \"Cascadia Code\", monospace; letter-spacing: .2em; }\nh1, h2, p { margin-top: 0; }\nh1 { margin-bottom: 0; font-size: clamp(22px, 3vw, 34px); font-weight: 650; letter-spacing: -.04em; }\nh2 { margin-bottom: 0; font-size: 18px; font-weight: 620; }\n.runtime-strip { display: flex; align-items: center; gap: 10px; color: var(--muted); font: 12px \"Cascadia Code\", monospace; }\n.signal { width: 8px; height: 8px; border-radius: 50%; background: var(--queued); box-shadow: 0 0 0 4px color-mix(in srgb, var(--queued) 14%, transparent); }\n.signal.ready { background: var(--running); box-shadow: 0 0 0 4px color-mix(in srgb, var(--running) 14%, transparent); }\n.divider { width: 1px; height: 18px; background: var(--line-strong); }\n.icon-button, .filter, .action-button { border: 1px solid var(--line-strong); border-radius: var(--radius); background: transparent; cursor: pointer; transition: border-color .18s ease, background .18s ease, transform .18s ease; }\n.icon-button { padding: 7px 11px; }\n.icon-button:hover, .filter:hover, .action-button:hover { border-color: var(--accent); }\n.icon-button:active, .action-button:active { transform: translateY(1px); }\nbutton:focus-visible, input:focus-visible, .task-row:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }\n.summary-band { display: grid; grid-template-columns: minmax(180px, 1.3fr) repeat(4, minmax(90px, .55fr)) minmax(170px, 1fr); border-bottom: 1px solid var(--line); }\n.summary-band > * { min-height: 88px; padding: 20px 18px; border-right: 1px solid var(--line); display: flex; flex-direction: column; justify-content: center; }\n.summary-band > *:last-child { border-right: 0; }\n.summary-band span, .summary-band time { color: var(--muted); font: 11px \"Cascadia Code\", monospace; }\n.summary-band strong { margin-top: 5px; font: 650 26px \"Cascadia Code\", monospace; }\n.summary-lead { background: var(--accent); color: #092016; }\n.summary-lead span { color: #244d3b; }\n.summary-band time { align-items: flex-end; text-align: right; }\n.workbench { display: grid; grid-template-columns: minmax(360px, .9fr) minmax(500px, 1.35fr); min-height: 560px; border-bottom: 1px solid var(--line-strong); }\n.task-rail { padding: 28px 26px 28px 0; border-right: 1px solid var(--line-strong); }\n.detail-pane { position: relative; padding: 32px 0 32px 34px; min-width: 0; }\n.section-heading { display: flex; align-items: end; justify-content: space-between; gap: 16px; margin-bottom: 20px; }\n.section-heading > span { color: var(--muted); font: 11px \"Cascadia Code\", monospace; }\n.search-box { height: 42px; display: flex; align-items: center; gap: 10px; padding: 0 12px; border: 1px solid var(--line-strong); background: var(--surface); }\n.search-box span { color: var(--accent); font-size: 20px; }\n.search-box input { width: 100%; border: 0; outline: 0; color: var(--ink); background: transparent; }\n.search-box input::placeholder { color: var(--dim); }\n.filter-row { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 10px; }\n.filter { padding: 6px 10px; color: var(--muted); font-size: 11px; }\n.filter.active { color: #092016; border-color: var(--accent); background: var(--accent); }\n.task-list { display: grid; gap: 1px; margin-top: 18px; background: var(--line); border: 1px solid var(--line); max-height: 620px; overflow: auto; }\n.task-row { position: relative; display: grid; grid-template-columns: 7px 1fr auto; gap: 13px; width: 100%; padding: 16px 14px 15px 0; border: 0; text-align: left; background: var(--surface); cursor: pointer; }\n.task-row:hover, .task-row.selected { background: var(--raised); }\n.task-row.selected::after { content: \"\"; position: absolute; inset: 0; border: 1px solid var(--accent); pointer-events: none; }\n.status-line { width: 3px; height: 100%; justify-self: center; background: var(--dim); }\n.status-line.running { background: var(--running); } .status-line.queued { background: var(--queued); } .status-line.blocked { background: var(--blocked); } .status-line.failed { background: var(--failed); } .status-line.paused { background: var(--paused); }\n.task-copy { min-width: 0; }\n.task-meta { display: flex; gap: 8px; margin-bottom: 7px; color: var(--muted); font: 10px \"Cascadia Code\", monospace; text-transform: uppercase; letter-spacing: .08em; }\n.task-title { display: block; margin-bottom: 6px; overflow: hidden; color: var(--ink); font-weight: 620; text-overflow: ellipsis; white-space: nowrap; }\n.task-description { display: block; overflow: hidden; color: var(--muted); font-size: 12px; line-height: 1.45; text-overflow: ellipsis; white-space: nowrap; }\n.task-time { color: var(--dim); font: 10px \"Cascadia Code\", monospace; white-space: nowrap; }\n.detail-empty { min-height: 420px; display: grid; place-content: center; justify-items: center; text-align: center; color: var(--muted); }\n.detail-empty p { max-width: 300px; margin-top: 10px; line-height: 1.6; }\n.crosshair { display: grid; place-items: center; width: 64px; height: 64px; margin-bottom: 20px; border: 1px dashed var(--line-strong); color: var(--accent); font: 28px \"Cascadia Code\", monospace; }\n.detail-content { position: relative; animation: reveal .28s cubic-bezier(.22,1,.36,1); }\n.detail-close { position: absolute; top: 0; right: 0; }\n@keyframes reveal { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }\n.detail-kicker { color: var(--accent); font: 11px \"Cascadia Code\", monospace; text-transform: uppercase; letter-spacing: .12em; }\n.detail-title { max-width: 760px; margin: 10px 0 14px; font-size: clamp(25px, 3vw, 40px); line-height: 1.05; letter-spacing: -.04em; }\n.detail-description { max-width: 760px; color: var(--muted); line-height: 1.7; }\n.detail-grid { display: grid; grid-template-columns: repeat(3, 1fr); margin: 28px 0; border-block: 1px solid var(--line); }\n.detail-stat { padding: 16px 12px 16px 0; }\n.detail-stat span { display: block; color: var(--dim); font: 10px \"Cascadia Code\", monospace; text-transform: uppercase; }\n.detail-stat strong { display: block; margin-top: 7px; font: 600 14px \"Cascadia Code\", monospace; }\n.detail-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 28px; }\n.action-button { padding: 9px 14px; }\n.action-button.primary { color: #092016; border-color: var(--accent); background: var(--accent); }\n.action-button.danger { color: var(--failed); border-color: color-mix(in srgb, var(--failed) 65%, var(--line)); }\n.event-log { display: grid; gap: 0; padding: 0; list-style: none; border-top: 1px solid var(--line); }\n.event-log li { display: grid; grid-template-columns: 90px 1fr; gap: 14px; padding: 11px 0; border-bottom: 1px solid var(--line); color: var(--muted); font-size: 12px; }\n.event-log time { color: var(--dim); font: 10px \"Cascadia Code\", monospace; }\n.activity-panel { padding: 28px 0; }\n.activity-list { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0 28px; padding: 0; list-style: none; }\n.activity-list li { display: grid; grid-template-columns: 88px 110px 1fr; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--line); color: var(--muted); font-size: 12px; }\n.activity-list time, .activity-type { color: var(--dim); font: 10px \"Cascadia Code\", monospace; }\n.boundary-bar { display: flex; flex-wrap: wrap; gap: 8px 24px; padding-top: 18px; border-top: 1px solid var(--line-strong); color: var(--dim); font: 10px \"Cascadia Code\", monospace; text-transform: uppercase; letter-spacing: .08em; }\n.boundary-bar span::before { content: \"\u25A1\"; margin-right: 7px; color: var(--accent); }\n.skeleton-stack { background: transparent; border: 0; }\n.skeleton { height: 78px; margin-bottom: 1px; background: linear-gradient(90deg, var(--surface), var(--raised), var(--surface)); background-size: 200% 100%; animation: scan 1.4s linear infinite; }\n@keyframes scan { to { background-position: -200% 0; } }\n.muted, .empty-copy { color: var(--muted); }\n.empty-copy { padding: 34px 20px; text-align: center; background: var(--surface); }\n.error-copy { color: var(--failed); }\n.toast { position: fixed; right: 24px; bottom: 24px; z-index: 10; max-width: min(420px, calc(100vw - 32px)); padding: 13px 16px; border: 1px solid var(--line-strong); background: var(--raised); box-shadow: 0 16px 50px #0008; font-size: 13px; }\n.toast.error { border-color: var(--failed); }\n@media (max-width: 880px) {\n .shell { padding: 18px; }\n .topbar { align-items: flex-start; }\n .runtime-strip { flex-wrap: wrap; justify-content: flex-end; }\n .summary-band { grid-template-columns: repeat(3, 1fr); }\n .summary-band > * { min-height: 68px; padding: 13px; }\n .summary-band time { align-items: flex-start; text-align: left; }\n .workbench { display: block; }\n .task-rail { padding-right: 0; border-right: 0; }\n .detail-pane { position: fixed; inset: auto 0 0; z-index: 8; max-height: 78vh; padding: 24px 20px; overflow: auto; border-top: 1px solid var(--accent); background: var(--ground); transform: translateY(105%); transition: transform .28s cubic-bezier(.22,1,.36,1); }\n .detail-pane.open { transform: none; }\n .detail-empty { display: none; }\n .detail-grid { grid-template-columns: repeat(2, 1fr); }\n .activity-list { grid-template-columns: 1fr; }\n}\n@media (max-width: 560px) {\n .brand-mark { width: 38px; }\n .runtime-strip .divider, #source-label { display: none; }\n .summary-band { grid-template-columns: repeat(2, 1fr); }\n .summary-lead { grid-column: span 2; }\n .summary-band time { grid-column: span 2; }\n .task-rail { padding-top: 22px; }\n .activity-list li { grid-template-columns: 72px 88px 1fr; }\n}\n@media (prefers-reduced-motion: reduce) { *, *::before, *::after { scroll-behavior: auto !important; animation: none !important; transition: none !important; } }\n";
|
|
3
|
+
//# sourceMappingURL=page.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../src/dashboard/page.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,k7JAkFnB,CAAC;AAET,eAAO,MAAM,aAAa,8iWAwHzB,CAAC"}
|