@zq-silk/yui 0.14.1 → 0.15.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 (185) hide show
  1. package/ARCHITECTURE.md +91 -47
  2. package/README.md +275 -145
  3. package/dist/agent/managedRuntimeEnvironment.js +5 -8
  4. package/dist/cli/commandCatalog.js +74 -109
  5. package/dist/cli/helpRenderer.js +1 -2
  6. package/dist/cli/interactionCandidates.js +10 -0
  7. package/dist/cli/interactionPolicy.js +76 -37
  8. package/dist/cli/roleWizard.js +5 -6
  9. package/dist/cli/updateCommand.js +17 -9
  10. package/dist/cli/updateOrchestrator.js +87 -19
  11. package/dist/cli/updatePorts.js +79 -13
  12. package/dist/cli/upgradeCommand.js +105 -23
  13. package/dist/cli.js +268 -231
  14. package/dist/commands/agentCommands.js +13 -0
  15. package/dist/commands/configCommands.js +7 -19
  16. package/dist/commands/configOverview.js +3 -2
  17. package/dist/commands/controllerCommands.js +1 -1
  18. package/dist/commands/durableJobCommands.js +1 -1
  19. package/dist/commands/executionAuditCommands.js +4 -9
  20. package/dist/commands/globalRoleCommands.js +17 -0
  21. package/dist/commands/profileCommands.js +200 -30
  22. package/dist/commands/sessionCommands.js +1 -1
  23. package/dist/commands/taskActor.js +29 -127
  24. package/dist/commands/taskChangeSetCommands.js +1 -3
  25. package/dist/commands/taskCommands.js +1771 -2107
  26. package/dist/commands/taskCompletionGate.js +27 -103
  27. package/dist/commands/taskContextCommand.js +47 -80
  28. package/dist/commands/taskExecutionCommands.js +9 -27
  29. package/dist/commands/taskInputCommands.js +10 -10
  30. package/dist/commands/taskIntegrationCommands.js +69 -61
  31. package/dist/commands/taskIntegrationQueueCommands.js +1 -1
  32. package/dist/commands/taskNextActionCommand.js +8 -29
  33. package/dist/commands/taskOverviewCommand.js +25 -3
  34. package/dist/commands/taskPublicationCommands.js +151 -85
  35. package/dist/commands/taskPublicationVerifyCommand.js +181 -0
  36. package/dist/commands/taskRemoteDeliveryCommand.js +134 -0
  37. package/dist/commands/taskRoleRuntimeStatus.js +5 -6
  38. package/dist/commands/taskUpstreamCommands.js +79 -95
  39. package/dist/config/configCatalog.js +1 -1
  40. package/dist/context/contextSnapshot.js +17 -2
  41. package/dist/context/sourceTurnContext.js +30 -0
  42. package/dist/context/turnContextPack.js +107 -48
  43. package/dist/context/turnInputContract.js +11 -4
  44. package/dist/context/wakeNotification.js +84 -22
  45. package/dist/controller/agentRuntimeObserver.js +9 -12
  46. package/dist/controller/clientRuntime.js +13 -13
  47. package/dist/controller/controller.js +11 -11
  48. package/dist/controller/fileSchedulerStoreAdapter.js +262 -219
  49. package/dist/controller/jobControl.js +11 -10
  50. package/dist/controller/resourceInventory.js +6 -6
  51. package/dist/controller/resourceInventoryLinux.js +2 -2
  52. package/dist/controller/runtime.js +18 -61
  53. package/dist/controller/runtimeEventInbox.js +57 -34
  54. package/dist/controller/runtimeEventProcessor.js +36 -96
  55. package/dist/controller/runtimeHookTurnFence.js +33 -57
  56. package/dist/controller/runtimeLaunchCoordinator.js +44 -40
  57. package/dist/controller/runtimeObservationHook.js +18 -12
  58. package/dist/controller/sessionNotify.js +43 -28
  59. package/dist/controller/sessionOwnerReconciliation.js +21 -21
  60. package/dist/controller/structuredProviderObservation.js +13 -16
  61. package/dist/coordination/workMailboxQueue.js +132 -0
  62. package/dist/core/controllerServer.js +6 -5
  63. package/dist/doctor/doctor.js +37 -14
  64. package/dist/domain/agentResultTransport.js +60 -0
  65. package/dist/execution/executionHealth.js +111 -118
  66. package/dist/execution/reviewMainTurn.js +161 -0
  67. package/dist/execution/workItemExecution.js +454 -0
  68. package/dist/execution/workItemExecutionProjection.js +309 -0
  69. package/dist/execution/workItemMainTurn.js +164 -0
  70. package/dist/executor/agentExecutor.js +19 -19
  71. package/dist/executor/executorRegistry.js +7 -28
  72. package/dist/executor/fileRoleLaunchPlanner.js +16 -82
  73. package/dist/external/githubPublicationVerifier.js +114 -0
  74. package/dist/external/gitlabPublicationVerifier.js +158 -0
  75. package/dist/external/pinnedCommandRunner.js +73 -0
  76. package/dist/integration/changeSetManifest.js +0 -3
  77. package/dist/integration/deliveryObligation.js +43 -6
  78. package/dist/integration/gitIntegrationService.js +284 -101
  79. package/dist/integration/integrationAttempt.js +64 -14
  80. package/dist/integration/integrationQueueEntry.js +5 -35
  81. package/dist/integration/integrationQueueService.js +65 -194
  82. package/dist/lifecycle/canonicalLifecycleEvent.js +16 -15
  83. package/dist/lifecycle/exactTurnTerminalization.js +100 -97
  84. package/dist/message/message.js +16 -0
  85. package/dist/observability/executionAudit.js +4 -25
  86. package/dist/observability/faultClassification.js +58 -70
  87. package/dist/observability/orchestrationMetrics.js +8 -50
  88. package/dist/observability/runtimeIdentity.js +48 -50
  89. package/dist/profile/agentProfile.js +60 -15
  90. package/dist/profile/agentProfileRuntime.js +100 -0
  91. package/dist/release/releaseWorkflowPorts.js +5 -68
  92. package/dist/release/runtimeRelease.js +9 -1
  93. package/dist/repository/executionLaneGitSnapshot.js +80 -0
  94. package/dist/repository/gitWorkspace.js +9 -67
  95. package/dist/repository/taskBaseFreshness.js +3 -1
  96. package/dist/repository/taskWorkspaceCoordinator.js +32 -4
  97. package/dist/repository/taskWorkspacePreparer.js +252 -411
  98. package/dist/resources/liveReferences.js +6 -55
  99. package/dist/resources/resourceDiscovery.js +1 -30
  100. package/dist/resources/resourceRegistrar.js +0 -23
  101. package/dist/review/deltaRecheck.js +8 -65
  102. package/dist/review/reviewAcceptance.js +22 -19
  103. package/dist/review/reviewConfig.js +0 -10
  104. package/dist/review/reviewDecision.js +2 -2
  105. package/dist/review/reviewRound.js +147 -273
  106. package/dist/review/reviewerAvailability.js +13 -23
  107. package/dist/role/role.js +3 -0
  108. package/dist/runtime/agentDriverObservation.js +1 -1
  109. package/dist/runtime/agentHost.js +51 -51
  110. package/dist/runtime/builtinAgentDrivers.js +9 -2
  111. package/dist/runtime/codexAppServerRuntime.js +23 -5
  112. package/dist/runtime/exactControlPlane.js +22 -296
  113. package/dist/runtime/firstProgressAdvisory.js +1 -1
  114. package/dist/runtime/index.js +1 -1
  115. package/dist/runtime/launchBroker.js +11 -11
  116. package/dist/runtime/lifecycleReservation.js +2 -2
  117. package/dist/runtime/managedCaller.js +111 -0
  118. package/dist/runtime/ports.js +16 -3
  119. package/dist/runtime/preallocatedNativeSession.js +2 -2
  120. package/dist/runtime/processExitObservation.js +3 -2
  121. package/dist/runtime/providerContinuationReconciliationService.js +1 -1
  122. package/dist/runtime/runtimeBinding.js +1 -1
  123. package/dist/runtime/runtimeObservation.js +33 -16
  124. package/dist/runtime/runtimeSessionCandidate.js +2 -2
  125. package/dist/runtime/runtimeStopReceipt.js +11 -11
  126. package/dist/runtime/sessionLaunchRequest.js +2 -2
  127. package/dist/runtime/sessionOwnerIdentity.js +9 -9
  128. package/dist/runtime/sessionOwnerRegistry.js +13 -13
  129. package/dist/runtime/sessionReconciliation.js +4 -4
  130. package/dist/runtime/sessionTerminationGuard.js +9 -9
  131. package/dist/runtime/sessionTokenMetrics.js +5 -7
  132. package/dist/runtime/structuredProviderHost.js +5 -5
  133. package/dist/runtime/taskRuntimeIsolation.js +24 -24
  134. package/dist/runtime/tmuxAdapters.js +32 -30
  135. package/dist/scheduler/activeRoleTurnDelivery.js +37 -15
  136. package/dist/scheduler/leaderWakeupProcessor.js +78 -55
  137. package/dist/scheduler/roleTurnLiveness.js +6 -6
  138. package/dist/scheduler/roleTurnStall.js +8 -9
  139. package/dist/scheduler/taskExecutionProjection.js +19 -41
  140. package/dist/scheduler/taskObservabilityProjection.js +75 -122
  141. package/dist/storage/currentTaskStore.js +6 -4
  142. package/dist/storage/sqliteSchema.js +135 -80
  143. package/dist/storage/sqliteStore.js +69 -52
  144. package/dist/storage/storageSchema.js +92 -230
  145. package/dist/storage/storageVersions.js +12 -13
  146. package/dist/storage/taskStore.js +8 -8
  147. package/dist/storage/upgrade/upgradeOrchestrator.js +276 -85
  148. package/dist/task/completionReadiness.js +17 -98
  149. package/dist/task/deliveryGuard.js +9 -11
  150. package/dist/task/draftPlan.js +142 -0
  151. package/dist/task/nextAction.js +179 -477
  152. package/dist/task/publicationVerification.js +1 -0
  153. package/dist/task/remoteDelivery.js +233 -0
  154. package/dist/task/task.js +108 -4
  155. package/dist/task/taskRecordReference.js +0 -1
  156. package/dist/turn/turn.js +109 -16
  157. package/dist/verification/verificationGateService.js +0 -26
  158. package/dist/version.js +3 -3
  159. package/dist/web/assets/client/components.js +99 -121
  160. package/dist/web/assets/client/i18n.js +136 -58
  161. package/dist/web/assets/client/view.js +44 -0
  162. package/dist/web/assets/styles/cards.js +3 -15
  163. package/dist/web/assets/styles/widgets.js +4 -0
  164. package/dist/web/webSnapshot.js +29 -14
  165. package/dist/workItem/dependencyGate.js +34 -0
  166. package/dist/workItem/workItem.js +99 -266
  167. package/dist/workspace/workItemChangeSetManager.js +15 -59
  168. package/docs/task-local-identity.md +9 -9
  169. package/i18n/README.zh-CN.md +189 -74
  170. package/package.json +1 -1
  171. package/skills/yui-leader/SKILL.md +272 -782
  172. package/skills/yui-operator/SKILL.md +190 -365
  173. package/skills/yui-reviewer/SKILL.md +40 -33
  174. package/skills/yui-runtime/SKILL.md +22 -0
  175. package/skills/yui-worker/SKILL.md +19 -6
  176. package/dist/execution/candidateConvergence.js +0 -623
  177. package/dist/execution/executionGroup.js +0 -854
  178. package/dist/execution/resourceBroker.js +0 -426
  179. package/dist/executor/launchPlan.js +0 -16
  180. package/dist/review/reviewFinding.js +0 -240
  181. package/dist/review/reviewFindingLedger.js +0 -550
  182. package/dist/review/reviewOutcomeClassifier.js +0 -255
  183. package/dist/scheduler/resourceQueueProjection.js +0 -71
  184. package/dist/storage/upgrade/recordVersions.js +0 -82
  185. package/dist/task/repairWave.js +0 -150
