@zq-silk/yui 0.15.6 → 0.15.8
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/ARCHITECTURE.md +192 -399
- package/README.md +127 -1149
- package/dist/agent/adapterCatalog.js +15 -2
- package/dist/agent/agent.js +23 -3
- package/dist/agent/argumentPolicy.js +7 -1
- package/dist/agent/connectionPlan.js +62 -0
- package/dist/agent/executionComponents.js +158 -0
- package/dist/agent/launchEnvironment.js +31 -3
- package/dist/agent/managedRuntimeEnvironment.js +3 -5
- package/dist/{turn/turn.js → agentRun/agentRun.js} +166 -109
- package/dist/{turn/turnIdentity.js → agentRun/runIdentity.js} +4 -4
- package/dist/brief/taskBrief.js +12 -0
- package/dist/cli/agentConfigurationPicker.js +13 -0
- package/dist/cli/commandCatalog.js +167 -70
- package/dist/cli/interactionCandidates.js +5 -5
- package/dist/cli/interactionPolicy.js +38 -8
- package/dist/cli/invocationRouter.js +1 -1
- package/dist/cli/managedDiagnostics.js +28 -0
- package/dist/cli/operatorWizard.js +1 -7
- package/dist/cli/roleOptionOrder.js +27 -0
- package/dist/cli/roleWizard.js +50 -14
- package/dist/cli/updateOrchestrator.js +1 -1
- package/dist/cli/updatePorts.js +3 -4
- package/dist/cli.js +188 -95
- package/dist/commands/agentCommands.js +72 -14
- package/dist/commands/capabilityCommands.js +57 -0
- package/dist/commands/configCommands.js +20 -20
- package/dist/commands/deliveryGuardPreflight.js +2 -2
- package/dist/commands/executionAuditCommands.js +24 -24
- package/dist/commands/globalRoleCommands.js +1 -1
- package/dist/commands/grantCommands.js +4 -4
- package/dist/commands/operatorCommands.js +1 -7
- package/dist/commands/projectCommands.js +4 -4
- package/dist/commands/resourcesCommands.js +2 -2
- package/dist/commands/roleConfiguration.js +25 -5
- package/dist/commands/roleRuntimeGuard.js +4 -5
- package/dist/commands/sessionCommands.js +3 -7
- package/dist/commands/taskActivationCommands.js +259 -0
- package/dist/commands/taskActor.js +28 -49
- package/dist/commands/taskCommands.js +1216 -730
- package/dist/commands/taskContextCommand.js +39 -583
- package/dist/commands/taskExecutionCommands.js +32 -32
- package/dist/commands/taskInputCommands.js +40 -104
- package/dist/commands/taskIntegrationCommands.js +3 -2
- package/dist/commands/taskIntegrationQueueCommands.js +1 -1
- package/dist/commands/taskNextActionCommand.js +8 -8
- package/dist/commands/taskOverviewCommand.js +33 -45
- package/dist/commands/taskRemoteDeliveryCommand.js +2 -2
- package/dist/commands/taskRoleRuntimeStatus.js +133 -102
- package/dist/commands/telemetryCommands.js +36 -38
- package/dist/config/configCatalog.js +4 -4
- package/dist/config/yuiConfig.js +8 -8
- package/dist/context/contextSnapshot.js +10 -10
- package/dist/context/dispatchContext.js +11 -11
- package/dist/context/roleSessionContext.js +6 -3
- package/dist/context/{turnContextPack.js → runContextPack.js} +146 -81
- package/dist/context/{turnInputContract.js → runInputContract.js} +73 -60
- package/dist/context/sessionBootstrapManifest.js +21 -2
- package/dist/context/sourceRunContext.js +30 -0
- package/dist/context/taskContext.js +458 -0
- package/dist/context/wakeNotification.js +27 -27
- package/dist/controller/agentRuntimeObserver.js +21 -24
- package/dist/controller/capabilityBridge.js +77 -0
- package/dist/controller/clientRuntime.js +65 -92
- package/dist/controller/controller.js +127 -188
- package/dist/controller/fileSchedulerStoreAdapter.js +787 -887
- package/dist/controller/jobControl.js +54 -85
- package/dist/controller/resourceInventory.js +8 -27
- package/dist/controller/resourceInventoryLinux.js +12 -13
- package/dist/controller/runtime.js +530 -476
- package/dist/controller/runtimeEventInbox.js +55 -25
- package/dist/controller/runtimeEventProcessor.js +22 -31
- package/dist/controller/{runtimeHookTurnFence.js → runtimeHookRunFence.js} +91 -115
- package/dist/controller/runtimeLaunchCoordinator.js +80 -426
- package/dist/controller/runtimeObservationHook.js +14 -18
- package/dist/controller/sessionNotify.js +16 -24
- package/dist/controller/sessionOwnerReconciliation.js +168 -50
- package/dist/controller/structuredProviderObservation.js +138 -99
- package/dist/coordination/workMailbox.js +3 -3
- package/dist/coordination/workMailboxQueue.js +36 -33
- package/dist/core/boundedRpc.js +8 -1
- package/dist/core/controllerClient.js +20 -1
- package/dist/core/controllerServer.js +4 -4
- package/dist/doctor/doctor.js +13 -2
- package/dist/domain/agentResultTransport.js +9 -9
- package/dist/execution/codexThreadNaming.js +2 -8
- package/dist/execution/executionHealth.js +51 -63
- package/dist/execution/reviewMainRun.js +137 -0
- package/dist/execution/workItemExecution.js +28 -29
- package/dist/execution/workItemExecutionProjection.js +99 -107
- package/dist/execution/workItemMainRun.js +141 -0
- package/dist/executor/agentAdapter.js +227 -20
- package/dist/executor/agentConfigurationCatalog.js +126 -4
- package/dist/executor/agentConfigurationProbe.js +162 -4
- package/dist/executor/agentExecutor.js +79 -78
- package/dist/executor/effectiveLaunch.js +105 -18
- package/dist/executor/executorRegistry.js +29 -44
- package/dist/executor/fileRoleLaunchPlanner.js +229 -154
- package/dist/executor/workspacePreflightClassification.js +16 -16
- package/dist/grant/capabilityGrant.js +6 -3
- package/dist/input/inputRequest.js +12 -10
- package/dist/integration/gitIntegrationService.js +4 -11
- package/dist/integration/integrationQueueService.js +4 -4
- package/dist/interaction/operatorPresentation.js +1 -1
- package/dist/kernel/builtinCapabilities.js +423 -0
- package/dist/kernel/capabilityRegistry.js +314 -0
- package/dist/kernel/capabilitySchema.js +91 -0
- package/dist/kernel/instanceHost.js +18 -1
- package/dist/kernel/kernelPorts.js +4 -1
- package/dist/lifecycle/canonicalLifecycleEvent.js +44 -49
- package/dist/lifecycle/exactRunTerminalization.js +449 -0
- package/dist/message/message.js +62 -6
- package/dist/message/messageContinuation.js +204 -0
- package/dist/observability/executionAudit.js +70 -72
- package/dist/observability/faultClassification.js +2 -2
- package/dist/observability/orchestrationMetrics.js +8 -8
- package/dist/operator/operatorSessionHistory.js +1 -7
- package/dist/output/agentConfigurationPresentation.js +8 -3
- package/dist/output/agentRunConfigurationPresentation.js +128 -0
- package/dist/output/rolePresentation.js +54 -3
- package/dist/plugins/pluginChild.js +104 -0
- package/dist/plugins/pluginIntent.js +26 -0
- package/dist/plugins/pluginInterpreter.js +43 -0
- package/dist/plugins/pluginPackage.js +101 -0
- package/dist/plugins/pluginProcess.js +112 -0
- package/dist/plugins/pluginService.js +380 -0
- package/dist/profile/agentProfile.js +1 -1
- package/dist/repository/gitWorkspace.js +26 -4
- package/dist/repository/project.js +19 -4
- package/dist/repository/taskBaseFreshness.js +13 -13
- package/dist/repository/taskWorkspaceCoordinator.js +20 -27
- package/dist/repository/taskWorkspacePreparer.js +344 -83
- package/dist/resources/autoResourceGc.js +3 -3
- package/dist/resources/liveReferences.js +3 -3
- package/dist/resources/projectResource.js +123 -0
- package/dist/resources/projectResourceService.js +421 -0
- package/dist/resources/resourceDiscovery.js +6 -6
- package/dist/resources/resourceGc.js +1 -1
- package/dist/resources/resourceRegistrar.js +1 -1
- package/dist/resources/resourceTypes.js +1 -1
- package/dist/review/deltaRecheck.js +3 -3
- package/dist/review/reviewAcceptance.js +16 -16
- package/dist/review/reviewDecision.js +7 -7
- package/dist/review/reviewRound.js +21 -20
- package/dist/review/reviewerAvailability.js +2 -2
- package/dist/role/role.js +51 -7
- package/dist/role/taskRoleUpdate.js +30 -0
- package/dist/runtime/acpProtocol.js +425 -0
- package/dist/runtime/acpSession.js +731 -0
- package/dist/runtime/acpSessionConfiguration.js +260 -0
- package/dist/runtime/agentDriver.js +30 -11
- package/dist/runtime/agentEndpoint.js +278 -0
- package/dist/runtime/agentEndpointIdentity.js +86 -0
- package/dist/runtime/agentEndpointOwnership.js +239 -0
- package/dist/runtime/agentError.js +2 -10
- package/dist/runtime/agentHost.js +565 -314
- package/dist/runtime/agentRunConfiguration.js +258 -0
- package/dist/runtime/builtinAgentDrivers.js +134 -18
- package/dist/runtime/builtinAgentErrorMappers.js +55 -3
- package/dist/runtime/builtinTranscriptUsage.js +1 -1
- package/dist/runtime/claude-process-owner +0 -0
- package/dist/runtime/codexAppServerRuntime.js +38 -30
- package/dist/runtime/codexInteractiveHost.js +41 -6
- package/dist/runtime/continuationManager.js +2 -6
- package/dist/runtime/executionEnvironment.js +30 -0
- package/dist/runtime/firstProgressAdvisory.js +11 -11
- package/dist/runtime/index.js +4 -3
- package/dist/runtime/jsonLineChannel.js +109 -0
- package/dist/runtime/launchBroker.js +91 -16
- package/dist/runtime/launchDiagnostics.js +2 -2
- package/dist/runtime/lifecycleReservation.js +10 -18
- package/dist/runtime/managedCaller.js +61 -17
- package/dist/runtime/nativeSessionControl.js +102 -0
- package/dist/runtime/ports.js +6 -21
- package/dist/runtime/processExitObservation.js +8 -7
- package/dist/runtime/promptEnvelope.js +17 -6
- package/dist/runtime/providerContinuation.js +3 -9
- package/dist/runtime/providerContinuationReconciliationService.js +4 -13
- package/dist/runtime/providerControl.js +2 -7
- package/dist/runtime/providerRuntimeIdentity.js +110 -222
- package/dist/runtime/providerRuntimeReconciler.js +5 -9
- package/dist/runtime/runtimeBinding.js +0 -1
- package/dist/runtime/runtimeContinuationProjection.js +4 -7
- package/dist/runtime/runtimeDeadlines.js +9 -0
- package/dist/runtime/runtimeHealthPolicy.js +1 -1
- package/dist/runtime/runtimeObservation.js +29 -65
- package/dist/runtime/runtimeProjection.js +43 -51
- package/dist/runtime/runtimeSessionCandidate.js +1 -3
- package/dist/runtime/sessionLaunchRequest.js +3 -7
- package/dist/runtime/sessionOwnerIdentity.js +7 -54
- package/dist/runtime/sessionOwnerRegistry.js +22 -17
- package/dist/runtime/sessionReconciliation.js +4 -8
- package/dist/runtime/sessionTerminationGuard.js +70 -259
- package/dist/runtime/sessionTokenMetrics.js +5 -16
- package/dist/runtime/structuredProviderHost.js +237 -117
- package/dist/runtime/taskRuntimeIsolation.js +39 -122
- package/dist/runtime/tmuxAdapters.js +39 -86
- package/dist/scheduler/activeRoleRunDelivery.js +354 -0
- package/dist/scheduler/leaderWakeupProcessor.js +75 -266
- package/dist/scheduler/operatorInputNotificationProcessor.js +1 -1
- package/dist/scheduler/ports.js +80 -9
- package/dist/scheduler/{roleTurnLiveness.js → roleRunLiveness.js} +26 -30
- package/dist/scheduler/{roleTurnStall.js → roleRunStall.js} +128 -139
- package/dist/scheduler/taskExecutionProjection.js +120 -124
- package/dist/scheduler/taskObservabilityProjection.js +29 -29
- package/dist/scheduler/taskWake.js +11 -4
- package/dist/scheduler/wakeReason.js +9 -1
- package/dist/setup/setupCommand.js +1 -0
- package/dist/storage/migrations/agentRunContract.js +159 -0
- package/dist/storage/migrations/removeRuntimeGeneration.js +207 -0
- package/dist/storage/sqliteSchema.js +431 -5
- package/dist/storage/sqliteStore.js +375 -220
- package/dist/storage/storageVersions.js +1 -1
- package/dist/storage/storeRpc.js +10 -5
- package/dist/storage/taskStore.js +13 -11
- package/dist/storage/upgrade/upgradeOrchestrator.js +5 -7
- package/dist/surface/surfaceContributions.js +102 -0
- package/dist/task/completionReadiness.js +32 -6
- package/dist/task/deliveryGuard.js +16 -16
- package/dist/task/draftPlan.js +72 -12
- package/dist/task/nextAction.js +144 -128
- package/dist/task/remoteDelivery.js +6 -6
- package/dist/task/task.js +184 -18
- package/dist/task/taskActivation.js +301 -0
- package/dist/task/taskActivationService.js +392 -0
- package/dist/task/taskRecordReference.js +5 -4
- package/dist/task/taskRecordRetirement.js +1 -1
- package/dist/telemetry/sqliteTelemetryStore.js +55 -68
- package/dist/telemetry/telemetryConfig.js +14 -14
- package/dist/telemetry/telemetryWiring.js +2 -2
- package/dist/web/assets/assetManifest.js +2 -0
- package/dist/web/assets/client/app.js +120 -20
- package/dist/web/assets/client/components.js +87 -54
- package/dist/web/assets/client/i18n.js +83 -41
- package/dist/web/assets/client/markdown.js +1 -1
- package/dist/web/assets/client/taskSurface.js +353 -0
- package/dist/web/assets/client/view.js +49 -44
- package/dist/web/assets/shell.js +1 -1
- package/dist/web/assets/styles/cards.js +22 -4
- package/dist/web/controllerWeb.js +60 -0
- package/dist/web/webMutation.js +28 -0
- package/dist/web/webServer.js +118 -8
- package/dist/web/webSnapshot.js +81 -74
- package/dist/web/webTaskSurface.js +64 -0
- package/dist/workItem/dependencyGate.js +1 -1
- package/dist/workItem/workItem.js +80 -48
- package/dist/workspace/workItemChangeSetManager.js +16 -9
- package/docs/agent-result-consumption.md +94 -0
- package/docs/agent-runtime-drivers.md +91 -0
- package/docs/architecture/README.md +38 -0
- package/docs/architecture/capabilities-and-resources.md +79 -0
- package/docs/managed-turn-and-session-runtime.md +222 -0
- package/docs/observability/README.md +81 -0
- package/docs/plugin-sdk.md +290 -0
- package/docs/provider-runtime.md +163 -0
- package/docs/release-workflow.md +303 -0
- package/docs/roles-and-configuration.md +113 -0
- package/docs/sqlite-control-plane-design.md +76 -0
- package/docs/task-dag-semantics.md +57 -0
- package/docs/task-delivery.md +103 -0
- package/docs/task-local-identity.md +6 -6
- package/docs/testing/verification-levels.md +86 -0
- package/i18n/README.zh-CN.md +98 -739
- package/package.json +5 -5
- package/skills/yui-leader/SKILL.md +130 -103
- package/skills/yui-leader/references/integration.md +39 -0
- package/skills/yui-leader/references/replicated-execution.md +42 -0
- package/skills/yui-leader/references/task-plugins.md +33 -0
- package/skills/yui-operator/SKILL.md +30 -59
- package/skills/yui-reviewer/SKILL.md +35 -36
- package/skills/yui-runtime/SKILL.md +88 -24
- package/skills/yui-runtime/references/publication.md +22 -0
- package/skills/yui-runtime/references/recovery.md +64 -0
- package/skills/yui-worker/SKILL.md +37 -39
- package/dist/cli/roleOptionCatalog.js +0 -68
- package/dist/context/sourceTurnContext.js +0 -30
- package/dist/execution/reviewMainTurn.js +0 -161
- package/dist/execution/workItemMainTurn.js +0 -164
- package/dist/lifecycle/exactTurnTerminalization.js +0 -407
- package/dist/runtime/preallocatedNativeSession.js +0 -13
- package/dist/runtime/runtimeStopReceipt.js +0 -42
- package/dist/scheduler/activeRoleTurnDelivery.js +0 -315
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
export const TASK_SURFACE_SCRIPT = `
|
|
2
|
+
import { node, clear } from "/assets/js/dom.js";
|
|
3
|
+
import { anchorSection, sectionHead, richText, inputCard, roleCard, runCard, pill } from "/assets/js/components.js";
|
|
4
|
+
|
|
5
|
+
// All business facts below retain their Context reference. Expanded values
|
|
6
|
+
// are current reads, not mutations of a historical Context snapshot.
|
|
7
|
+
export function renderTaskSurface(container, data, t, locale, actions) {
|
|
8
|
+
clear(container);
|
|
9
|
+
const core = data.core;
|
|
10
|
+
const task = data.task;
|
|
11
|
+
container.dataset.taskId = task.id;
|
|
12
|
+
const zh = locale.startsWith("zh");
|
|
13
|
+
const say = (en, cn) => zh ? cn : en;
|
|
14
|
+
const records = (store) => core.records.filter((entry) => entry.ref.store === store);
|
|
15
|
+
const values = (store) => records(store).filter((entry) => !entry.omitted).map((entry) => entry.value);
|
|
16
|
+
const scaffold = node("div", "detail-scaffold task-surface");
|
|
17
|
+
const summary = node("div", "section-body");
|
|
18
|
+
summary.append(node("span", "detail-kicker", task.id), node("h2", "detail-title", task.title), pill(t, "status", task.status));
|
|
19
|
+
const conversation = node("button", "record-open", say("View Leader Session (read-only)", "查看 Leader Session(只读)"));
|
|
20
|
+
conversation.type = "button";
|
|
21
|
+
// A Draft's planning Session is a real Leader Session, so it is viewable once it
|
|
22
|
+
// actually exists. The button is disabled only when there is no Session to show
|
|
23
|
+
// — not because the Task has yet to be activated. The Session lives in the
|
|
24
|
+
// runtime observation, which arrives separately from the Context snapshot.
|
|
25
|
+
const leaderRole = (data.runtime?.roles ?? []).find((role) => role.name === "leader") ?? null;
|
|
26
|
+
const hasLeaderSession = Boolean(leaderRole?.runtimeSession?.nativeSessionId);
|
|
27
|
+
conversation.disabled = task.status === "archived" || !hasLeaderSession;
|
|
28
|
+
conversation.addEventListener("click", () => actions.openTerminal({ scope: "task", taskId: task.id, roleName: "leader" }));
|
|
29
|
+
summary.append(conversation);
|
|
30
|
+
const chat = node("form", "record-card");
|
|
31
|
+
const chatLabel = node("label", "", say("Message to Task Leader", "发送给 Task Leader"));
|
|
32
|
+
const message = node("textarea", "");
|
|
33
|
+
message.required = true;
|
|
34
|
+
message.maxLength = 8000;
|
|
35
|
+
chatLabel.append(message);
|
|
36
|
+
chat.addEventListener("input", () => { chat.dataset.unsent = message.value ? "true" : "false"; });
|
|
37
|
+
const send = node("button", "record-open", say("Send", "发送"));
|
|
38
|
+
send.type = "submit";
|
|
39
|
+
send.disabled = !["active", "draft"].includes(task.status);
|
|
40
|
+
const sent = node("p", "muted", say("Not submitted", "未提交"));
|
|
41
|
+
sent.setAttribute("role", "status");
|
|
42
|
+
chat.append(chatLabel, send, sent);
|
|
43
|
+
chat.addEventListener("submit", async (event) => {
|
|
44
|
+
event.preventDefault();
|
|
45
|
+
if (send.disabled) return;
|
|
46
|
+
send.disabled = true;
|
|
47
|
+
chat.dataset.unsent = "true";
|
|
48
|
+
const requestId = crypto.randomUUID();
|
|
49
|
+
sent.textContent = say("Waiting for receipt · ", "等待回执 · ") + requestId;
|
|
50
|
+
try {
|
|
51
|
+
const receipt = await actions.sendMessage(task.id, message.value, requestId);
|
|
52
|
+
sent.textContent = (receipt.disposition === "queued"
|
|
53
|
+
? say("Queued for Leader; not proof of execution · ", "已为 Leader 排队,不代表已执行 · ")
|
|
54
|
+
: say("Saved to Task context; this Task's Leader is not waking · ",
|
|
55
|
+
"已保存到 Task 上下文;该 Task 的 Leader 不会被唤醒 · "))
|
|
56
|
+
+ receipt.record.id;
|
|
57
|
+
message.value = "";
|
|
58
|
+
chat.dataset.unsent = "false";
|
|
59
|
+
send.disabled = false;
|
|
60
|
+
} catch (error) {
|
|
61
|
+
if (error.disposition === "not-submitted") {
|
|
62
|
+
sent.textContent = say("Not submitted: ", "未提交:") + error.message;
|
|
63
|
+
send.disabled = false;
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
sent.textContent = say("Unknown submission outcome. Reload and inspect saved messages before sending again · ",
|
|
67
|
+
"提交结果未知。请重新加载并检查已保存消息,不要盲目重发 · ") + requestId;
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
summary.append(chat);
|
|
71
|
+
// A Draft's Leader conversation IS its planning Turn, so this entry point does
|
|
72
|
+
// reach a Leader. Report the real planning facts the snapshot carries — Turn,
|
|
73
|
+
// Session, environment and the time they were observed — instead of asserting
|
|
74
|
+
// that no runtime exists. When nothing has been dispatched yet, say exactly
|
|
75
|
+
// that rather than implying the entry point is inert.
|
|
76
|
+
if (task.status === "draft") {
|
|
77
|
+
// Planning facts come from the Context snapshot, which is the authoritative
|
|
78
|
+
// durable read and the one that drives re-rendering. The runtime observation
|
|
79
|
+
// is explicitly optional (it may time out and only ever enriches a live
|
|
80
|
+
// Session), so it must not decide whether a planning Turn is reported.
|
|
81
|
+
const turnEntries = records("turn");
|
|
82
|
+
const planningTurns = values("turn").filter((turn) =>
|
|
83
|
+
turn.roleName === "leader" && turn.purpose === "planning");
|
|
84
|
+
// The latest planning Turn, whatever state it reached. A completed planning
|
|
85
|
+
// Turn is still the real observed fact; reporting only active ones would call
|
|
86
|
+
// a Draft that has genuinely talked to its Leader "not dispatched".
|
|
87
|
+
const planningTurn = planningTurns[planningTurns.length - 1] ?? null;
|
|
88
|
+
// A bounded snapshot may withhold Turn values. That is not evidence that no
|
|
89
|
+
// Turn exists, so it is reported as withheld rather than as "not dispatched".
|
|
90
|
+
const withheldTurns = planningTurn === null && turnEntries.some((entry) => entry.omitted);
|
|
91
|
+
const environment = planningTurn?.effective?.executionEnvironment ?? null;
|
|
92
|
+
const liveLeader = (data.runtime?.roles ?? []).find((role) => role.name === "leader") ?? null;
|
|
93
|
+
const planning = node("div", "record-card");
|
|
94
|
+
planning.dataset.planning = planningTurn !== null
|
|
95
|
+
? planningTurn.status
|
|
96
|
+
: withheldTurns ? "withheld" : "not-dispatched";
|
|
97
|
+
planning.append(node("p", "muted", withheldTurns
|
|
98
|
+
? say("This bounded snapshot withholds Turn detail; read the Turn directly to see planning state.",
|
|
99
|
+
"当前受限快照未展开 Turn 详情;请直接读取 Turn 查看规划状态。")
|
|
100
|
+
: planningTurn === null
|
|
101
|
+
? say("No planning Turn has been dispatched yet. Sending a message queues the Leader.",
|
|
102
|
+
"尚未派发 planning Turn;发送消息会为 Leader 排队。")
|
|
103
|
+
: planningTurn.status === "active"
|
|
104
|
+
? say("Planning Turn is active; messages reach the Task Leader.",
|
|
105
|
+
"planning Turn 正在进行;消息会送达 Task Leader。")
|
|
106
|
+
: say("Planning Turn reached " + planningTurn.status
|
|
107
|
+
+ "; messages reach the same Task Leader and queue the next Turn.",
|
|
108
|
+
"planning Turn 已" + planningTurn.status + ";消息仍送达同一 Task Leader 并为下一个 Turn 排队。")));
|
|
109
|
+
const facts = [
|
|
110
|
+
[say("Planning Turn", "planning Turn"), planningTurn
|
|
111
|
+
? planningTurn.id + " (" + planningTurn.status + ")"
|
|
112
|
+
: withheldTurns ? say("withheld by this snapshot", "本快照未展开") : say("none", "无")],
|
|
113
|
+
[say("Provider terminal", "Provider 终态"),
|
|
114
|
+
planningTurn?.result?.provider?.status ?? say("not reported", "未上报")],
|
|
115
|
+
// The Provider conversation is the durable transport identity of the
|
|
116
|
+
// Session this Turn actually ran on; the live Session, when observed,
|
|
117
|
+
// is reported separately so a stale read is never dressed up as current.
|
|
118
|
+
[say("Provider conversation", "Provider 会话"),
|
|
119
|
+
planningTurn?.result?.provider?.conversationId ?? say("not reported", "未上报")],
|
|
120
|
+
[say("Live Leader Session", "在线 Leader Session"),
|
|
121
|
+
liveLeader?.runtimeSession?.nativeSessionId
|
|
122
|
+
?? say("not currently running", "当前未在运行")],
|
|
123
|
+
[say("Environment", "环境"), environment?.environmentRef
|
|
124
|
+
?? say("empty (legal for planning)", "空环境(规划阶段合法)")],
|
|
125
|
+
[say("Turn observed at", "Turn 观测时间"),
|
|
126
|
+
planningTurn?.result?.completedAt ?? planningTurn?.updatedAt ?? say("unknown", "未知")]
|
|
127
|
+
];
|
|
128
|
+
for (const [label, value] of facts) {
|
|
129
|
+
planning.append(node("p", "muted", label + ": " + value));
|
|
130
|
+
}
|
|
131
|
+
summary.append(planning);
|
|
132
|
+
}
|
|
133
|
+
if (task.description) summary.append(richText(say("Current requirements", "当前要求"), task.description, t));
|
|
134
|
+
if (task.completionSummary) summary.append(richText(t("detail.conclusion"), task.completionSummary, t));
|
|
135
|
+
const edit = node("details", "record-card");
|
|
136
|
+
edit.append(node("summary", "", say("Edit Task title", "修改任务标题")));
|
|
137
|
+
const form = node("form", "record-block");
|
|
138
|
+
const label = node("label", "", say("Title", "标题"));
|
|
139
|
+
const title = node("input", "");
|
|
140
|
+
title.value = task.title;
|
|
141
|
+
title.required = true;
|
|
142
|
+
title.disabled = task.status === "archived";
|
|
143
|
+
title.maxLength = 500;
|
|
144
|
+
label.append(title);
|
|
145
|
+
form.addEventListener("input", () => { form.dataset.unsent = "true"; });
|
|
146
|
+
const save = node("button", "record-open", say("Save", "保存"));
|
|
147
|
+
save.type = "submit";
|
|
148
|
+
save.disabled = task.status === "archived";
|
|
149
|
+
const feedback = node("p", "muted", say("Not submitted", "未提交"));
|
|
150
|
+
feedback.setAttribute("role", "status");
|
|
151
|
+
form.append(label, save, feedback);
|
|
152
|
+
form.addEventListener("submit", async (event) => {
|
|
153
|
+
event.preventDefault();
|
|
154
|
+
if (save.disabled) return;
|
|
155
|
+
save.disabled = true;
|
|
156
|
+
form.dataset.unsent = "true";
|
|
157
|
+
const requestId = crypto.randomUUID();
|
|
158
|
+
feedback.textContent = say("Waiting for save receipt · ", "正在等待保存回执 · ") + requestId;
|
|
159
|
+
try {
|
|
160
|
+
const receipt = await actions.updateTask(task.id, { title: title.value }, requestId);
|
|
161
|
+
feedback.textContent = say("Saved · revision ", "已保存 · revision ") + receipt.revision;
|
|
162
|
+
title.value = receipt.record.title;
|
|
163
|
+
form.dataset.unsent = "false";
|
|
164
|
+
save.disabled = false;
|
|
165
|
+
} catch (error) {
|
|
166
|
+
if (error.disposition === "not-submitted") {
|
|
167
|
+
feedback.textContent = say("Not saved: ", "未保存:") + error.message;
|
|
168
|
+
save.disabled = false;
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
// Local mutation IDs correlate requests; they are not a deduplication
|
|
172
|
+
// ledger. A lost response must never automatically replay a write.
|
|
173
|
+
feedback.textContent = say("Unknown save outcome. Reload this page to read current facts before submitting again. Request: ",
|
|
174
|
+
"保存结果未知。请重新加载页面读取当前事实,再决定是否提交。请求:") + requestId;
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
edit.append(form);
|
|
178
|
+
summary.append(edit);
|
|
179
|
+
scaffold.append(anchorSection("detail-top", sectionHead(t("tabs.summary")), summary));
|
|
180
|
+
|
|
181
|
+
function recordCard(entry) {
|
|
182
|
+
const card = node("article", "record-card");
|
|
183
|
+
card.append(node("strong", "", entry.ref.store + " · " + entry.ref.refId));
|
|
184
|
+
const ref = node("small", "muted", say("Revision: ", "版本:") + entry.ref.revision);
|
|
185
|
+
card.append(ref);
|
|
186
|
+
if (!entry.omitted) {
|
|
187
|
+
const value = entry.value;
|
|
188
|
+
const text = value.content || value.summary || value.body || value.objective || value.title || value.leaderSummary;
|
|
189
|
+
if (text) card.append(richText(null, text, t));
|
|
190
|
+
if (value.status) card.append(node("p", "muted", value.status));
|
|
191
|
+
if (value.roleName) card.append(node("p", "muted", value.roleName));
|
|
192
|
+
if (entry.ref.store === "work-item") {
|
|
193
|
+
card.append(node("p", "muted", say("Owner: ", "负责人:") + (value.assignee || "Leader")));
|
|
194
|
+
if (value.acceptance) card.append(richText(say("Acceptance criteria", "验收标准"), value.acceptance.join("\\n"), t));
|
|
195
|
+
}
|
|
196
|
+
if (entry.ref.store === "job") {
|
|
197
|
+
const status = value.status;
|
|
198
|
+
const label = status === "queued" ? say("Queued", "已排队")
|
|
199
|
+
: status === "running" ? say("Waiting for a terminal receipt", "等待明确终态")
|
|
200
|
+
: status === "unknown-needs-attention" ? say("Unknown effect — inspect the original operation; do not resend", "效果未知——检查原操作,不要重发")
|
|
201
|
+
: say("Terminal record", "已记录终态");
|
|
202
|
+
card.append(node("p", "", label + " · " + task.id + "/" + value.id));
|
|
203
|
+
}
|
|
204
|
+
} else card.append(node("p", "muted", entry.summary || say("Value omitted from compact read", "紧凑读取已省略正文")));
|
|
205
|
+
const expand = node("button", "record-open", say("Read full record / source", "读取完整记录/来源"));
|
|
206
|
+
expand.type = "button";
|
|
207
|
+
expand.addEventListener("click", async () => {
|
|
208
|
+
expand.disabled = true;
|
|
209
|
+
try {
|
|
210
|
+
const result = await actions.inspect(task.id, entry.ref);
|
|
211
|
+
const content = node("pre", "surface-json", JSON.stringify(result.value, null, 2));
|
|
212
|
+
card.append(content);
|
|
213
|
+
if (result.result?.output) card.append(richText(say("Original execution report", "原始执行报告"), result.result.output, t));
|
|
214
|
+
if (result.result?.diagnostic) card.append(richText(say("Execution diagnostic", "执行诊断"), result.result.diagnostic, t));
|
|
215
|
+
if (result.execution) card.append(node("pre", "surface-json", JSON.stringify(result.execution, null, 2)));
|
|
216
|
+
expand.remove();
|
|
217
|
+
} catch {
|
|
218
|
+
expand.disabled = false;
|
|
219
|
+
expand.textContent = say("Record changed or unavailable; refresh context", "记录已变化或不可用;请刷新 Context");
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
card.append(expand);
|
|
223
|
+
return card;
|
|
224
|
+
}
|
|
225
|
+
function section(id, name, entries) {
|
|
226
|
+
const body = node("div", "section-body");
|
|
227
|
+
entries.forEach((entry) => body.append(recordCard(entry)));
|
|
228
|
+
if (!entries.length) body.append(node("p", "muted", core.omitted.records
|
|
229
|
+
? say("Not included in this compact read", "此紧凑读取未包含该记录")
|
|
230
|
+
: say("No records", "暂无记录")));
|
|
231
|
+
scaffold.append(anchorSection(id, sectionHead(name, { count: entries.length }), body));
|
|
232
|
+
return body;
|
|
233
|
+
}
|
|
234
|
+
const focus = section("detail-focus", say("Goal and current focus", "目标与当前关注"), records("task-brief"));
|
|
235
|
+
const brief = values("task-brief")[0];
|
|
236
|
+
if (brief) {
|
|
237
|
+
focus.prepend(richText(t("detail.focus"), brief.currentFocus, t));
|
|
238
|
+
if (brief.boundaries.length) focus.append(richText(say("Boundaries", "边界"), brief.boundaries.join("\\n"), t));
|
|
239
|
+
}
|
|
240
|
+
const questions = node("div", "section-body");
|
|
241
|
+
records("input-request").filter((entry) => entry.omitted || entry.value.status === "open").forEach((entry) => {
|
|
242
|
+
questions.append(entry.omitted ? recordCard(entry) : inputCard(entry.value, { single: true }, t, locale, actions));
|
|
243
|
+
});
|
|
244
|
+
scaffold.append(anchorSection("detail-attention", sectionHead(t("detail.attention")), questions));
|
|
245
|
+
section("detail-work", say("Responsibilities and acceptance", "工作责任与验收"), records("work-item"));
|
|
246
|
+
section("detail-results", say("Saved results and provenance", "已保存结果与来源"), records("artifact").concat(records("candidate")));
|
|
247
|
+
section("detail-messages", t("detail.messages"), records("task-message"));
|
|
248
|
+
section("detail-history", say("Decisions and milestones", "决策与里程碑"), records("task-decision").concat(records("task-milestone")));
|
|
249
|
+
section("detail-reviews", t("detail.reviews"), records("review-round"));
|
|
250
|
+
const roles = node("div", "section-body");
|
|
251
|
+
records("role").forEach((entry) => {
|
|
252
|
+
if (entry.omitted) { roles.append(recordCard(entry)); return; }
|
|
253
|
+
const role = entry.value;
|
|
254
|
+
const active = values("run").find((run) => run.roleName === role.name && run.status === "active");
|
|
255
|
+
const incomplete = core.omitted.records > 0 || records("run").some((entry) => entry.omitted);
|
|
256
|
+
roles.append(roleCard({
|
|
257
|
+
...role, status: active || incomplete ? "unknown" : "idle",
|
|
258
|
+
effectiveLaunch: active ? active.effective : null,
|
|
259
|
+
launchDrift: active && active.effective.sourceDesiredRevision !== role.launchRevision
|
|
260
|
+
}, task, t, locale, actions));
|
|
261
|
+
if (!active) roles.append(node("p", "muted", say(
|
|
262
|
+
"No active AgentRun in this read; Session activity is a separate observation.",
|
|
263
|
+
"此读取中没有活跃 AgentRun;Session 活动属于独立观察。")));
|
|
264
|
+
});
|
|
265
|
+
scaffold.append(anchorSection("detail-roles", sectionHead(t("detail.roles")), roles));
|
|
266
|
+
const execution = node("details", "record-card");
|
|
267
|
+
execution.append(node("summary", "", say("Execution and observations", "展开执行与观察")));
|
|
268
|
+
execution.append(node("p", "muted", say(
|
|
269
|
+
"An open execution record is not proof of Agent activity. Native admission and Task progress are separate facts.",
|
|
270
|
+
"执行记录未结清不等于 Agent 正在工作;原生准入、运行观察与 Task 进展分别呈现。")));
|
|
271
|
+
records("run").forEach((entry) => execution.append(entry.omitted ? recordCard(entry)
|
|
272
|
+
: runCard({ ...entry.value, execution: entry.execution }, t, locale)));
|
|
273
|
+
(core.observations || []).forEach((observation) => execution.append(node("p", "muted",
|
|
274
|
+
observation.source + " · " + observation.status + " · " + observation.coverage + " · " + observation.observedAt)));
|
|
275
|
+
const runtimeStatus = node("p", "muted", data.runtimeStatus + " · " + data.runtimeObservedAt);
|
|
276
|
+
runtimeStatus.dataset.runtimeStatus = "";
|
|
277
|
+
execution.append(runtimeStatus);
|
|
278
|
+
const raw = node("pre", "surface-json", data.runtime ? JSON.stringify({
|
|
279
|
+
roles: data.runtime.roles, runtimeHealth: data.runtime.runtimeHealth
|
|
280
|
+
}, null, 2) : "");
|
|
281
|
+
raw.dataset.runtimeValue = "";
|
|
282
|
+
execution.append(raw);
|
|
283
|
+
scaffold.append(anchorSection("detail-exec", sectionHead(t("detail.execution")), execution));
|
|
284
|
+
section("detail-operations", say("Original operation facts (no automatic retry)", "原始操作事实(不自动重试)"), records("job"));
|
|
285
|
+
const refs = node("details", "record-card");
|
|
286
|
+
refs.append(node("summary", "", say("Context cursor and omitted references", "Context 游标与省略引用")));
|
|
287
|
+
refs.append(node("pre", "surface-json", JSON.stringify({
|
|
288
|
+
coreCursor: core.coreCursor, throughCursor: core.throughCursor, count: core.count, omitted: core.omitted
|
|
289
|
+
}, null, 2)));
|
|
290
|
+
refs.append(node("p", "muted", say("Reads do not acknowledge messages. Omitted records can be located with the CLI domain query and inspected by reference.",
|
|
291
|
+
"读取不确认消息。被省略的记录可经 CLI 领域查询定位后按引用读取。")));
|
|
292
|
+
scaffold.append(refs);
|
|
293
|
+
const panels = node("details", "record-card");
|
|
294
|
+
panels.append(node("summary", "", say("Capability panels", "能力面板")));
|
|
295
|
+
const panelBody = node("div", "section-body");
|
|
296
|
+
panels.append(panelBody);
|
|
297
|
+
let loadingPanels = false;
|
|
298
|
+
panels.addEventListener("toggle", async () => {
|
|
299
|
+
if (!panels.open || loadingPanels) return;
|
|
300
|
+
loadingPanels = true;
|
|
301
|
+
panelBody.textContent = say("Reading current contributions…", "读取当前贡献…");
|
|
302
|
+
try {
|
|
303
|
+
const current = await actions.panels(task.id);
|
|
304
|
+
clear(panelBody);
|
|
305
|
+
panelBody.append(node("small", "muted", current.observedAt));
|
|
306
|
+
if (!current.panels.length) panelBody.append(node("p", "muted", say("No visible panels", "暂无可见面板")));
|
|
307
|
+
current.panels.forEach((item) => {
|
|
308
|
+
const card = node("article", "record-card");
|
|
309
|
+
const panel = item.panel;
|
|
310
|
+
card.append(node("strong", "", panel.title), node("small", "muted", item.capability + " · " + item.provider.id));
|
|
311
|
+
if (item.unavailable) card.append(node("p", "muted", item.unavailable));
|
|
312
|
+
else if (panel.kind === "text") card.append(node("p", "", panel.text));
|
|
313
|
+
else if (panel.kind === "link") {
|
|
314
|
+
const url = new URL(panel.href);
|
|
315
|
+
if (["http:", "https:"].includes(url.protocol) && !url.username && !url.password) {
|
|
316
|
+
const link = node("a", "", panel.title);
|
|
317
|
+
link.href = url.href;
|
|
318
|
+
link.rel = "noopener noreferrer";
|
|
319
|
+
card.append(link);
|
|
320
|
+
}
|
|
321
|
+
} else if (panel.kind === "data" && panel.renderer === "json") {
|
|
322
|
+
const label = node("label", "", say("Query input (JSON)", "查询输入(JSON)"));
|
|
323
|
+
const input = node("textarea", "");
|
|
324
|
+
input.value = JSON.stringify({ taskId: task.id });
|
|
325
|
+
label.append(input);
|
|
326
|
+
const contract = node("details", "");
|
|
327
|
+
contract.append(node("summary", "", say("Input schema", "输入结构")));
|
|
328
|
+
contract.append(node("pre", "surface-json", JSON.stringify(item.inputSchema, null, 2)));
|
|
329
|
+
const read = node("button", "record-open", say("Read", "读取"));
|
|
330
|
+
read.type = "button";
|
|
331
|
+
const output = node("pre", "surface-json");
|
|
332
|
+
read.addEventListener("click", async () => {
|
|
333
|
+
if (read.disabled) return;
|
|
334
|
+
read.disabled = true;
|
|
335
|
+
try {
|
|
336
|
+
const result = await actions.readPanel(task.id, {
|
|
337
|
+
capability: item.capability, contractVersion: item.contractVersion, provider: item.provider
|
|
338
|
+
}, JSON.parse(input.value));
|
|
339
|
+
output.textContent = JSON.stringify(result, null, 2);
|
|
340
|
+
} catch (error) { output.textContent = say("Panel unavailable: ", "面板不可用:") + error.message; }
|
|
341
|
+
finally { read.disabled = false; }
|
|
342
|
+
});
|
|
343
|
+
card.append(label, contract, read, output);
|
|
344
|
+
}
|
|
345
|
+
panelBody.append(card);
|
|
346
|
+
});
|
|
347
|
+
} catch (error) { panelBody.textContent = say("Panels unavailable: ", "面板不可用:") + error.message; }
|
|
348
|
+
finally { loadingPanels = false; }
|
|
349
|
+
});
|
|
350
|
+
scaffold.append(panels);
|
|
351
|
+
container.append(scaffold);
|
|
352
|
+
}
|
|
353
|
+
`;
|
|
@@ -2,6 +2,7 @@ export const VIEW_SCRIPT = `
|
|
|
2
2
|
// Page composition: sidebar lists, overview, and the task detail scaffold.
|
|
3
3
|
// All reusable widgets and cards come from components.js.
|
|
4
4
|
import { clear, node } from "/assets/js/dom.js";
|
|
5
|
+
import { renderTaskSurface } from "/assets/js/task-surface.js";
|
|
5
6
|
import { byNewest, formatDateTime } from "/assets/js/format.js";
|
|
6
7
|
import {
|
|
7
8
|
anchorSection,
|
|
@@ -23,14 +24,14 @@ import {
|
|
|
23
24
|
reviewCard,
|
|
24
25
|
richText,
|
|
25
26
|
roleCard,
|
|
26
|
-
|
|
27
|
+
runCard,
|
|
27
28
|
sectionHead,
|
|
28
29
|
taskCard,
|
|
29
30
|
translatedStatus,
|
|
30
31
|
workItemCard
|
|
31
32
|
} from "/assets/js/components.js";
|
|
32
33
|
|
|
33
|
-
const statuses = ["all", "active", "draft", "completed", "
|
|
34
|
+
const statuses = ["all", "active", "draft", "completed", "cancelled", "archived"];
|
|
34
35
|
|
|
35
36
|
export function renderFilters(container, state, t, onFilter) {
|
|
36
37
|
const counts = state.counts || {};
|
|
@@ -83,7 +84,7 @@ function taskGroupOf(task, attentionIds) {
|
|
|
83
84
|
if (attentionIds.has(task.id)) return "attention";
|
|
84
85
|
if (task.status === "active") return "active";
|
|
85
86
|
if (task.status === "draft") return "draft";
|
|
86
|
-
if (task.status === "
|
|
87
|
+
if (task.status === "cancelled") return "cancelled";
|
|
87
88
|
if (task.status === "archived") return "archived";
|
|
88
89
|
return "finished";
|
|
89
90
|
}
|
|
@@ -102,7 +103,7 @@ export function renderTasks(container, state, t, locale, onSelect) {
|
|
|
102
103
|
clear(container);
|
|
103
104
|
const query = state.query.trim().toLocaleLowerCase(locale);
|
|
104
105
|
const attentionIds = new Set((state.attention || []).map(function (item) { return item.taskId; }));
|
|
105
|
-
const groups = { attention: [], active: [], draft: [], finished: [],
|
|
106
|
+
const groups = { attention: [], active: [], draft: [], finished: [], cancelled: [], archived: [] };
|
|
106
107
|
(state.tasks || []).forEach(function (task) {
|
|
107
108
|
if (state.filter !== "all" && task.status !== state.filter) return;
|
|
108
109
|
if (!taskMatchesQuery(task, query, locale)) return;
|
|
@@ -114,7 +115,7 @@ export function renderTasks(container, state, t, locale, onSelect) {
|
|
|
114
115
|
["active", t("group.active")],
|
|
115
116
|
["draft", t("group.draft")],
|
|
116
117
|
["finished", t("group.finished")],
|
|
117
|
-
["
|
|
118
|
+
["cancelled", t("group.cancelled")],
|
|
118
119
|
["archived", t("group.archived")]
|
|
119
120
|
];
|
|
120
121
|
const firstGroup = order.find(function (entry) { return groups[entry[0]].length > 0; });
|
|
@@ -182,7 +183,7 @@ export function renderOverview(detail, state, t, locale, onSelect) {
|
|
|
182
183
|
wrap.append(inbox);
|
|
183
184
|
|
|
184
185
|
// Tasks whose Task-first projection says they need attention: blocked,
|
|
185
|
-
// recovering, or in an attention state. This replaces the raw stalled-
|
|
186
|
+
// recovering, or in an attention state. This replaces the raw stalled-AgentRun
|
|
186
187
|
// count with the derived execution status.
|
|
187
188
|
const attentionTasks = (state.tasks || []).filter(function (task) {
|
|
188
189
|
const status = task.executionStatus;
|
|
@@ -232,23 +233,23 @@ export function renderError(container, message) {
|
|
|
232
233
|
container.append(node("div", "error", message));
|
|
233
234
|
}
|
|
234
235
|
|
|
235
|
-
const
|
|
236
|
+
const RUN_PAGE_SIZE = 12;
|
|
236
237
|
const LIST_PAGE_SIZE = 10;
|
|
237
|
-
const
|
|
238
|
+
const RUN_FILTERS = ["all", "active", "completed", "failed"];
|
|
238
239
|
|
|
239
|
-
function
|
|
240
|
-
const row = node("div", "filter-row
|
|
240
|
+
function runFilterRow(sortedRuns, t, onChange) {
|
|
241
|
+
const row = node("div", "filter-row run-filter");
|
|
241
242
|
const buttons = [];
|
|
242
|
-
|
|
243
|
+
RUN_FILTERS.forEach(function (status) {
|
|
243
244
|
const count = status === "all"
|
|
244
|
-
?
|
|
245
|
-
:
|
|
245
|
+
? sortedRuns.length
|
|
246
|
+
: sortedRuns.filter(function (run) { return run.status === status; }).length;
|
|
246
247
|
if (status !== "all" && count === 0) return;
|
|
247
248
|
const btn = node("button", "filter-chip");
|
|
248
249
|
btn.type = "button";
|
|
249
250
|
btn.dataset.status = status;
|
|
250
251
|
if (status !== "all") btn.append(node("span", "filter-dot " + status));
|
|
251
|
-
btn.append(document.createTextNode(status === "all" ? t("status.all") : t("
|
|
252
|
+
btn.append(document.createTextNode(status === "all" ? t("status.all") : t("run." + status)));
|
|
252
253
|
btn.append(node("span", "filter-count", String(count)));
|
|
253
254
|
btn.addEventListener("click", function () { onChange(status); });
|
|
254
255
|
buttons.push({ status: status, element: btn });
|
|
@@ -265,6 +266,7 @@ function turnFilterRow(sortedTurns, t, onChange) {
|
|
|
265
266
|
}
|
|
266
267
|
|
|
267
268
|
export function renderTaskDetail(detail, data, t, locale, actions) {
|
|
269
|
+
if (data.core) return renderTaskSurface(detail, data, t, locale, actions);
|
|
268
270
|
actions = actions || {};
|
|
269
271
|
clear(detail);
|
|
270
272
|
const task = data.task;
|
|
@@ -346,14 +348,14 @@ export function renderTaskDetail(detail, data, t, locale, actions) {
|
|
|
346
348
|
conclusion.append(richText(null, task.completionSummary, t));
|
|
347
349
|
conclusion.append(conclusionMeta(task, t, locale, "completed"));
|
|
348
350
|
summaryBody.append(conclusion);
|
|
349
|
-
} else if (task.status === "
|
|
351
|
+
} else if (task.status === "cancelled" || task.retirementSummary) {
|
|
350
352
|
const conclusion = node("div", "conclusion archived");
|
|
351
|
-
conclusion.append(node("h3", "", t("detail.
|
|
353
|
+
conclusion.append(node("h3", "", t("detail.cancelled")));
|
|
352
354
|
if (task.retirementSummary) conclusion.append(richText(null, task.retirementSummary, t));
|
|
353
355
|
if (task.replacementTaskId) {
|
|
354
356
|
conclusion.append(node("p", "muted", t("detail.replacement") + " · " + task.replacementTaskId));
|
|
355
357
|
}
|
|
356
|
-
conclusion.append(conclusionMeta(task, t, locale, "
|
|
358
|
+
conclusion.append(conclusionMeta(task, t, locale, "cancelled"));
|
|
357
359
|
summaryBody.append(conclusion);
|
|
358
360
|
} else if (task.status === "archived" || task.archiveSummary || task.archiveReason) {
|
|
359
361
|
const conclusion = node("div", "conclusion archived");
|
|
@@ -377,23 +379,23 @@ export function renderTaskDetail(detail, data, t, locale, actions) {
|
|
|
377
379
|
attentionBody));
|
|
378
380
|
}
|
|
379
381
|
|
|
380
|
-
const
|
|
381
|
-
? data.runtimeHealth.
|
|
382
|
+
const stalledRuns = data.runtimeHealth && data.runtimeHealth.needsAttentionRuns
|
|
383
|
+
? data.runtimeHealth.needsAttentionRuns
|
|
382
384
|
: [];
|
|
383
|
-
if (
|
|
385
|
+
if (stalledRuns.length) {
|
|
384
386
|
const runtimeHealthBody = node("div", "section-body");
|
|
385
|
-
|
|
387
|
+
stalledRuns.forEach(function (run) {
|
|
386
388
|
const card = node("article", "record-card");
|
|
387
389
|
card.append(
|
|
388
|
-
node("strong", "",
|
|
389
|
-
node("p", "record-copy", (
|
|
390
|
-
node("small", "", t("detail.lastProgress") + " · " + formatDateTime(
|
|
390
|
+
node("strong", "", run.roleName + " · " + run.runId),
|
|
391
|
+
node("p", "record-copy", (run.kind || "workflow-not-progressing") + " · " + (run.classification || "truly-stalled")),
|
|
392
|
+
node("small", "", t("detail.lastProgress") + " · " + formatDateTime(run.progressAt, locale))
|
|
391
393
|
);
|
|
392
394
|
runtimeHealthBody.append(card);
|
|
393
395
|
});
|
|
394
396
|
scaffold.append(anchorSection(
|
|
395
397
|
"detail-health",
|
|
396
|
-
sectionHead(t("detail.runtimeHealth"), { count:
|
|
398
|
+
sectionHead(t("detail.runtimeHealth"), { count: stalledRuns.length }),
|
|
397
399
|
runtimeHealthBody
|
|
398
400
|
));
|
|
399
401
|
}
|
|
@@ -438,35 +440,35 @@ export function renderTaskDetail(detail, data, t, locale, actions) {
|
|
|
438
440
|
sectionHead(t("detail.workItems"), { count: data.workItems.length }),
|
|
439
441
|
workBody));
|
|
440
442
|
|
|
441
|
-
// 5.
|
|
443
|
+
// 5. AgentRuns (anchor #detail-exec) — execution grid with status filter + paging
|
|
442
444
|
const execWrap = node("div", "section-body");
|
|
443
|
-
const execBody = node("div", "
|
|
444
|
-
const
|
|
445
|
-
if (!
|
|
446
|
-
execBody.append(emptyRow(t, "empty.
|
|
445
|
+
const execBody = node("div", "run-grid");
|
|
446
|
+
const sortedRuns = data.runs.slice().sort(byNewest);
|
|
447
|
+
if (!sortedRuns.length) {
|
|
448
|
+
execBody.append(emptyRow(t, "empty.runs"));
|
|
447
449
|
execWrap.append(execBody);
|
|
448
450
|
} else {
|
|
449
|
-
let
|
|
450
|
-
const filter =
|
|
451
|
-
|
|
451
|
+
let activeRunFilter = "all";
|
|
452
|
+
const filter = runFilterRow(sortedRuns, t, function (status) {
|
|
453
|
+
activeRunFilter = status;
|
|
452
454
|
filter.sync(status);
|
|
453
|
-
|
|
455
|
+
renderRunGrid();
|
|
454
456
|
});
|
|
455
|
-
function
|
|
457
|
+
function renderRunGrid() {
|
|
456
458
|
clear(execBody);
|
|
457
|
-
const visible =
|
|
458
|
-
?
|
|
459
|
-
:
|
|
460
|
-
pagedList(execBody, visible,
|
|
461
|
-
return
|
|
459
|
+
const visible = activeRunFilter === "all"
|
|
460
|
+
? sortedRuns
|
|
461
|
+
: sortedRuns.filter(function (run) { return run.status === activeRunFilter; });
|
|
462
|
+
pagedList(execBody, visible, RUN_PAGE_SIZE, function (run) {
|
|
463
|
+
return runCard(run, t, locale);
|
|
462
464
|
}, t);
|
|
463
465
|
}
|
|
464
|
-
filter.sync(
|
|
466
|
+
filter.sync(activeRunFilter);
|
|
465
467
|
execWrap.append(filter.row, execBody);
|
|
466
|
-
|
|
468
|
+
renderRunGrid();
|
|
467
469
|
}
|
|
468
470
|
scaffold.append(anchorSection("detail-exec",
|
|
469
|
-
sectionHead(t("detail.execution"), { count: data.
|
|
471
|
+
sectionHead(t("detail.execution"), { count: data.runs.length }),
|
|
470
472
|
execWrap));
|
|
471
473
|
|
|
472
474
|
// 5b. Reviews (anchor #detail-reviews) — review rounds for completed candidates
|
|
@@ -522,7 +524,10 @@ export function renderTaskDetail(detail, data, t, locale, actions) {
|
|
|
522
524
|
messagesBody.append(emptyRow(t));
|
|
523
525
|
} else {
|
|
524
526
|
pagedList(messagesBody, data.messages.slice().sort(byNewest), LIST_PAGE_SIZE, function (message) {
|
|
525
|
-
|
|
527
|
+
const source = message.resultRef && data.runs.find(function (run) {
|
|
528
|
+
return run.id === message.resultRef.runId && run.roleName === message.author.roleName;
|
|
529
|
+
});
|
|
530
|
+
return messageCard(message, t, locale, source && source.result);
|
|
526
531
|
}, t);
|
|
527
532
|
}
|
|
528
533
|
scaffold.append(anchorSection("detail-messages",
|
package/dist/web/assets/shell.js
CHANGED
|
@@ -83,7 +83,7 @@ export const DASHBOARD_HTML = `<!doctype html>
|
|
|
83
83
|
<button class="tab" type="button" data-target="detail-top" data-i18n="tabs.summary">Summary</button>
|
|
84
84
|
<button class="tab" type="button" data-target="detail-focus" data-i18n="tabs.focus">Focus</button>
|
|
85
85
|
<button class="tab" type="button" data-target="detail-work" data-i18n="tabs.work">Work items</button>
|
|
86
|
-
<button class="tab" type="button" data-target="detail-exec" data-i18n="tabs.exec">
|
|
86
|
+
<button class="tab" type="button" data-target="detail-exec" data-i18n="tabs.exec">AgentRuns</button>
|
|
87
87
|
<button class="tab" type="button" data-target="detail-reviews" data-i18n="tabs.reviews">Reviews</button>
|
|
88
88
|
<button class="tab" type="button" data-target="detail-roles" data-i18n="tabs.roles">Roles</button>
|
|
89
89
|
<button class="tab" type="button" data-target="detail-history" data-i18n="tabs.history">History</button>
|
|
@@ -1,10 +1,28 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* CARDS — content-bearing surfaces.
|
|
3
3
|
* Overview blocks, detail head / conclusion band, sections, record cards,
|
|
4
|
-
* input cards,
|
|
4
|
+
* input cards, AgentRun cards, criteria lists. Widgets (pills, chips, metrics)
|
|
5
5
|
* live in widgets.ts; markdown typography lives in markdown.ts.
|
|
6
6
|
*/
|
|
7
7
|
export const CARD_STYLES = `
|
|
8
|
+
.surface-json { white-space: pre-wrap; overflow-wrap: anywhere; max-height: 36rem; overflow: auto; }
|
|
9
|
+
.task-surface .section-body { display:grid; gap:12px; min-width:0; }
|
|
10
|
+
.task-surface { grid-template-columns:minmax(0,1fr); }
|
|
11
|
+
.task-surface .detail-section,.task-surface .record-card,.task-surface .execute-card { min-width:0; max-width:100%; }
|
|
12
|
+
.task-surface .record-meta { min-width:0; overflow-wrap:anywhere; }
|
|
13
|
+
@media(max-width:620px){
|
|
14
|
+
.task-surface .record-head{flex-wrap:wrap}
|
|
15
|
+
.task-surface .record-title-row{flex-basis:100%}
|
|
16
|
+
}
|
|
17
|
+
.task-surface .section-body > .pill { width:max-content; }
|
|
18
|
+
.task-surface form,.task-surface label { display:grid; gap:10px; min-width:0; }
|
|
19
|
+
.task-surface label { font-size:13px; font-weight:500; }
|
|
20
|
+
.task-surface input,.task-surface textarea { box-sizing:border-box; width:100%; min-width:0; padding:12px; border:1px solid var(--border-strong); border-radius:var(--radius); background:var(--bg-1); color:var(--text); font:inherit; }
|
|
21
|
+
.task-surface textarea { min-height:96px; resize:vertical; }
|
|
22
|
+
.task-surface input:focus-visible,.task-surface textarea:focus-visible,.task-surface summary:focus-visible { outline:2px solid var(--accent); outline-offset:3px; }
|
|
23
|
+
.task-surface button { min-height:40px; }
|
|
24
|
+
.task-surface summary { cursor:pointer; padding:8px 0; font-weight:600; }
|
|
25
|
+
.task-surface [role=status] { overflow-wrap:anywhere; }
|
|
8
26
|
/* Overview scaffolding */
|
|
9
27
|
.overview{display:grid;gap:14px;padding-top:2px}
|
|
10
28
|
.overview-duo{display:grid;grid-template-columns:1fr 1fr;gap:14px;align-items:start}
|
|
@@ -109,9 +127,9 @@ details.work-item-card>summary.record-head~*{margin-top:0}
|
|
|
109
127
|
.input-answer:hover{border-color:var(--accent-line);color:var(--accent);background:var(--accent-soft)}
|
|
110
128
|
.input-form{display:flex;gap:8px;flex:1}
|
|
111
129
|
.input-form input{min-width:0;flex:1;padding:8px 12px;color:var(--text);background:var(--bg-2);border:1px solid var(--border);border-radius:var(--radius);font-family:var(--font-body);font-size:12.5px}
|
|
112
|
-
/* Execution
|
|
113
|
-
.
|
|
114
|
-
.
|
|
130
|
+
/* Execution AgentRuns */
|
|
131
|
+
.run-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(320px,100%),1fr));gap:9px}
|
|
132
|
+
.run-filter{margin-bottom:3px}
|
|
115
133
|
.execute-card{background:var(--bg-2);border:1px solid var(--border);border-left:2px solid var(--border);border-radius:var(--radius);padding:9px 12px;display:grid;gap:6px;box-shadow:var(--shadow-card);transition:border-color var(--motion-fast)}
|
|
116
134
|
.execute-card:hover{border-left-color:var(--border-strong)}
|
|
117
135
|
.execute-card[data-status=active]{border-left-color:var(--accent)}
|