@zq-silk/yui 0.10.1 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +53 -0
  2. package/dist/cli/commandCatalog.js +28 -7
  3. package/dist/cli.js +50 -47
  4. package/dist/commands/projectCommands.js +69 -6
  5. package/dist/commands/taskCommands.js +639 -89
  6. package/dist/commands/taskContextCommand.js +78 -27
  7. package/dist/commands/taskNextActionCommand.js +13 -2
  8. package/dist/commands/taskOverviewCommand.js +21 -5
  9. package/dist/commands/taskUpstreamCommands.js +136 -0
  10. package/dist/context/runContextPack.js +184 -17
  11. package/dist/controller/agentRuntimeObserver.js +31 -20
  12. package/dist/controller/fileSchedulerStoreAdapter.js +7 -13
  13. package/dist/execution/candidateConvergence.js +623 -0
  14. package/dist/execution/executionGroup.js +255 -13
  15. package/dist/execution/executionHealth.js +324 -0
  16. package/dist/execution/resourceBroker.js +425 -0
  17. package/dist/executor/fileRoleLaunchPlanner.js +6 -9
  18. package/dist/executor/workspacePreflightClassification.js +117 -0
  19. package/dist/lifecycle/exactRunTerminalization.js +13 -2
  20. package/dist/lifecycle/taskRoleSessionReset.js +4 -2
  21. package/dist/repository/taskBaseFreshness.js +26 -1
  22. package/dist/repository/taskWorkspacePreparer.js +17 -1
  23. package/dist/review/reviewRound.js +27 -6
  24. package/dist/run/agentRun.js +2 -2
  25. package/dist/run/recoveryProjection.js +15 -0
  26. package/dist/runtime/runtimeContinuationProjection.js +7 -0
  27. package/dist/scheduler/actionability.js +169 -3
  28. package/dist/scheduler/activeTaskProgress.js +15 -10
  29. package/dist/scheduler/leaderWakeupProcessor.js +17 -1
  30. package/dist/scheduler/taskExecutionProjection.js +105 -8
  31. package/dist/scheduler/taskObservabilityProjection.js +282 -0
  32. package/dist/storage/migration/productionRegistry.js +14 -0
  33. package/dist/storage/sqliteStore.js +12 -0
  34. package/dist/storage/taskStore.js +1 -1
  35. package/dist/task/completionReadiness.js +1 -1
  36. package/dist/task/nextAction.js +314 -2
  37. package/dist/web/assets/client/components.js +116 -0
  38. package/dist/web/assets/client/i18n.js +66 -0
  39. package/dist/web/assets/client/view.js +15 -0
  40. package/dist/web/assets/styles/cards.js +23 -0
  41. package/dist/web/assets/styles/responsive.js +2 -0
  42. package/dist/web/webSnapshot.js +8 -2
  43. package/dist/workItem/workItem.js +262 -5
  44. package/i18n/README.zh-CN.md +42 -0
  45. package/package.json +1 -1