@@ -292,6 +292,50 @@ export function renderTaskDetail(detail, data, t, locale, actions) {
292
292
  // the attention/blocker facts behind it.
293
293
  const band = executionBand(data.execution, t, locale);
294
294
  if (band) summaryBody.append(band);
295
+ if (data.remoteDelivery) {
296
+ const remote = data.remoteDelivery;
297
+ const card = node("article", "record-card");
298
+ const head = node("div", "record-head");
299
+ head.append(
300
+ node("strong", "record-title", t("detail.remoteDelivery")),
301
+ pill(t, "remoteDelivery", remote.status)
302
+ );
303
+ card.append(head);
304
+ card.append(node(
305
+ "p",
306
+ "record-copy",
307
+ t("detail.expectedHeads") + " · " + remote.source
308
+ + (remote.provisional ? " · " + t("detail.provisional") : "")
309
+ ));
310
+ const facts = node("div", "record-meta");
311
+ const unavailable = remote.status === "unavailable";
312
+ facts.append(
313
+ node("span", "", t("detail.allMerged") + " · "
314
+ + (unavailable
315
+ ? t("detail.unavailable")
316
+ : remote.allMerged ? t("common.yes") : t("common.no"))),
317
+ node("span", "", t("detail.allVerified") + " · "
318
+ + (unavailable
319
+ ? t("detail.unavailable")
320
+ : remote.allVerified ? t("common.yes") : t("common.no"))),
321
+ node("span", "", t("detail.integratedCoverage") + " · "
322
+ + (unavailable
323
+ ? t("detail.unavailable")
324
+ : remote.integratedCoverageSatisfied ? t("detail.satisfied") : t("detail.blocked")))
325
+ );
326
+ card.append(facts);
327
+ remote.projects.forEach(function (project) {
328
+ card.append(node(
329
+ "p",
330
+ "muted mono",
331
+ project.directory + " · " + project.coverage + " · "
332
+ + (project.expectedLocalCommit ? project.expectedLocalCommit.slice(0, 12) : "unknown")
333
+ + " → "
334
+ + (project.remoteCommit ? project.remoteCommit.slice(0, 12) : "unknown")
335
+ ));
336
+ });
337
+ summaryBody.append(card);
338
+ }
295
339
  const observability = data.observability || (data.execution && data.execution.observability);
296
340
  const metrics = observabilityMetricCard(observability, t);
297
341
  if (metrics) summaryBody.append(metrics);
@@ -151,7 +151,7 @@ details.work-item-card>summary.record-head~*{margin-top:0}
151
151
  .exec-signal.is-blocker{background:var(--danger-soft);border:1px solid color-mix(in srgb,var(--danger) 30%,transparent)}
152
152
  .exec-signal-kind{flex:none;font-family:var(--font-mono);font-size:9.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
153
153
  .exec-signal-text{min-width:0;color:var(--text)}
154
- /* Unified execution Group (Lanes + resolution) */
154
+ /* WorkItem execution and recovery */
155
155
  .exec-group{gap:8px}
156
156
  .lane-list{display:grid;gap:4px}
157
157
  .lane-row{display:flex;align-items:center;gap:9px;padding:5px 9px;border-radius:var(--radius);background:var(--bg-3);border:1px solid var(--border);font-size:11.5px}
@@ -159,9 +159,8 @@ details.work-item-card>summary.record-head~*{margin-top:0}
159
159
  .lane-role{font-family:var(--font-body);font-weight:700;font-size:12px;color:var(--text)}
160
160
  .lane-status{font-family:var(--font-mono);font-size:9.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
161
161
  .lane-summary{flex:1;min-width:0;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
162
- .execution-stage-meta,.execution-resource-meta,.work-item-observability{gap:10px;flex-wrap:wrap}
163
- .work-item-stages{margin-top:6px}
164
- .execution-stage-meta .chip,.execution-resource-meta .chip{margin-left:auto}
162
+ .execution-resource-meta,.work-item-observability{gap:10px;flex-wrap:wrap}
163
+ .execution-resource-meta .chip{margin-left:auto}
165
164
  .observability-metrics{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:8px;margin-top:12px}
166
165
  .observability-metrics .metric{min-height:52px;padding:8px 10px}
167
166
  .observability-metrics .metric-value{font-size:18px}
@@ -193,17 +192,6 @@ details.work-item-card>summary.record-head~*{margin-top:0}
193
192
  .candidate-summary{flex:1;min-width:0;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
194
193
  .candidate-source{flex:none;font-family:var(--font-mono);font-size:9.5px;letter-spacing:.04em;text-transform:uppercase;color:var(--muted)}
195
194
  .candidate-row time{flex:none;color:var(--muted);font-size:10.5px}
196
- /* Findings */
197
- .finding-list{display:grid;gap:4px}
198
- .finding-row{display:flex;align-items:baseline;gap:8px;padding:5px 9px;border-radius:var(--radius);background:var(--bg-3);border:1px solid var(--border);font-size:11.5px}
199
- .finding-summary{flex:1;min-width:0;color:var(--text)}
200
- .finding-row.is-critical,.finding-row.is-high{border-left:2px solid var(--danger)}
201
- .finding-row.is-medium{border-left:2px solid var(--warning)}
202
- .finding-row.is-low{border-left:2px solid var(--faint)}
203
- .chip.is-critical{color:var(--danger);border-color:var(--danger)}
204
- .chip.is-high{color:var(--danger)}
205
- .chip.is-medium{color:var(--warning)}
206
- .chip.is-low{color:var(--muted)}
207
195
  /* Sidebar derived execution status */
208
196
  .task-exec{grid-row:1;grid-column:3;align-self:center;flex:none;font-family:var(--font-mono);font-size:8.5px;letter-spacing:.05em;text-transform:uppercase;color:var(--faint);white-space:nowrap;max-width:90px;overflow:hidden;text-overflow:ellipsis}
209
197
  .task-exec.is-blocked,.task-exec.is-attention{color:var(--danger)}
@@ -104,6 +104,10 @@ kbd{background:var(--bg-3);border:1px solid var(--border);border-bottom-width:2p
104
104
  .status-dot{width:8px;height:8px;flex:none;border-radius:50%;background:var(--faint);margin-top:4px}
105
105
  .status-dot.active{background:var(--active);box-shadow:0 0 8px var(--active)}
106
106
  .status-dot.completed{background:var(--success);box-shadow:0 0 8px var(--success)}
107
+ .status-dot.running{background:var(--active);box-shadow:0 0 8px var(--active)}
108
+ .status-dot.succeeded{background:var(--success);box-shadow:0 0 8px var(--success)}
109
+ .status-dot.needs-attention{background:var(--warning);box-shadow:0 0 8px var(--warning)}
110
+ .status-dot.failed{background:var(--danger);box-shadow:0 0 8px var(--danger)}
107
111
  .status-dot.draft{background:var(--warning);box-shadow:0 0 8px var(--warning)}
108
112
  .status-dot.retired{background:var(--faint)}
109
113
  .status-dot.archived{background:var(--faint)}
@@ -1,12 +1,13 @@
1
1
  import { isRoleTurnStalled, latestTurnDurableProgressAt } from "../scheduler/roleTurnStall.js";
2
+ import { retiredTaskRecordIds } from "../task/taskRecordRetirement.js";
2
3
  import { buildTaskExecutionProjection } from "../scheduler/taskExecutionProjection.js";
3
- import { summarizeExecutionGroup } from "../execution/executionGroup.js";
4
- import { currentWorkItemExecutionGroup } from "../workItem/workItem.js";
4
+ import { projectWorkItemExecution } from "../execution/workItemExecutionProjection.js";
5
5
  import { classifyRuntimeHealth, projectRuntimeTaskEvents } from "../runtime/runtimeProjection.js";
6
6
  import { builtinDriverIdForAdapter } from "../runtime/builtinAgentDrivers.js";
7
7
  import { formatTurnReceiptId } from "../task/taskRecordReference.js";
8
8
  import { resolveRuntimeHealth } from "../config/yuiConfig.js";
9
9
  import { projectSessionTokenMetrics, resolveSessionTokenIdentity } from "../runtime/sessionTokenMetrics.js";
10
+ import { projectTaskRemoteDelivery } from "../task/remoteDelivery.js";
10
11
  export function buildWebDashboardSnapshot(store, now = new Date()) {
11
12
  return store.transaction((reader) => {
12
13
  const statusCounts = {
@@ -70,6 +71,7 @@ export function buildWebTaskDetail(store, taskId, now = new Date()) {
70
71
  });
71
72
  const turns = reader.listTurns(taskId);
72
73
  const events = reader.listEvents?.(taskId) ?? [];
74
+ const retiredMessageIds = retiredTaskRecordIds(events, "message");
73
75
  const needsAttentionTurns = turns
74
76
  .filter((turn) => turn.status === "active" && isRoleTurnStalled(events, turn.id))
75
77
  .map((turn) => ({
@@ -109,6 +111,9 @@ export function buildWebTaskDetail(store, taskId, now = new Date()) {
109
111
  const execution = buildTaskExecutionProjection(reader, taskId, task, now);
110
112
  if (execution === null)
111
113
  return null;
114
+ const remoteDelivery = webRemoteDelivery(reader, task);
115
+ const workItems = reader.listWorkItems(taskId);
116
+ const roleSessionSets = reader.listRoleSessionSets(taskId);
112
117
  const workItemObservability = new Map(execution.observability.workItems.map((item) => [item.workItemId, item]));
113
118
  return {
114
119
  task: {
@@ -116,27 +121,38 @@ export function buildWebTaskDetail(store, taskId, now = new Date()) {
116
121
  ...(projectNames.length === 0 ? {} : { projectNames })
117
122
  },
118
123
  execution,
124
+ remoteDelivery,
119
125
  observability: execution.observability,
120
126
  brief: reader.getTaskBrief(taskId),
121
127
  roles,
122
- workItems: reader.listWorkItems(taskId).map((item) => {
123
- const group = currentWorkItemExecutionGroup(item);
124
- return {
125
- ...item,
126
- observability: workItemObservability.get(item.id),
127
- ...(group === undefined ? {} : { currentExecution: summarizeExecutionGroup(group) })
128
- };
129
- }),
128
+ workItems: workItems.map((item) => ({
129
+ ...item,
130
+ observability: workItemObservability.get(item.id),
131
+ execution: projectWorkItemExecution(item, turns, roleSessionSets)
132
+ })),
130
133
  turns,
131
134
  runtimeHealth: { needsAttentionTurns, activeTurns: activeTurnHealth },
132
135
  reviewRounds: reader.listReviewRounds(taskId),
133
136
  openInputs: inputs.filter((request) => request.status === "open"),
134
- messages: reader.listMessages(taskId),
137
+ messages: reader.listMessages(taskId).map((message) => ({
138
+ ...message,
139
+ status: retiredMessageIds.has(message.id) ? "retired" : "active"
140
+ })),
135
141
  decisions: reader.listDecisions(taskId),
136
142
  milestones: reader.listMilestones(taskId)
137
143
  };
138
144
  });
139
145
  }
146
+ function webRemoteDelivery(reader, task) {
147
+ return projectTaskRemoteDelivery({
148
+ task,
149
+ events: reader.listEvents?.(task.id) ?? [],
150
+ publications: reader.listPublicationReferences(task.id),
151
+ managedWorkspaces: reader.listManagedWorkspaces(task.id),
152
+ turns: reader.listTurns(task.id),
153
+ currentCandidate: null
154
+ });
155
+ }
140
156
  function latestStallProgress(events, turnId) {
141
157
  return latestStallField(events, turnId, "progressAt");
142
158
  }
@@ -153,7 +169,7 @@ function projectWebTurnRuntimeHealth(reader, taskId, turn, events, now, policy)
153
169
  const sessions = reader.getTaskRoleSessionSet(taskId, turn.roleName);
154
170
  const session = sessions?.sessions[turn.effective.agentId];
155
171
  const stallReason = "the live active Turn has no durable progress in the configured stall window";
156
- if (session?.launchId === undefined) {
172
+ if (session?.runtimeGenerationId === undefined) {
157
173
  return {
158
174
  turnId: turn.id,
159
175
  roleName: turn.roleName,
@@ -184,8 +200,7 @@ function projectWebTurnRuntimeHealth(reader, taskId, turn, events, now, policy)
184
200
  turnId: turn.id,
185
201
  agentId: turn.effective.agentId,
186
202
  driverId,
187
- launchId: session.launchId,
188
- sessionGenerationId: session.launchId,
203
+ runtimeGenerationId: session.runtimeGenerationId,
189
204
  nativeSessionId: session.nativeSessionId,
190
205
  nativeTurnId: providerTurn?.turnId === turn.id
191
206
  ? providerTurn.nativeTurnId ?? turn.id
@@ -0,0 +1,34 @@
1
+ export const WORK_ITEM_DEPENDENCIES_NOT_COMPLETED = "work-item-dependencies-not-completed";
2
+ export class WorkItemDependencyGateError extends Error {
3
+ details;
4
+ constructor(workItemId, unmetDependencies) {
5
+ super(`Work Item dependencies are not completed: ${unmetDependencies
6
+ .map(({ id, status }) => `${id} (${status})`)
7
+ .join(", ")}.`);
8
+ this.name = "WorkItemDependencyGateError";
9
+ this.details = Object.freeze({
10
+ reason: WORK_ITEM_DEPENDENCIES_NOT_COMPLETED,
11
+ workItemId,
12
+ unmetDependencies: Object.freeze([...unmetDependencies])
13
+ });
14
+ }
15
+ }
16
+ /**
17
+ * The direct `dependsOn` list is the only dependency authority. Every direct
18
+ * dependency must exist and be completed; retirement and replacement metadata
19
+ * never satisfy or rewrite the edge.
20
+ */
21
+ export function assertWorkItemDependenciesCompleted(store, item) {
22
+ const unmetDependencies = item.dependsOn.flatMap((dependencyId) => {
23
+ const dependency = store.getWorkItem(item.taskId, dependencyId);
24
+ if (dependency?.status === "completed")
25
+ return [];
26
+ return [{
27
+ id: dependencyId,
28
+ status: dependency?.status ?? "missing"
29
+ }];
30
+ });
31
+ if (unmetDependencies.length > 0) {
32
+ throw new WorkItemDependencyGateError(item.id, unmetDependencies);
33
+ }
34
+ }