@zq-silk/yui 0.15.7 → 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 +157 -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 +178 -95
- package/dist/commands/agentCommands.js +72 -14
- package/dist/commands/capabilityCommands.js +9 -6
- 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 +1188 -710
- 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 +17 -6
- package/dist/controller/clientRuntime.js +65 -92
- package/dist/controller/controller.js +114 -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 +529 -479
- 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 +247 -12
- package/dist/kernel/capabilityRegistry.js +64 -18
- package/dist/kernel/instanceHost.js +12 -1
- package/dist/kernel/kernelPorts.js +2 -2
- 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 +2 -2
- 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
|
@@ -5,7 +5,7 @@ const DEFAULT_MAX_CONCURRENT_SAMPLES = 8;
|
|
|
5
5
|
const MAX_CONCURRENT_SAMPLES = 64;
|
|
6
6
|
/**
|
|
7
7
|
* Controller-owned, provider-independent sampler. Drivers own source parsing;
|
|
8
|
-
* this component owns active-
|
|
8
|
+
* this component owns active-AgentRun discovery, cursor lifetime, canonical event
|
|
9
9
|
* creation, and low-latency mailbox wakes.
|
|
10
10
|
*/
|
|
11
11
|
export class AgentRuntimeObserver {
|
|
@@ -72,8 +72,8 @@ export class AgentRuntimeObserver {
|
|
|
72
72
|
let usages = sample.usages ?? [];
|
|
73
73
|
if (state.usage === undefined) {
|
|
74
74
|
// Cumulative counters need a lower bound. An exact initial sample
|
|
75
|
-
// proves the complete Session
|
|
76
|
-
// current
|
|
75
|
+
// proves the complete Session history even when the
|
|
76
|
+
// current AgentRun resumed that Session, so preserve every occurrence and
|
|
77
77
|
// anchor it at zero. A partial sample cannot prove the omitted request
|
|
78
78
|
// boundaries; retain its latest total as a partial baseline, plus the
|
|
79
79
|
// smallest ordered witness if the visible counter already rolled back.
|
|
@@ -251,43 +251,43 @@ export class AgentRuntimeObserver {
|
|
|
251
251
|
&& task.executionGate.state === "enabled"));
|
|
252
252
|
for (const task of activeTasks) {
|
|
253
253
|
// A Task still incurs one O(E) event projection. Group those observations
|
|
254
|
-
// by
|
|
254
|
+
// by AgentRun and sort each group once so every active AgentRun can reuse the same
|
|
255
255
|
// ordered slice instead of repeatedly filtering/sorting all E events.
|
|
256
|
-
const
|
|
256
|
+
const observationsByRunId = new Map();
|
|
257
257
|
const taskObservations = [];
|
|
258
258
|
for (const event of this.store.listEvents(task.id)) {
|
|
259
259
|
const observation = runtimeObservationFromTaskEvent(event);
|
|
260
|
-
const
|
|
261
|
-
if (observation === null ||
|
|
260
|
+
const runId = observation?.fence.runId;
|
|
261
|
+
if (observation === null || runId === undefined)
|
|
262
262
|
continue;
|
|
263
263
|
taskObservations.push(observation);
|
|
264
|
-
const grouped =
|
|
264
|
+
const grouped = observationsByRunId.get(runId);
|
|
265
265
|
if (grouped === undefined) {
|
|
266
|
-
|
|
266
|
+
observationsByRunId.set(runId, [observation]);
|
|
267
267
|
}
|
|
268
268
|
else {
|
|
269
269
|
grouped.push(observation);
|
|
270
270
|
}
|
|
271
271
|
}
|
|
272
|
-
for (const observations of
|
|
272
|
+
for (const observations of observationsByRunId.values()) {
|
|
273
273
|
observations.sort(compareObservations);
|
|
274
274
|
}
|
|
275
275
|
taskObservations.sort(compareObservations);
|
|
276
|
-
for (const run of this.store.
|
|
276
|
+
for (const run of this.store.listRuns(task.id)) {
|
|
277
277
|
if (run.status !== "active"
|
|
278
|
-
|| this.store.
|
|
278
|
+
|| this.store.getActiveRun(task.id, run.roleName)?.id !== run.id)
|
|
279
279
|
continue;
|
|
280
|
-
const observations =
|
|
280
|
+
const observations = observationsByRunId.get(run.id) ?? [];
|
|
281
281
|
const accepted = observations
|
|
282
282
|
.filter((observation) => observation.kind === "turn.accepted"
|
|
283
|
-
&& observation.fence.
|
|
283
|
+
&& observation.fence.runId === run.id
|
|
284
284
|
&& observation.fence.roleName === run.roleName
|
|
285
285
|
&& observation.fence.agentId === run.effective.agentId
|
|
286
286
|
&& observation.payload.observerSource !== undefined)
|
|
287
287
|
.at(-1);
|
|
288
288
|
const source = accepted?.payload.observerSource;
|
|
289
289
|
if (accepted === undefined || source === undefined
|
|
290
|
-
|| accepted.fence.taskId === undefined || accepted.fence.
|
|
290
|
+
|| accepted.fence.taskId === undefined || accepted.fence.runId === undefined)
|
|
291
291
|
continue;
|
|
292
292
|
try {
|
|
293
293
|
if (this.drivers.require(accepted.fence.driverId).runtime.observer === undefined)
|
|
@@ -297,14 +297,14 @@ export class AgentRuntimeObserver {
|
|
|
297
297
|
continue;
|
|
298
298
|
}
|
|
299
299
|
const fence = accepted.fence;
|
|
300
|
-
const
|
|
300
|
+
const sessionObservations = taskObservations.filter((observation) => (sessionRuntimeFenceMatches(fence, observation.fence)
|
|
301
301
|
&& observation.payload.sourceId === source.sourceId));
|
|
302
|
-
const persistedUsage =
|
|
302
|
+
const persistedUsage = sessionObservations.filter((observation) => (observation.kind === "activity.observed"
|
|
303
303
|
&& observation.payload.usage !== undefined)).at(-1);
|
|
304
|
-
const persistedActivity =
|
|
304
|
+
const persistedActivity = sessionObservations.filter((observation) => (observation.kind === "activity.observed"
|
|
305
305
|
&& observation.payload.activityId !== undefined
|
|
306
306
|
&& observation.payload.usage === undefined)).at(-1);
|
|
307
|
-
const persistedHealth =
|
|
307
|
+
const persistedHealth = sessionObservations.filter((observation) => (observation.kind === "observer.health"
|
|
308
308
|
&& observation.payload.sourceId === source.sourceId)).at(-1);
|
|
309
309
|
const persistedUsageResume = persistedUsage === undefined
|
|
310
310
|
? undefined
|
|
@@ -313,10 +313,9 @@ export class AgentRuntimeObserver {
|
|
|
313
313
|
key: JSON.stringify([
|
|
314
314
|
fence.taskId,
|
|
315
315
|
fence.roleName,
|
|
316
|
-
fence.
|
|
316
|
+
fence.runId,
|
|
317
317
|
fence.agentId,
|
|
318
318
|
fence.driverId,
|
|
319
|
-
fence.runtimeGenerationId,
|
|
320
319
|
fence.nativeSessionId,
|
|
321
320
|
source.sourceId
|
|
322
321
|
]),
|
|
@@ -462,19 +461,17 @@ function tokenObservationId(kind, fence, sourceId, value) {
|
|
|
462
461
|
fence.roleName,
|
|
463
462
|
fence.agentId,
|
|
464
463
|
fence.driverId,
|
|
465
|
-
fence.runtimeGenerationId,
|
|
466
464
|
fence.nativeSessionId ?? null,
|
|
467
465
|
sourceId,
|
|
468
466
|
value
|
|
469
467
|
])).digest("hex")}`;
|
|
470
468
|
}
|
|
471
|
-
function
|
|
469
|
+
function sessionRuntimeFenceMatches(expected, actual) {
|
|
472
470
|
for (const field of [
|
|
473
471
|
"taskId",
|
|
474
472
|
"roleName",
|
|
475
473
|
"agentId",
|
|
476
474
|
"driverId",
|
|
477
|
-
"runtimeGenerationId",
|
|
478
475
|
"nativeSessionId"
|
|
479
476
|
]) {
|
|
480
477
|
if (expected[field] !== actual[field])
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { capabilitySchemaError } from "../kernel/capabilitySchema.js";
|
|
2
|
+
import { SurfaceContributions } from "../surface/surfaceContributions.js";
|
|
2
3
|
/** The same transport method is usable by CLI, Agent and an authenticated
|
|
3
4
|
* Surface adapter. Credentials are an ingress envelope, never capability input. */
|
|
4
5
|
export function createCapabilityDispatcher(capabilities) {
|
|
6
|
+
const surfaces = new SurfaceContributions(capabilities.registry);
|
|
5
7
|
return async (method, value) => {
|
|
6
8
|
const error = capabilitySchemaError({
|
|
7
9
|
type: "object", required: ["taskId", "caller"],
|
|
@@ -12,12 +14,12 @@ export function createCapabilityDispatcher(capabilities) {
|
|
|
12
14
|
type: "object", required: ["scope"], additionalProperties: false,
|
|
13
15
|
properties: {
|
|
14
16
|
scope: { enum: ["user", "global", "task"] }, taskId: { type: "string" },
|
|
15
|
-
role: { type: "string" }, agentId: { type: "string" }, adapterId: { type: "string" },
|
|
16
|
-
|
|
17
|
-
turnId: { type: "string" }, callerKey: { type: "string" }
|
|
17
|
+
role: { type: "string" }, agentId: { type: "string" }, adapterId: { type: "string" }, nativeSessionId: { type: "string" },
|
|
18
|
+
runId: { type: "string" }
|
|
18
19
|
}
|
|
19
20
|
},
|
|
20
21
|
query: { type: "string" },
|
|
22
|
+
surface: { enum: ["commands", "panels"] },
|
|
21
23
|
request: {
|
|
22
24
|
type: "object", required: ["name"], additionalProperties: false,
|
|
23
25
|
properties: {
|
|
@@ -37,11 +39,20 @@ export function createCapabilityDispatcher(capabilities) {
|
|
|
37
39
|
if (method === "capability.search") {
|
|
38
40
|
if (params.request !== undefined)
|
|
39
41
|
throw invalidParams("search accepts query, not request.");
|
|
40
|
-
|
|
42
|
+
if (params.surface !== undefined) {
|
|
43
|
+
if (params.query !== undefined)
|
|
44
|
+
throw invalidParams("Surface listing does not accept query.");
|
|
45
|
+
result = params.surface === "commands"
|
|
46
|
+
? { commands: surfaces.listCommands(context) }
|
|
47
|
+
: { panels: surfaces.listPanels(context) };
|
|
48
|
+
}
|
|
49
|
+
else
|
|
50
|
+
result = { capabilities: capabilities.registry.search(context, params.query) };
|
|
41
51
|
}
|
|
42
52
|
else {
|
|
43
|
-
if (params.query !== undefined || params.request === undefined)
|
|
44
|
-
throw invalidParams("describe/call requires request.");
|
|
53
|
+
if (params.query !== undefined || params.surface !== undefined || params.request === undefined) {
|
|
54
|
+
throw invalidParams("describe/call requires request, not query or surface.");
|
|
55
|
+
}
|
|
45
56
|
if (method === "capability.describe")
|
|
46
57
|
result = capabilities.registry.describe(context, params.request);
|
|
47
58
|
else if (method === "capability.call") {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { findLiveControllerProcessForHome } from "../core/controllerProcessIdentity.js";
|
|
4
|
+
import { readHomeFilesystemId } from "../core/homeFilesystemIdentity.js";
|
|
3
5
|
import { callController, ControllerClientError, readControllerDiscovery, stopOrphanedFileTaskController } from "../core/controllerClient.js";
|
|
4
|
-
import { controllerSocketPath } from "../core/controllerEndpoint.js";
|
|
5
6
|
import { FILE_TASK_CONTROLLER_PROTOCOL_VERSION } from "../core/protocol.js";
|
|
6
7
|
import { AGENT_OPERATIONAL_ENVIRONMENT_NAMES, nativeAgentEnvironmentNames, operationalAgentEnvironment, selectEnvironment, YUI_MANAGED_RUNTIME_ENVIRONMENT_NAMES } from "../agent/launchEnvironment.js";
|
|
7
8
|
import { openCurrentTaskStore } from "../storage/currentTaskStore.js";
|
|
8
|
-
import { yuiTmuxServerName } from "../tmux/tmuxManager.js";
|
|
9
9
|
import { hasRuntimeLifecycleWork } from "../runtime/lifecycleReservation.js";
|
|
10
10
|
import { assertControllerStatusIdentity } from "../runtime/runtimeCoherence.js";
|
|
11
11
|
import { EPHEMERAL_DOMAIN_ENVIRONMENT_NAMES } from "./domainIdentity.js";
|
|
@@ -13,7 +13,6 @@ import { yuiVersionIdentity } from "../version.js";
|
|
|
13
13
|
import { SessionOwnerReconciliation } from "./sessionOwnerReconciliation.js";
|
|
14
14
|
import { WorkspaceCleanupBlockedError } from "../repository/taskWorkspacePreparer.js";
|
|
15
15
|
import { CONTROLLER_SHUTDOWN_TIMEOUT_MS, LIFECYCLE_REQUEST_TIMEOUT_MS } from "../runtime/runtimeDeadlines.js";
|
|
16
|
-
import { FileTaskRuntimeIsolation } from "../runtime/taskRuntimeIsolation.js";
|
|
17
16
|
import { isForeignHandoverLockHeld } from "../release/runtimeRelease.js";
|
|
18
17
|
const STARTUP_TIMEOUT_MS = 5_000;
|
|
19
18
|
const POLL_INTERVAL_MS = 50;
|
|
@@ -24,7 +23,7 @@ const CONTROLLER_OPERATIONAL_ENVIRONMENT = [
|
|
|
24
23
|
// The worker toggle changes process placement, not storage authority.
|
|
25
24
|
"YUI_STORE_WORKER",
|
|
26
25
|
// rr13/test: Forward the liveness seam so an integration test's Controller
|
|
27
|
-
// subprocess does not reap a saved active Leader
|
|
26
|
+
// subprocess does not reap a saved active Leader AgentRun without a real tmux role.
|
|
28
27
|
"YUI_TEST_ROLE_LIVENESS_PRESENT",
|
|
29
28
|
...EPHEMERAL_DOMAIN_ENVIRONMENT_NAMES
|
|
30
29
|
];
|
|
@@ -68,7 +67,13 @@ export async function ensureFileTaskController(home, options = {}) {
|
|
|
68
67
|
const timeoutMs = positive(options.startupTimeoutMs, STARTUP_TIMEOUT_MS, "startupTimeoutMs");
|
|
69
68
|
const pollMs = positive(options.pollIntervalMs, POLL_INTERVAL_MS, "pollIntervalMs");
|
|
70
69
|
const spawnController = options.spawnController ?? spawnDetachedFileTaskController;
|
|
71
|
-
|
|
70
|
+
// A readiness timeout is not exit evidence. Reuse the observable startup
|
|
71
|
+
// process for this exact Home rather than multiplying unready Controllers.
|
|
72
|
+
const existing = options.spawnController === undefined && options.call === undefined
|
|
73
|
+
? findLiveControllerProcessForHome(readHomeFilesystemId(home))
|
|
74
|
+
: undefined;
|
|
75
|
+
const startupPid = existing?.pid
|
|
76
|
+
?? spawnController(home, controllerSpawnEnvironment(home, options.environment ?? process.env));
|
|
72
77
|
const deadline = Date.now() + timeoutMs;
|
|
73
78
|
for (;;) {
|
|
74
79
|
try {
|
|
@@ -80,7 +85,9 @@ export async function ensureFileTaskController(home, options = {}) {
|
|
|
80
85
|
if (!isUnavailable(error))
|
|
81
86
|
throw error;
|
|
82
87
|
if (Date.now() >= deadline) {
|
|
83
|
-
throw new Error(`Controller did not become ready within ${timeoutMs} ms
|
|
88
|
+
throw new Error(`Controller did not become ready within ${timeoutMs} ms.`
|
|
89
|
+
+ (startupPid === undefined ? "" : ` Startup PID: ${startupPid}.`)
|
|
90
|
+
+ " Read current process state before retrying; timeout does not prove it stopped.", { cause: error });
|
|
84
91
|
}
|
|
85
92
|
await delay(pollMs);
|
|
86
93
|
}
|
|
@@ -88,7 +95,7 @@ export async function ensureFileTaskController(home, options = {}) {
|
|
|
88
95
|
}
|
|
89
96
|
/** Start and await readiness for a captured Controller identity. */
|
|
90
97
|
export async function ensureFileTaskControllerIdentity(home, identity, options = {}) {
|
|
91
|
-
|
|
98
|
+
assertExpectedControllerRuntimeProcessIdentity(identity);
|
|
92
99
|
const status = await ensureFileTaskController(home, {
|
|
93
100
|
...options,
|
|
94
101
|
expectedVersion: identity.version
|
|
@@ -102,36 +109,36 @@ export async function ensureFileTaskControllerIdentity(home, identity, options =
|
|
|
102
109
|
const actual = await call(home, "controller.identity", {}, {
|
|
103
110
|
timeoutMs: options.requestTimeoutMs
|
|
104
111
|
});
|
|
105
|
-
|
|
112
|
+
assertControllerRuntimeProcessIdentity(actual, identity);
|
|
106
113
|
return status;
|
|
107
114
|
}
|
|
108
|
-
function
|
|
115
|
+
function assertExpectedControllerRuntimeProcessIdentity(identity) {
|
|
109
116
|
if (typeof identity.executablePath !== "string"
|
|
110
117
|
|| identity.executablePath.length === 0
|
|
111
118
|
|| !Array.isArray(identity.args)
|
|
112
119
|
|| identity.args.some((arg) => typeof arg !== "string")
|
|
113
120
|
|| typeof identity.version !== "string"
|
|
114
121
|
|| identity.version.length === 0) {
|
|
115
|
-
throw new Error("Expected Controller runtime
|
|
122
|
+
throw new Error("Expected Controller runtime identity is malformed; refusing to start or accept a Controller.");
|
|
116
123
|
}
|
|
117
124
|
}
|
|
118
|
-
function
|
|
125
|
+
function assertControllerRuntimeProcessIdentity(actual, expected) {
|
|
119
126
|
if (!isJsonRecord(actual)) {
|
|
120
|
-
throw new Error("Authenticated Controller runtime
|
|
127
|
+
throw new Error("Authenticated Controller runtime identity is malformed; refusing to accept readiness.");
|
|
121
128
|
}
|
|
122
129
|
const actualArgs = actual.args;
|
|
123
130
|
if (typeof actual.executablePath !== "string"
|
|
124
131
|
|| !Array.isArray(actualArgs)
|
|
125
132
|
|| actualArgs.some((arg) => typeof arg !== "string")
|
|
126
133
|
|| typeof actual.version !== "string") {
|
|
127
|
-
throw new Error("Authenticated Controller runtime
|
|
134
|
+
throw new Error("Authenticated Controller runtime identity is malformed; refusing to accept readiness.");
|
|
128
135
|
}
|
|
129
136
|
const argsMatch = actualArgs.length === expected.args.length
|
|
130
137
|
&& actualArgs.every((arg, index) => arg === expected.args[index]);
|
|
131
138
|
if (actual.executablePath !== expected.executablePath
|
|
132
139
|
|| !argsMatch
|
|
133
140
|
|| actual.version !== expected.version) {
|
|
134
|
-
throw new Error("Authenticated Controller runtime
|
|
141
|
+
throw new Error("Authenticated Controller runtime identity does not match the captured executable, argv, and version; refusing readiness.");
|
|
135
142
|
}
|
|
136
143
|
}
|
|
137
144
|
function assertCompatibleControllerStatus(status, expectedVersion) {
|
|
@@ -166,10 +173,33 @@ function spawnDetachedFileTaskController(home, environment) {
|
|
|
166
173
|
stdio: "ignore"
|
|
167
174
|
});
|
|
168
175
|
child.unref();
|
|
176
|
+
return child.pid;
|
|
169
177
|
}
|
|
170
178
|
/** Stops the per-home Controller and waits until its owned discovery is gone. */
|
|
171
179
|
export async function stopFileTaskController(home, options = {}) {
|
|
172
|
-
|
|
180
|
+
await waitForForeignHandover(home, options);
|
|
181
|
+
const physical = options.call === undefined
|
|
182
|
+
? findLiveControllerProcessForHome(readHomeFilesystemId(home)) : undefined;
|
|
183
|
+
const expectedPid = options.expectedPid ?? physical?.pid;
|
|
184
|
+
const bounded = { ...options, requestTimeoutMs: options.requestTimeoutMs ?? 2000,
|
|
185
|
+
...(expectedPid === undefined ? {} : { expectedPid }) };
|
|
186
|
+
try {
|
|
187
|
+
const result = await stopControllerGracefully(home, bounded);
|
|
188
|
+
if (result.stopped || options.call !== undefined)
|
|
189
|
+
return result;
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
if (options.call !== undefined || !controllerRecoveryError(error))
|
|
193
|
+
throw error;
|
|
194
|
+
}
|
|
195
|
+
const stopped = await stopOrphanedFileTaskController(home, options.shutdownTimeoutMs ?? CONTROLLER_SHUTDOWN_TIMEOUT_MS, { force: true, ...(expectedPid === undefined ? {} : { expectedPid }),
|
|
196
|
+
...(physical === undefined ? {} : { expectedProcessStartIdentity: physical.processStartIdentity }) });
|
|
197
|
+
return stopped === undefined ? { stopped: false, alreadyStopped: true } : { stopped: true, pid: stopped.pid };
|
|
198
|
+
}
|
|
199
|
+
async function stopControllerGracefully(home, options) {
|
|
200
|
+
const call = options.call ?? ((h, method, params) => callController(h, method, params, {
|
|
201
|
+
timeoutMs: options.requestTimeoutMs
|
|
202
|
+
}));
|
|
173
203
|
const shutdownTimeoutMs = positive(options.shutdownTimeoutMs, CONTROLLER_SHUTDOWN_TIMEOUT_MS, "shutdownTimeoutMs");
|
|
174
204
|
const pollMs = positive(options.pollIntervalMs, POLL_INTERVAL_MS, "pollIntervalMs");
|
|
175
205
|
const expectedPid = options.expectedPid === undefined
|
|
@@ -178,6 +208,8 @@ export async function stopFileTaskController(home, options = {}) {
|
|
|
178
208
|
const current = await readOptionalControllerStatus(home, call);
|
|
179
209
|
const pid = controllerPid(current);
|
|
180
210
|
if (expectedPid !== undefined && pid !== expectedPid) {
|
|
211
|
+
if (pid === undefined)
|
|
212
|
+
throw new ControllerClientError("CONTROLLER_UNAVAILABLE", `Controller ownership could not be queried for expected PID ${expectedPid}.`);
|
|
181
213
|
throw new Error(`Controller ownership changed before fenced stop (expected PID ${expectedPid}, `
|
|
182
214
|
+ `found ${pid === undefined ? "none" : pid}).`);
|
|
183
215
|
}
|
|
@@ -214,7 +246,7 @@ export async function stopFileTaskController(home, options = {}) {
|
|
|
214
246
|
break;
|
|
215
247
|
}
|
|
216
248
|
if (Date.now() >= deadline) {
|
|
217
|
-
throw new
|
|
249
|
+
throw new ControllerClientError("CONTROLLER_TIMEOUT", `Controller did not stop within ${shutdownTimeoutMs} ms.`);
|
|
218
250
|
}
|
|
219
251
|
await delay(pollMs);
|
|
220
252
|
}
|
|
@@ -225,41 +257,8 @@ export async function stopFileTaskController(home, options = {}) {
|
|
|
225
257
|
}
|
|
226
258
|
/** Restarts only the per-home Controller process; managed tmux sessions remain untouched. */
|
|
227
259
|
export async function restartFileTaskController(home, options = {}) {
|
|
228
|
-
const
|
|
229
|
-
const
|
|
230
|
-
const pollMs = positive(options.pollIntervalMs, POLL_INTERVAL_MS, "pollIntervalMs");
|
|
231
|
-
let current = null;
|
|
232
|
-
let previousPid;
|
|
233
|
-
try {
|
|
234
|
-
current = await readOptionalControllerStatus(home, call);
|
|
235
|
-
previousPid = controllerPid(current);
|
|
236
|
-
}
|
|
237
|
-
catch (error) {
|
|
238
|
-
if (options.call !== undefined || !isInvalidDiscovery(error))
|
|
239
|
-
throw error;
|
|
240
|
-
// A malformed current discovery record cannot authorize a protocol call.
|
|
241
|
-
// Exact process identity below may still fence and stop an orphaned owner.
|
|
242
|
-
}
|
|
243
|
-
if (!controllerRunning(current) && options.call === undefined) {
|
|
244
|
-
const orphan = await stopOrphanedFileTaskController(home, shutdownTimeoutMs);
|
|
245
|
-
if (orphan !== undefined)
|
|
246
|
-
previousPid = orphan.pid;
|
|
247
|
-
}
|
|
248
|
-
if (controllerRunning(current)) {
|
|
249
|
-
await callFileTaskController(home, "controller.stop", {}, options);
|
|
250
|
-
const deadline = Date.now() + shutdownTimeoutMs;
|
|
251
|
-
for (;;) {
|
|
252
|
-
const stillOwned = options.call === undefined
|
|
253
|
-
? await ownedControllerDiscoveryExists(home, previousPid)
|
|
254
|
-
: controllerPid(await readOptionalControllerStatus(home, call)) === previousPid;
|
|
255
|
-
if (!stillOwned)
|
|
256
|
-
break;
|
|
257
|
-
if (Date.now() >= deadline) {
|
|
258
|
-
throw new Error(`Controller did not stop within ${shutdownTimeoutMs} ms.`);
|
|
259
|
-
}
|
|
260
|
-
await delay(pollMs);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
260
|
+
const stopped = await stopFileTaskController(home, options);
|
|
261
|
+
const previousPid = stopped.pid;
|
|
263
262
|
const started = await ensureFileTaskController(home, options);
|
|
264
263
|
const pid = controllerPid(started);
|
|
265
264
|
return {
|
|
@@ -268,6 +267,12 @@ export async function restartFileTaskController(home, options = {}) {
|
|
|
268
267
|
...(pid === undefined ? {} : { pid })
|
|
269
268
|
};
|
|
270
269
|
}
|
|
270
|
+
function controllerRecoveryError(error) {
|
|
271
|
+
return error instanceof ControllerClientError && [
|
|
272
|
+
"CONTROLLER_TIMEOUT", "CONTROLLER_UNAVAILABLE", "CONTROLLER_DELIVERY_UNKNOWN",
|
|
273
|
+
"CONTROLLER_DISCOVERY_INVALID", "INVALID_RESPONSE", "CONTROLLER_NOT_RUNNING"
|
|
274
|
+
].includes(error.code);
|
|
275
|
+
}
|
|
271
276
|
function controllerSpawnEnvironment(home, source) {
|
|
272
277
|
const allowed = new Set(CONTROLLER_OPERATIONAL_ENVIRONMENT);
|
|
273
278
|
try {
|
|
@@ -433,8 +438,8 @@ export class FileTaskWorkflowRuntime {
|
|
|
433
438
|
async stopTaskRoleSessions(taskId, roleNames) {
|
|
434
439
|
const targets = [];
|
|
435
440
|
for (const roleName of [...new Set(roleNames)]) {
|
|
436
|
-
if (this.store.
|
|
437
|
-
throw new Error(`Role has an active
|
|
441
|
+
if (this.store.getActiveRun(taskId, roleName) !== null) {
|
|
442
|
+
throw new Error(`Role has an active AgentRun: ${taskId}/${roleName}.`);
|
|
438
443
|
}
|
|
439
444
|
const target = this.schedulerStore.enqueueRuntimeCleanup({
|
|
440
445
|
scope: "task",
|
|
@@ -464,11 +469,8 @@ export class FileTaskWorkflowRuntime {
|
|
|
464
469
|
}
|
|
465
470
|
}
|
|
466
471
|
}
|
|
467
|
-
/**
|
|
472
|
+
/** Explicitly stops the exact Session observed by an Agent command. */
|
|
468
473
|
async stopExactTaskRoleSession(input) {
|
|
469
|
-
if (this.store.getActiveTurn(input.taskId, input.roleName) !== null) {
|
|
470
|
-
throw new Error(`Role has an active Turn: ${input.taskId}/${input.roleName}.`);
|
|
471
|
-
}
|
|
472
474
|
const owner = {
|
|
473
475
|
scope: "task",
|
|
474
476
|
taskId: input.taskId,
|
|
@@ -479,9 +481,8 @@ export class FileTaskWorkflowRuntime {
|
|
|
479
481
|
agentId: input.agentId,
|
|
480
482
|
adapterId: input.adapterId,
|
|
481
483
|
nativeSessionId: input.nativeSessionId,
|
|
482
|
-
...(input.runtimeGenerationId === undefined ? {} : { runtimeGenerationId: input.runtimeGenerationId }),
|
|
483
484
|
sessionUpdatedAt: input.sessionUpdatedAt
|
|
484
|
-
});
|
|
485
|
+
}, true);
|
|
485
486
|
if (target === null) {
|
|
486
487
|
throw new Error(`Role Session changed before its exact stop was reserved: ${input.taskId}/${input.roleName}.`);
|
|
487
488
|
}
|
|
@@ -492,14 +493,9 @@ export class FileTaskWorkflowRuntime {
|
|
|
492
493
|
if (hasRuntimeLifecycleWork(this.store.getWorkMailbox(target))) {
|
|
493
494
|
throw new Error(`Role runtime did not stop: ${input.taskId}/${input.roleName}.`);
|
|
494
495
|
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
&& session.agentId === input.agentId
|
|
499
|
-
&& session.adapterId === input.adapterId
|
|
500
|
-
&& session.nativeSessionId === input.nativeSessionId) {
|
|
501
|
-
throw new Error(`Role runtime session is still active: ${input.taskId}/${input.roleName}.`);
|
|
502
|
-
}
|
|
496
|
+
// Cleanup completion proves the requested stop. A retained Message may
|
|
497
|
+
// already have started a successor on the same reusable conversation;
|
|
498
|
+
// its new active state must not retroactively turn this stop into failure.
|
|
503
499
|
}
|
|
504
500
|
/** Wait until every cancellation requested by Task execution stop is physically settled. */
|
|
505
501
|
async stopTaskDurableJobs(taskId) {
|
|
@@ -563,7 +559,7 @@ export class FileTaskWorkflowRuntime {
|
|
|
563
559
|
if (blockers.length === 0)
|
|
564
560
|
return;
|
|
565
561
|
throw new WorkspaceCleanupBlockedError("physical-resource-live", `task:${taskId}`, true, `Task archive blocked: ${blockers.length} owned physical resource(s) still live: `
|
|
566
|
-
+ blockers.map((entry) => (`${entry.owner.roleName}/${entry.
|
|
562
|
+
+ blockers.map((entry) => (`${entry.owner.roleName}/${entry.nativeSessionId ?? "unknown-session"}`
|
|
567
563
|
+ ` (pid ${entry.physical?.alive === true ? entry.physical.pid : "?"})`)).join("; "));
|
|
568
564
|
}
|
|
569
565
|
async stopGlobalRoleSession(roleName) {
|
|
@@ -622,27 +618,9 @@ export class FileTaskWorkflowRuntime {
|
|
|
622
618
|
if (termination.outcome !== "stop-confirmed") {
|
|
623
619
|
throw new Error(`Role runtime cleanup could not prove physical exit: ${runtimeOwnerLabel(candidate.owner)}; `
|
|
624
620
|
+ termination.remaining
|
|
625
|
-
.map(({ record, detail }) =>
|
|
621
|
+
.map(({ record, detail }) => `PID ${record.providerRoot.pid}: ${detail}`)
|
|
626
622
|
.join("; "));
|
|
627
623
|
}
|
|
628
|
-
if (candidate.owner.scope === "task" && candidate.runtimeGenerationId !== undefined) {
|
|
629
|
-
const isolation = new FileTaskRuntimeIsolation({
|
|
630
|
-
runtimeRoot: `${this.home}.task-runtimes`,
|
|
631
|
-
controlPlane: {
|
|
632
|
-
yuiHome: this.home,
|
|
633
|
-
controllerSocketPath: controllerSocketPath(this.store.getHomeIdentity().homeId),
|
|
634
|
-
tmuxNamespace: yuiTmuxServerName(this.home),
|
|
635
|
-
globalInstallPaths: [process.execPath]
|
|
636
|
-
}
|
|
637
|
-
});
|
|
638
|
-
isolation.cleanupTaskLaunch({
|
|
639
|
-
taskId: candidate.owner.taskId,
|
|
640
|
-
runtimeGenerationId: candidate.runtimeGenerationId,
|
|
641
|
-
reason: this.store.getTask(candidate.owner.taskId)?.status === "completed"
|
|
642
|
-
? "completion"
|
|
643
|
-
: "interruption"
|
|
644
|
-
});
|
|
645
|
-
}
|
|
646
624
|
if (!this.schedulerStore.completeRuntimeCleanup(target, new Date())) {
|
|
647
625
|
throw new Error(`Role runtime cleanup state changed before completion: ${runtimeOwnerLabel(candidate.owner)}.`);
|
|
648
626
|
}
|
|
@@ -746,11 +724,6 @@ function isDefinitelyNotRunning(error) {
|
|
|
746
724
|
const code = error.code;
|
|
747
725
|
return code === "CONTROLLER_NOT_RUNNING";
|
|
748
726
|
}
|
|
749
|
-
function isInvalidDiscovery(error) {
|
|
750
|
-
if (typeof error !== "object" || error === null || !("code" in error))
|
|
751
|
-
return false;
|
|
752
|
-
return error.code === "CONTROLLER_DISCOVERY_INVALID";
|
|
753
|
-
}
|
|
754
727
|
async function readOptionalControllerStatus(home, call) {
|
|
755
728
|
try {
|
|
756
729
|
return await call(home, "controller.status", {});
|