@@ -0,0 +1,324 @@
1
+ import { isRoleRunStalled, latestStallProgressAt } from "../scheduler/roleRunStall.js";
2
+ import { validateRuntimeProcessExitObservation } from "../runtime/processExitObservation.js";
3
+ import { runtimeObservationFromTaskEvent } from "../runtime/runtimeObservation.js";
4
+ import { projectRuntimeTaskEvents } from "../runtime/runtimeProjection.js";
5
+ import { DEFAULT_RUNTIME_HEALTH_POLICY } from "../runtime/runtimeHealthPolicy.js";
6
+ import { runOwnsBlockingProviderContinuation } from "../runtime/runtimeContinuationProjection.js";
7
+ import { summarizeExecutionGroup } from "./executionGroup.js";
8
+ import { executionStageSpendClosed, observedExecutionResourceUsage, projectExecutionStageResources } from "./resourceBroker.js";
9
+ /**
10
+ * Fold existing Run, runtime, Session, process-exit, and stall facts into the
11
+ * four Lane health states. This is a read model only: it never advances a
12
+ * Lane, terminalizes a Run, or guesses that silence means death.
13
+ */
14
+ export function projectExecutionGroupHealth(input) {
15
+ const policy = input.policy ?? DEFAULT_RUNTIME_HEALTH_POLICY;
16
+ const lanes = input.group.lanes.map((lane) => projectExecutionLaneHealth(lane, input, policy));
17
+ return Object.freeze({
18
+ groupId: input.group.id,
19
+ lanes,
20
+ activeLaneCount: countHealth(lanes, "active"),
21
+ silentLaneCount: countHealth(lanes, "silent"),
22
+ suspectedStalledLaneCount: countHealth(lanes, "suspected-stalled"),
23
+ confirmedDeadLaneCount: countHealth(lanes, "confirmed-dead"),
24
+ reusableLaneIds: lanes.filter(({ resultReusable }) => resultReusable)
25
+ .map(({ laneId }) => laneId),
26
+ retryableLaneIds: lanes.filter(({ recovery }) => recovery === "retry-new-agent-run")
27
+ .map(({ laneId }) => laneId)
28
+ });
29
+ }
30
+ /** Structural Group summary plus the health/recovery projection used by CLI/Web reads. */
31
+ export function summarizeExecutionGroupHealth(input) {
32
+ const summary = summarizeExecutionGroup(input.group);
33
+ const projection = projectExecutionGroupHealth(input);
34
+ const resources = input.group.stage === undefined
35
+ ? undefined
36
+ : projectExecutionStageResources({
37
+ group: input.group,
38
+ ...(input.stageGroups === undefined ? {} : { stageGroups: input.stageGroups }),
39
+ usage: observedExecutionResourceUsage({
40
+ group: input.group,
41
+ ...(input.stageGroups === undefined ? {} : { stageGroups: input.stageGroups }),
42
+ runs: input.runs,
43
+ events: input.events
44
+ }),
45
+ now: input.now
46
+ });
47
+ const healthByLane = new Map(projection.lanes.map((lane) => [lane.laneId, lane]));
48
+ return Object.freeze({
49
+ ...summary,
50
+ laneSummaries: summary.laneSummaries.map((lane) => Object.freeze({
51
+ ...lane,
52
+ ...healthByLane.get(lane.laneId)
53
+ })),
54
+ health: Object.freeze({
55
+ activeLaneCount: projection.activeLaneCount,
56
+ silentLaneCount: projection.silentLaneCount,
57
+ suspectedStalledLaneCount: projection.suspectedStalledLaneCount,
58
+ confirmedDeadLaneCount: projection.confirmedDeadLaneCount,
59
+ reusableLaneIds: projection.reusableLaneIds,
60
+ retryableLaneIds: projection.retryableLaneIds
61
+ }),
62
+ ...(resources === undefined ? {} : { resources })
63
+ });
64
+ }
65
+ /** Unresolved Lane recovery in deterministic operational priority order. */
66
+ export function actionableExecutionLaneRecoveries(groups) {
67
+ const priority = {
68
+ "terminate-exact-run": 0,
69
+ "retry-new-agent-run": 1,
70
+ diagnose: 2
71
+ };
72
+ return groups
73
+ .filter(({ resolution }) => resolution === undefined)
74
+ .flatMap((group) => group.laneSummaries.flatMap((lane) => {
75
+ if (lane.recovery === "retry-new-agent-run"
76
+ && group.resources !== undefined
77
+ && executionStageSpendClosed(group.resources))
78
+ return [];
79
+ if (lane.recovery !== "diagnose"
80
+ && lane.recovery !== "terminate-exact-run"
81
+ && lane.recovery !== "retry-new-agent-run")
82
+ return [];
83
+ return [{
84
+ groupId: group.groupId,
85
+ laneId: lane.laneId,
86
+ ...(lane.runId === undefined ? {} : { runId: lane.runId }),
87
+ ...(lane.runtimeHealth === undefined ? {} : { runtimeHealth: lane.runtimeHealth }),
88
+ recovery: lane.recovery
89
+ }];
90
+ }))
91
+ .sort((left, right) => priority[left.recovery] - priority[right.recovery]);
92
+ }
93
+ function projectExecutionLaneHealth(lane, input, policy) {
94
+ const run = lane.runId === undefined
95
+ ? undefined
96
+ : input.runs.find((candidate) => exactLaneRun(candidate, input.group, lane));
97
+ const continuationAgentId = run?.effective.agentId ?? lane.effective?.agentId;
98
+ if (lane.status !== "completed"
99
+ && lane.status !== "yielded"
100
+ && lane.runId !== undefined
101
+ && continuationAgentId !== undefined
102
+ && runOwnsBlockingProviderContinuation(input.events, {
103
+ taskId: input.group.taskId,
104
+ roleName: lane.roleName,
105
+ runId: lane.runId,
106
+ agentId: continuationAgentId
107
+ })) {
108
+ return projection(lane, {
109
+ runtimeHealth: "active",
110
+ recovery: "none",
111
+ resultReusable: false,
112
+ reason: "the exact Run still owns an unsettled Provider continuation writer",
113
+ evidence: ["runtime-continuation-writer-owned"]
114
+ });
115
+ }
116
+ if (lane.status === "completed" || lane.status === "yielded") {
117
+ return projection(lane, {
118
+ recovery: "reuse-result",
119
+ resultReusable: true,
120
+ reason: "the terminal Lane result is durable and must be reused",
121
+ evidence: ["execution-lane-result"]
122
+ });
123
+ }
124
+ if (lane.status === "failed") {
125
+ return projection(lane, {
126
+ runtimeHealth: "confirmed-dead",
127
+ recovery: "retry-new-agent-run",
128
+ resultReusable: false,
129
+ reason: "the exact Lane attempt is durably failed; a retry must create a new AgentRun",
130
+ evidence: ["execution-lane-terminal-failure"]
131
+ });
132
+ }
133
+ if (lane.status === "skipped") {
134
+ return projection(lane, {
135
+ recovery: "none",
136
+ resultReusable: false,
137
+ reason: "the Lane was never started after sufficient stage evidence made further spend unnecessary",
138
+ evidence: ["execution-lane-resource-skip"]
139
+ });
140
+ }
141
+ if (lane.status === "pending") {
142
+ return projection(lane, {
143
+ recovery: "none",
144
+ resultReusable: false,
145
+ reason: "the Lane has not started",
146
+ evidence: []
147
+ });
148
+ }
149
+ if (run === undefined) {
150
+ return projection(lane, {
151
+ runtimeHealth: "suspected-stalled",
152
+ recovery: "diagnose",
153
+ resultReusable: false,
154
+ reason: "the running Lane has no exact AgentRun record",
155
+ evidence: ["execution-lineage-missing"]
156
+ });
157
+ }
158
+ if (run.status === "failed") {
159
+ return projection(lane, {
160
+ runtimeHealth: "confirmed-dead",
161
+ recovery: "retry-new-agent-run",
162
+ resultReusable: false,
163
+ reason: "the exact AgentRun is durably failed",
164
+ evidence: ["agent-run-terminal-failure"]
165
+ });
166
+ }
167
+ if (run.status !== "active") {
168
+ return projection(lane, {
169
+ runtimeHealth: "suspected-stalled",
170
+ recovery: "diagnose",
171
+ resultReusable: false,
172
+ reason: "the Lane is running but its exact AgentRun is terminal without a Lane result",
173
+ evidence: ["execution-lineage-inconsistent"]
174
+ });
175
+ }
176
+ const session = input.sessions.find((candidate) => (candidate.roleName === run.roleName
177
+ && candidate.agentId === run.effective.agentId
178
+ && candidate.adapterId === run.effective.adapterId));
179
+ const observations = exactRunObservations(input.events, run, session);
180
+ const runtime = runtimeProjection(observations, input.events, run);
181
+ const unsettledContinuation = runtime !== null
182
+ && Object.values(runtime.continuations).some((continuation) => (continuation.execution === "active"
183
+ || continuation.execution === "unknown"
184
+ || continuation.identityConflict));
185
+ const unsettledChildWork = runtime !== null
186
+ && (Object.values(runtime.operations).some(({ kind }) => kind === "subagent")
187
+ || unsettledContinuation);
188
+ if (observations.some((observation) => (observation.kind === "turn.failed"
189
+ && observation.payload.failure?.runTerminal === true)) && !unsettledChildWork) {
190
+ return projection(lane, {
191
+ runtimeHealth: "confirmed-dead",
192
+ recovery: "terminate-exact-run",
193
+ resultReusable: false,
194
+ reason: "the Provider reported an exact run-terminal failure",
195
+ evidence: ["provider-run-terminal"]
196
+ });
197
+ }
198
+ const runtimeTerminalEvidence = runtime === null
199
+ ? []
200
+ : [
201
+ ...(runtime.host === "exited" ? ["runtime-host-exited"] : []),
202
+ ...(runtime.session === "ended" || runtime.session === "failed"
203
+ ? [`runtime-session-${runtime.session}`]
204
+ : [])
205
+ ];
206
+ if (runtimeTerminalEvidence.length > 0 && !unsettledChildWork) {
207
+ return projection(lane, {
208
+ runtimeHealth: "confirmed-dead",
209
+ recovery: "terminate-exact-run",
210
+ resultReusable: false,
211
+ reason: "the exact runtime host or Session is terminal and no unsettled child work remains",
212
+ evidence: runtimeTerminalEvidence
213
+ });
214
+ }
215
+ const exit = latestExactProcessExit(input.events, run, session);
216
+ const sessionDead = session?.status === "stopped" || session?.status === "broken";
217
+ if (sessionDead
218
+ && exit !== null
219
+ && isAbnormalExit(exit.classification)
220
+ && !unsettledChildWork) {
221
+ return projection(lane, {
222
+ runtimeHealth: "confirmed-dead",
223
+ recovery: "terminate-exact-run",
224
+ resultReusable: false,
225
+ reason: "the exact Session and abnormal process exit independently confirm death",
226
+ evidence: ["native-session-terminal", `process-exit:${exit.classification}`]
227
+ });
228
+ }
229
+ if (isRoleRunStalled(input.events, run.id)) {
230
+ return projection(lane, {
231
+ runtimeHealth: "suspected-stalled",
232
+ recovery: "diagnose",
233
+ resultReusable: false,
234
+ reason: `the durable progress clock has not advanced since ${latestStallProgressAt(input.events, run.id) ?? run.updatedAt}; no death proof exists`,
235
+ evidence: ["run-stalled"]
236
+ });
237
+ }
238
+ const activeOperation = runtime !== null
239
+ && (Object.keys(runtime.operations).length > 0 || unsettledContinuation);
240
+ const lastActivityAt = runtime?.lastRuntimeActivityAt
241
+ ?? run.deliveredAt
242
+ ?? run.pushedAt
243
+ ?? run.createdAt;
244
+ const recentActivity = input.now.getTime() - Date.parse(lastActivityAt) < policy.quietAfterMs;
245
+ if (activeOperation || recentActivity) {
246
+ return projection(lane, {
247
+ runtimeHealth: "active",
248
+ recovery: "none",
249
+ resultReusable: false,
250
+ reason: unsettledContinuation
251
+ ? "the exact runtime reports unsettled continuation work"
252
+ : activeOperation
253
+ ? "the exact runtime reports an active operation"
254
+ : "the exact Run has recent structured runtime activity",
255
+ evidence: unsettledContinuation
256
+ ? ["runtime-continuation-unsettled"]
257
+ : activeOperation ? ["runtime-operation-active"] : ["runtime-activity-recent"]
258
+ });
259
+ }
260
+ return projection(lane, {
261
+ runtimeHealth: "silent",
262
+ recovery: "none",
263
+ resultReusable: false,
264
+ reason: "the exact Run remains active without recent structured activity; silence alone is not death",
265
+ evidence: ["agent-run-active"]
266
+ });
267
+ }
268
+ function projection(lane, value) {
269
+ return Object.freeze({ laneId: lane.id, ...value });
270
+ }
271
+ function exactLaneRun(run, group, lane) {
272
+ return run.id === lane.runId
273
+ && run.taskId === group.taskId
274
+ && run.roleName === lane.roleName
275
+ && run.executionGroupId === group.id
276
+ && run.executionLaneId === lane.id;
277
+ }
278
+ function exactRunObservations(events, run, session) {
279
+ return events.map(runtimeObservationFromTaskEvent)
280
+ .filter((observation) => (observation !== null
281
+ && observation.fence.taskId === run.taskId
282
+ && observation.fence.runId === run.id
283
+ && observation.fence.roleName === run.roleName
284
+ && observation.fence.agentId === run.effective.agentId
285
+ && (session?.launchId === undefined || observation.fence.launchId === session.launchId)
286
+ && (session?.nativeSessionId === undefined
287
+ || observation.fence.nativeSessionId === session.nativeSessionId)));
288
+ }
289
+ function runtimeProjection(observations, events, run) {
290
+ const first = observations[0];
291
+ return first === undefined
292
+ ? null
293
+ : projectRuntimeTaskEvents(first.fence, run.createdAt, events);
294
+ }
295
+ function latestExactProcessExit(events, run, session) {
296
+ const matching = events.flatMap((event) => {
297
+ if (event.type !== "runtime.process-exit-observed")
298
+ return [];
299
+ try {
300
+ const observation = validateRuntimeProcessExitObservation(JSON.parse(event.payload.observation ?? ""));
301
+ if (observation.taskId !== run.taskId
302
+ || observation.runId !== run.id
303
+ || observation.roleName !== run.roleName
304
+ || (session?.launchId !== undefined && observation.launchId !== session.launchId)
305
+ || (session?.nativeSessionId !== undefined
306
+ && observation.nativeSessionId !== session.nativeSessionId))
307
+ return [];
308
+ return [{
309
+ observation,
310
+ classification: event.payload.classification ?? "unknown"
311
+ }];
312
+ }
313
+ catch {
314
+ return [];
315
+ }
316
+ });
317
+ return matching.sort((left, right) => (Date.parse(right.observation.observedAt) - Date.parse(left.observation.observedAt)))[0] ?? null;
318
+ }
319
+ function isAbnormalExit(classification) {
320
+ return classification === "host-abnormal" || classification === "provider-turn-failed";
321
+ }
322
+ function countHealth(lanes, health) {
323
+ return lanes.filter(({ runtimeHealth }) => runtimeHealth === health).length;
324
+ }