@zq-silk/yui 0.15.7 → 0.15.9
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 +194 -399
- package/ARCHITECTURE.zh-CN.md +151 -0
- package/README.md +306 -1131
- 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/artifacts/artifactCapability.js +74 -0
- package/dist/artifacts/artifactCommitLock.js +249 -0
- package/dist/artifacts/artifactPaths.js +151 -0
- package/dist/artifacts/gitArtifactRef.js +146 -0
- package/dist/artifacts/managedGit.js +332 -0
- package/dist/artifacts/taskArtifactRepository.js +277 -0
- package/dist/brief/taskBrief.js +12 -0
- package/dist/cli/agentConfigurationPicker.js +13 -0
- package/dist/cli/commandCatalog.js +165 -74
- 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 +245 -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 +34 -9
- 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 +281 -0
- package/dist/commands/taskActor.js +28 -49
- package/dist/commands/taskCommands.js +1461 -720
- 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} +158 -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 +481 -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 +120 -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 +255 -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 +118 -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 +388 -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 +75 -0
- package/dist/resources/projectResourceService.js +343 -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 +3 -7
- package/dist/storage/migrations/agentRunContract.js +159 -0
- package/dist/storage/migrations/artifactsToGit.js +338 -0
- package/dist/storage/migrations/removeRuntimeGeneration.js +207 -0
- package/dist/storage/migrations/submitIntent.js +126 -0
- package/dist/storage/sqliteSchema.js +467 -7
- package/dist/storage/sqliteStore.js +355 -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 +327 -0
- package/dist/task/taskActivationService.js +408 -0
- package/dist/task/taskRecordReference.js +5 -4
- package/dist/task/taskRecordRetirement.js +1 -1
- package/dist/task/taskSubmission.js +236 -0
- 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 +121 -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 +442 -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 +133 -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 +84 -48
- package/dist/workspace/workItemChangeSetManager.js +16 -9
- package/docs/agent-result-consumption.md +96 -0
- package/docs/agent-result-consumption.zh-CN.md +81 -0
- package/docs/agent-runtime-drivers.md +93 -0
- package/docs/agent-runtime-drivers.zh-CN.md +77 -0
- package/docs/architecture/README.md +50 -0
- package/docs/architecture/README.zh-CN.md +43 -0
- package/docs/architecture/capabilities-and-resources.md +118 -0
- package/docs/architecture/capabilities-and-resources.zh-CN.md +83 -0
- package/docs/managed-turn-and-session-runtime.md +224 -0
- package/docs/managed-turn-and-session-runtime.zh-CN.md +180 -0
- package/docs/observability/README.md +83 -0
- package/docs/observability/README.zh-CN.md +71 -0
- package/docs/plugin-sdk.md +393 -0
- package/docs/plugin-sdk.zh-CN.md +293 -0
- package/docs/provider-runtime.md +165 -0
- package/docs/provider-runtime.zh-CN.md +132 -0
- package/docs/release-workflow.md +305 -0
- package/docs/release-workflow.zh-CN.md +237 -0
- package/docs/roles-and-configuration.md +115 -0
- package/docs/roles-and-configuration.zh-CN.md +96 -0
- package/docs/sqlite-control-plane-design.md +78 -0
- package/docs/sqlite-control-plane-design.zh-CN.md +62 -0
- package/docs/task-dag-semantics.md +80 -0
- package/docs/task-dag-semantics.zh-CN.md +59 -0
- package/docs/task-delivery.md +105 -0
- package/docs/task-delivery.zh-CN.md +82 -0
- package/docs/task-local-identity.md +8 -6
- package/docs/task-local-identity.zh-CN.md +58 -0
- package/docs/testing/verification-levels.md +88 -0
- package/docs/testing/verification-levels.zh-CN.md +69 -0
- package/i18n/README.zh-CN.md +270 -722
- package/package.json +3 -2
- package/skills/yui-leader/SKILL.md +88 -304
- package/skills/yui-leader/references/execution.md +303 -0
- package/skills/yui-leader/references/integration.md +39 -0
- package/skills/yui-leader/references/planning.md +109 -0
- package/skills/yui-leader/references/replicated-execution.md +42 -0
- package/skills/yui-leader/references/task-plugins.md +37 -0
- package/skills/yui-operator/SKILL.md +46 -62
- 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
|
@@ -13,20 +13,17 @@ export async function runSessionNotifyCommand(payloadArgument, environment = pro
|
|
|
13
13
|
if (params.scope === "global")
|
|
14
14
|
return;
|
|
15
15
|
const home = requireText(environment.YUI_HOME, "YUI_HOME");
|
|
16
|
-
//
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const current = currentNotifyGeneration(home, params);
|
|
20
|
-
const enqueued = new FileRuntimeEventInbox(home).enqueueTurnTerminal({
|
|
16
|
+
// The caller reports native identity; durable state supplies the current AgentRun.
|
|
17
|
+
const current = currentNotifyRun(home, params);
|
|
18
|
+
const enqueued = new FileRuntimeEventInbox(home).enqueueRunTerminal({
|
|
21
19
|
scope: params.scope,
|
|
22
20
|
...(params.scope === "task" ? { taskId: params.taskId } : {}),
|
|
23
21
|
roleName: params.roleName,
|
|
24
22
|
agentId: params.agentId,
|
|
25
23
|
adapterId: params.adapterId,
|
|
26
|
-
...(current.runtimeGenerationId === undefined ? {} : { runtimeGenerationId: current.runtimeGenerationId }),
|
|
27
24
|
nativeSessionId: params.nativeSessionId,
|
|
28
25
|
nativeTurnId: params.nativeTurnId,
|
|
29
|
-
...(current.
|
|
26
|
+
...(current.runId === undefined ? {} : { runId: current.runId }),
|
|
30
27
|
...(params.title === undefined ? {} : { title: params.title }),
|
|
31
28
|
providerStatus: "completed",
|
|
32
29
|
outcome: params.outcome
|
|
@@ -45,34 +42,32 @@ export async function runSessionNotifyCommand(payloadArgument, environment = pro
|
|
|
45
42
|
roleName: params.roleName
|
|
46
43
|
})
|
|
47
44
|
}, { timeoutMs: 100 }).catch(() => { });
|
|
48
|
-
if (enqueued.created && shouldSetThreadName(home, params, current.
|
|
45
|
+
if (enqueued.created && shouldSetThreadName(home, params, current.runId)) {
|
|
49
46
|
const request = threadNameRequest(params, environment);
|
|
50
47
|
if (request !== null)
|
|
51
48
|
await setThreadName(request).catch(() => { });
|
|
52
49
|
}
|
|
53
50
|
}
|
|
54
51
|
/**
|
|
55
|
-
*
|
|
56
|
-
* Session. The envelope's runtime generation id only applies before Yui has projected a
|
|
57
|
-
* Session for this Role, which is the one moment durable state cannot answer.
|
|
52
|
+
* Resolve the active AgentRun only when the notifying native Session matches.
|
|
58
53
|
*/
|
|
59
|
-
function
|
|
54
|
+
function currentNotifyRun(home, params) {
|
|
60
55
|
if (params.scope !== "task" || params.taskId === undefined) {
|
|
61
|
-
return
|
|
56
|
+
return {};
|
|
62
57
|
}
|
|
63
58
|
try {
|
|
64
59
|
const store = openCurrentTaskStore(home);
|
|
65
60
|
const session = store.getTaskRoleSessionSet(params.taskId, params.roleName)
|
|
66
61
|
?.sessions[params.agentId];
|
|
67
|
-
const
|
|
68
|
-
|
|
62
|
+
const activeRun = store.getActiveRun(params.taskId, params.roleName);
|
|
63
|
+
if (session?.nativeSessionId !== params.nativeSessionId)
|
|
64
|
+
return {};
|
|
69
65
|
return {
|
|
70
|
-
...(
|
|
71
|
-
...(activeTurn === null ? {} : { turnId: activeTurn.id })
|
|
66
|
+
...(activeRun === null ? {} : { runId: activeRun.id })
|
|
72
67
|
};
|
|
73
68
|
}
|
|
74
69
|
catch {
|
|
75
|
-
return
|
|
70
|
+
return {};
|
|
76
71
|
}
|
|
77
72
|
}
|
|
78
73
|
export function parseCodexSessionNotification(payloadArgument, environment) {
|
|
@@ -95,9 +90,6 @@ export function parseCodexSessionNotification(payloadArgument, environment) {
|
|
|
95
90
|
roleName: requireText(environment.YUI_ROLE, "YUI_ROLE"),
|
|
96
91
|
agentId: requireText(environment.YUI_AGENT_ID, "YUI_AGENT_ID"),
|
|
97
92
|
adapterId: requireCodexAdapter(environment.YUI_ADAPTER_ID),
|
|
98
|
-
...(environment.YUI_RUNTIME_GENERATION_ID === undefined
|
|
99
|
-
? {}
|
|
100
|
-
: { runtimeGenerationId: requireText(environment.YUI_RUNTIME_GENERATION_ID, "YUI_RUNTIME_GENERATION_ID") }),
|
|
101
93
|
nativeSessionId,
|
|
102
94
|
nativeTurnId,
|
|
103
95
|
...(title === undefined ? {} : { title }),
|
|
@@ -138,14 +130,14 @@ function requireText(value, label) {
|
|
|
138
130
|
throw new Error(`${label} is invalid.`);
|
|
139
131
|
return text;
|
|
140
132
|
}
|
|
141
|
-
function shouldSetThreadName(home, params,
|
|
133
|
+
function shouldSetThreadName(home, params, runId) {
|
|
142
134
|
if (params.scope !== "task"
|
|
143
135
|
|| params.title === undefined
|
|
144
|
-
||
|
|
136
|
+
|| runId === undefined)
|
|
145
137
|
return false;
|
|
146
138
|
try {
|
|
147
139
|
const store = openCurrentTaskStore(home);
|
|
148
|
-
return store.
|
|
140
|
+
return store.getRun(params.taskId, runId)?.mode === "new";
|
|
149
141
|
}
|
|
150
142
|
catch {
|
|
151
143
|
return false;
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { createTaskEvent } from "../event/taskEvent.js";
|
|
4
|
-
import { createSessionOwnerIdentity,
|
|
5
|
-
import {
|
|
4
|
+
import { createSessionOwnerIdentity, isLinuxProcessLive, listOwnedProcessTree, readLinuxProcessIdentity, reconcileSessionOwners, terminateSessionOwners } from "../runtime/index.js";
|
|
5
|
+
import { sessionOwnerProcessKey } from "../runtime/sessionOwnerIdentity.js";
|
|
6
|
+
import { AGENT_HOST_CONTROL_PROTOCOL, sendAgentHostCancelControl } from "../runtime/agentHost.js";
|
|
7
|
+
import { settleProviderTurn, cancelQuiescentProviderInput, clearProviderGoal } from "../runtime/providerRuntimeIdentity.js";
|
|
8
|
+
import { updateTaskRoleProviderRuntime, taskRoleControlTarget } from "../executor/agentExecutor.js";
|
|
9
|
+
import { FileRoleLaunchPlanner } from "../executor/fileRoleLaunchPlanner.js";
|
|
10
|
+
import { stopCodexNativeSession } from "../runtime/nativeSessionControl.js";
|
|
11
|
+
import { routeRoleEvent } from "../scheduler/operatorEvent.js";
|
|
12
|
+
import { redactAgentErrorText } from "../runtime/agentError.js";
|
|
13
|
+
import { runtimeCleanupDisposition, runtimeLifecycleTarget } from "../runtime/lifecycleReservation.js";
|
|
6
14
|
import { tmuxSocketDirectory } from "../tmux/tmuxSocketEndpoint.js";
|
|
7
15
|
import { yuiTmuxServerName, yuiTmuxSessionName, yuiTmuxTarget } from "../tmux/tmuxManager.js";
|
|
8
16
|
/**
|
|
@@ -16,29 +24,33 @@ export class SessionOwnerReconciliation {
|
|
|
16
24
|
#environment;
|
|
17
25
|
#tmux;
|
|
18
26
|
#onWarning;
|
|
27
|
+
#cancelInput;
|
|
28
|
+
#nativeConnection;
|
|
29
|
+
#stopNative;
|
|
19
30
|
constructor(deps) {
|
|
20
31
|
this.#home = deps.home;
|
|
21
32
|
this.#store = deps.store;
|
|
22
33
|
this.#environment = deps.environment ?? process.env;
|
|
23
34
|
this.#tmux = deps.tmux;
|
|
24
35
|
this.#onWarning = deps.onWarning ?? (() => undefined);
|
|
36
|
+
this.#cancelInput = deps.cancelInput ?? sendAgentHostCancelControl;
|
|
37
|
+
this.#nativeConnection = deps.nativeConnection ?? ((taskId, roleName) => new FileRoleLaunchPlanner(this.#home, this.#store, { environment: this.#environment })
|
|
38
|
+
.planNativeControl(taskId, roleName));
|
|
39
|
+
this.#stopNative = deps.stopNative ?? stopCodexNativeSession;
|
|
25
40
|
}
|
|
26
41
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* YUI_RUNTIME_GENERATION_ID environment fence; the tmux pane PID is only a weaker
|
|
30
|
-
* fallback when the fence cannot be read.
|
|
42
|
+
* Capture the created pane's concrete process identity. No inherited
|
|
43
|
+
* environment marker is used to discover or claim other applications.
|
|
31
44
|
*/
|
|
32
45
|
recordHostOwner(input) {
|
|
33
|
-
const
|
|
34
|
-
const fallback = discovered === undefined && input.panePid !== undefined
|
|
46
|
+
const observed = input.panePid !== undefined
|
|
35
47
|
? readLinuxProcessIdentity(input.panePid)
|
|
36
48
|
: undefined;
|
|
37
|
-
const root =
|
|
49
|
+
const root = observed === undefined
|
|
38
50
|
? undefined
|
|
39
|
-
: { pid:
|
|
51
|
+
: { pid: observed.pid, identity: observed };
|
|
40
52
|
if (root === undefined) {
|
|
41
|
-
this.#onWarning(`Session owner identity could not
|
|
53
|
+
this.#onWarning(`Session owner identity could not read the Host process for ${input.owner.roleName}; `
|
|
42
54
|
+ "no owner record was written.");
|
|
43
55
|
return;
|
|
44
56
|
}
|
|
@@ -52,7 +64,6 @@ export class SessionOwnerReconciliation {
|
|
|
52
64
|
},
|
|
53
65
|
agentId: input.agentId,
|
|
54
66
|
adapterId: input.adapterId,
|
|
55
|
-
runtimeGenerationId: input.runtimeGenerationId,
|
|
56
67
|
...(input.nativeSessionId === undefined
|
|
57
68
|
? {}
|
|
58
69
|
: { nativeSessionId: input.nativeSessionId }),
|
|
@@ -74,7 +85,7 @@ export class SessionOwnerReconciliation {
|
|
|
74
85
|
...(root.identity.processSessionId === undefined
|
|
75
86
|
? {}
|
|
76
87
|
: { processSessionId: root.identity.processSessionId }),
|
|
77
|
-
attribution:
|
|
88
|
+
attribution: "pane-pid"
|
|
78
89
|
},
|
|
79
90
|
...(input.runtimeRoot === undefined ? {} : { runtimeRoot: input.runtimeRoot }),
|
|
80
91
|
recordedAt: new Date()
|
|
@@ -98,7 +109,7 @@ export class SessionOwnerReconciliation {
|
|
|
98
109
|
return undefined;
|
|
99
110
|
}
|
|
100
111
|
},
|
|
101
|
-
lastStopOutcome: (taskId, roleName
|
|
112
|
+
lastStopOutcome: (taskId, roleName) => (lastSessionTerminationOutcome(this.#store, taskId, roleName)),
|
|
102
113
|
now: new Date()
|
|
103
114
|
});
|
|
104
115
|
}
|
|
@@ -108,7 +119,27 @@ export class SessionOwnerReconciliation {
|
|
|
108
119
|
*/
|
|
109
120
|
async terminateOwner(owner, options = {}) {
|
|
110
121
|
const records = this.#store.listSessionOwnersForOwner(owner);
|
|
111
|
-
|
|
122
|
+
// Killing a proxy is not cancelling its remote Turn. Settle the exact
|
|
123
|
+
// owned native input before any Host signal or owner-record removal.
|
|
124
|
+
try {
|
|
125
|
+
await this.#quiesceInput(owner);
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
this.#recordTerminationEvent({ owner, stage: "stop-blocked",
|
|
129
|
+
detail: redactAgentErrorText(error instanceof Error ? error.message : String(error)).slice(0, 2000),
|
|
130
|
+
at: new Date() });
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
const result = await terminateSessionOwners(owner, records, this.#terminationPorts(), options);
|
|
134
|
+
if (result.outcome === "stop-confirmed") {
|
|
135
|
+
for (const record of result.confirmed) {
|
|
136
|
+
this.#store.removeSessionOwner(sessionOwnerProcessKey(record));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
#terminationPorts() {
|
|
142
|
+
return {
|
|
112
143
|
gracefulStop: async (target) => {
|
|
113
144
|
if (this.#tmux === undefined)
|
|
114
145
|
return false;
|
|
@@ -130,52 +161,149 @@ export class SessionOwnerReconciliation {
|
|
|
130
161
|
return false;
|
|
131
162
|
}
|
|
132
163
|
},
|
|
133
|
-
listLaunchFencedProcesses: (runtimeGenerationId) => listLaunchFencedProcesses(runtimeGenerationId),
|
|
134
164
|
signalProcess: (pid, signal) => process.kill(pid, signal),
|
|
135
|
-
signalProcessGroup: (processGroupId, signal) => {
|
|
136
|
-
try {
|
|
137
|
-
process.kill(-processGroupId, signal);
|
|
138
|
-
}
|
|
139
|
-
catch (error) {
|
|
140
|
-
if (error.code !== "ESRCH")
|
|
141
|
-
throw error;
|
|
142
|
-
}
|
|
143
|
-
},
|
|
144
165
|
sleep: (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)),
|
|
145
166
|
emit: (event) => this.#recordTerminationEvent(event),
|
|
146
167
|
now: () => new Date()
|
|
147
168
|
};
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
169
|
+
}
|
|
170
|
+
async #quiesceInput(owner) {
|
|
171
|
+
if (owner.scope !== "task")
|
|
172
|
+
return;
|
|
173
|
+
if (runtimeCleanupDisposition(this.#store.getWorkMailbox(runtimeLifecycleTarget(owner))) === "detach-host")
|
|
174
|
+
return;
|
|
175
|
+
const set = this.#store.getTaskRoleSessionSet(owner.taskId, owner.roleName);
|
|
176
|
+
const binding = set?.providerBinding;
|
|
177
|
+
const input = binding?.run;
|
|
178
|
+
const unsettled = input != null && ["submitting", "accepted", "delivery-unknown"].includes(input.status);
|
|
179
|
+
const hasGoal = binding?.goal != null && binding.goal.status !== "complete";
|
|
180
|
+
const selected = taskRoleControlTarget(set);
|
|
181
|
+
if (set == null || (!unsettled && !hasGoal && selected?.adapterId !== "codex"))
|
|
182
|
+
return;
|
|
183
|
+
if (selected === undefined) {
|
|
184
|
+
throw new Error("Cannot identify the native execution to stop.");
|
|
185
|
+
}
|
|
186
|
+
const request = this.#store.listEvents(owner.taskId).filter(event => ["runtime.session-replacement-requested", "runtime.session-stop-requested"].includes(event.type)
|
|
187
|
+
&& event.payload.roleName === owner.roleName
|
|
188
|
+
&& event.payload.nativeSessionId === selected.nativeSessionId).at(-1);
|
|
189
|
+
const operatorStop = this.#store.getTask(owner.taskId)?.executionGate.state === "stopped"
|
|
190
|
+
|| (request !== undefined && ["user", "operator"].includes(request.payload.requestedBy));
|
|
191
|
+
if (binding?.authority.owner === "human" && !operatorStop) {
|
|
192
|
+
throw new Error("This native Session is under human control; Operator/user must request its stop or replacement.");
|
|
193
|
+
}
|
|
194
|
+
let terminal;
|
|
195
|
+
try {
|
|
196
|
+
const result = unsettled && binding?.authority.owner === "controller" && binding.authority.holderId !== undefined ? await this.#cancelInput({
|
|
197
|
+
home: this.#home, scope: "task", taskId: owner.taskId, roleName: owner.roleName,
|
|
198
|
+
control: {
|
|
199
|
+
protocol: AGENT_HOST_CONTROL_PROTOCOL, type: "cancel",
|
|
200
|
+
nativeSessionId: selected.nativeSessionId,
|
|
201
|
+
attemptId: input.attemptId, authority: {
|
|
202
|
+
epoch: binding.authority.epoch, owner: "controller", holderId: binding.authority.holderId
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}) : undefined;
|
|
206
|
+
const proof = result?.cancellation?.terminal;
|
|
207
|
+
if (result?.cancellation?.status !== "unknown" && proof?.clientOwned
|
|
208
|
+
&& proof.attemptId === input?.attemptId && proof.nativeSessionId === selected.nativeSessionId
|
|
209
|
+
&& (input?.nativeTurnId === undefined || proof.nativeTurnId === input.nativeTurnId))
|
|
210
|
+
terminal = proof;
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
// Recovery follows the recorded native identity, not the availability of
|
|
214
|
+
// the disposable Host which used to own its control socket.
|
|
215
|
+
}
|
|
216
|
+
if (terminal === undefined || hasGoal || selected.adapterId === "codex") {
|
|
217
|
+
if (selected.adapterId === "codex") {
|
|
218
|
+
await this.#stopNative(this.#nativeConnection(owner.taskId, owner.roleName), {
|
|
219
|
+
conversationId: selected.nativeSessionId,
|
|
220
|
+
nativeTurnId: unsettled && terminal === undefined ? input?.nativeTurnId : undefined,
|
|
221
|
+
clearGoal: true
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
else if (selected.adapterId === "claude") {
|
|
225
|
+
const records = this.#store.listSessionOwnersForOwner(owner);
|
|
226
|
+
const children = records.filter(record => record.nativeSessionId === selected.nativeSessionId
|
|
227
|
+
&& record.providerRoot.attribution === "owned-child");
|
|
228
|
+
if (children.length > 0) {
|
|
229
|
+
const stopped = await terminateSessionOwners(owner, children, this.#terminationPorts());
|
|
230
|
+
if (stopped.outcome !== "stop-confirmed")
|
|
231
|
+
throw new Error("Dedicated native execution is still draining; no resource was released.");
|
|
232
|
+
}
|
|
233
|
+
else if (selected.status !== "ended"
|
|
234
|
+
|| records.some(ownerRootIsLive)
|
|
235
|
+
|| this.#tmux?.probeRoleStatus(owner.taskId, owner.roleName) !== "exited") {
|
|
236
|
+
throw new Error("Native process custody is unavailable; inspect the exact local execution before reusing its workspace.");
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
throw new Error("This Provider has no detached native control proof; inspect its execution resources before replacement.");
|
|
153
241
|
}
|
|
154
242
|
}
|
|
155
|
-
|
|
243
|
+
this.#store.transaction(tx => {
|
|
244
|
+
const current = tx.getTaskRoleSessionSet(owner.taskId, owner.roleName);
|
|
245
|
+
const provider = current?.providerBinding;
|
|
246
|
+
if (current == null || provider?.run?.attemptId !== input?.attemptId
|
|
247
|
+
|| (selected.fromBinding
|
|
248
|
+
? current.providerBinding?.conversations.find(entry => entry.status === "current")?.conversationId
|
|
249
|
+
: current.sessions[current.activeAgentId]?.nativeSessionId) !== selected.nativeSessionId
|
|
250
|
+
|| provider?.authority.epoch !== binding?.authority.epoch) {
|
|
251
|
+
throw new Error("Native input identity changed while confirming its stop.");
|
|
252
|
+
}
|
|
253
|
+
if (provider != null && (provider.run != null && ["submitting", "accepted", "delivery-unknown"].includes(provider.run.status)
|
|
254
|
+
|| hasGoal || selected.adapterId === "codex")) {
|
|
255
|
+
const now = new Date();
|
|
256
|
+
let stopped = provider;
|
|
257
|
+
if (unsettled && input != null) {
|
|
258
|
+
stopped = terminal !== undefined && provider.run?.status === "accepted"
|
|
259
|
+
? settleProviderTurn(provider, { attemptId: input.attemptId, nativeTurnId: terminal.nativeTurnId,
|
|
260
|
+
status: terminal.status, settledAt: now.toISOString() })
|
|
261
|
+
: cancelQuiescentProviderInput(provider, { attemptId: input.attemptId, cancelledAt: now.toISOString(),
|
|
262
|
+
reason: "Explicit Session stop; native execution quiescence independently verified." });
|
|
263
|
+
}
|
|
264
|
+
if (hasGoal || selected.adapterId === "codex")
|
|
265
|
+
stopped = clearProviderGoal(stopped);
|
|
266
|
+
tx.saveTaskRoleSessionSet(updateTaskRoleProviderRuntime(current, stopped, now));
|
|
267
|
+
tx.saveEvent(owner.taskId, createTaskEvent(tx.nextEventId(owner.taskId), owner.taskId, "runtime.input-stop-confirmed", {
|
|
268
|
+
roleName: owner.roleName, ...(input == null ? {} : { attemptId: input.attemptId }),
|
|
269
|
+
nativeSessionId: selected.nativeSessionId, status: stopped.run?.status ?? "quiescent",
|
|
270
|
+
evidence: terminal === undefined ? "native-resource-inspection" : "native-terminal",
|
|
271
|
+
...(input?.nativeTurnId === undefined ? {} : { nativeTurnId: input.nativeTurnId })
|
|
272
|
+
}, now));
|
|
273
|
+
}
|
|
274
|
+
else if (selected.adapterId === "codex") {
|
|
275
|
+
tx.saveEvent(owner.taskId, createTaskEvent(tx.nextEventId(owner.taskId), owner.taskId, "runtime.input-stop-confirmed", {
|
|
276
|
+
roleName: owner.roleName, nativeSessionId: selected.nativeSessionId,
|
|
277
|
+
status: "quiescent", evidence: "native-resource-inspection"
|
|
278
|
+
}, new Date()));
|
|
279
|
+
}
|
|
280
|
+
});
|
|
156
281
|
}
|
|
157
282
|
#recordTerminationEvent(event) {
|
|
158
283
|
const owner = event.owner;
|
|
159
|
-
if (event.stage === "stop-requested" && event.runtimeGenerationId !== undefined) {
|
|
160
|
-
writeRuntimeStopReceipt(this.#home, event.runtimeGenerationId, event.at);
|
|
161
|
-
}
|
|
162
284
|
if (owner.scope !== "task")
|
|
163
285
|
return;
|
|
164
286
|
try {
|
|
165
|
-
this.#store.
|
|
287
|
+
const last = this.#store.listEvents(owner.taskId).filter(entry => entry.type === "runtime.session-termination" && entry.payload.roleName === owner.roleName).at(-1);
|
|
288
|
+
if (event.stage === "stop-blocked" && last?.payload.outcome === event.stage
|
|
289
|
+
&& last.payload.detail === event.detail)
|
|
290
|
+
return;
|
|
291
|
+
const fact = createTaskEvent(this.#store.nextEventId(owner.taskId), owner.taskId, "runtime.session-termination", {
|
|
166
292
|
roleName: owner.roleName,
|
|
167
|
-
runtimeGenerationId: event.runtimeGenerationId ?? "",
|
|
168
293
|
nativeSessionId: event.nativeSessionId ?? "",
|
|
169
294
|
outcome: event.stage,
|
|
170
295
|
...(event.detail === undefined ? {} : { detail: event.detail })
|
|
171
|
-
}, event.at)
|
|
296
|
+
}, event.at);
|
|
297
|
+
this.#store.saveEvent(owner.taskId, fact);
|
|
298
|
+
if (event.stage === "stop-blocked")
|
|
299
|
+
routeRoleEvent(this.#store, fact, owner.roleName, "session-recovery-blocked", event.at);
|
|
172
300
|
}
|
|
173
301
|
catch (error) {
|
|
174
302
|
this.#onWarning(`Session termination event could not be persisted: ${error instanceof Error ? error.message : String(error)}`);
|
|
175
303
|
}
|
|
176
304
|
}
|
|
177
305
|
}
|
|
178
|
-
/** Projects every durable Role runtime
|
|
306
|
+
/** Projects every durable Role runtime for reconciliation. */
|
|
179
307
|
export function durableSessionFacts(store) {
|
|
180
308
|
const facts = [];
|
|
181
309
|
for (const task of store.listTasks()) {
|
|
@@ -187,7 +315,6 @@ export function durableSessionFacts(store) {
|
|
|
187
315
|
roleName: set.owner.roleName,
|
|
188
316
|
agentId,
|
|
189
317
|
adapterId: session.adapterId,
|
|
190
|
-
...(session.runtimeGenerationId === undefined ? {} : { runtimeGenerationId: session.runtimeGenerationId }),
|
|
191
318
|
...(session.nativeSessionId === undefined
|
|
192
319
|
? {}
|
|
193
320
|
: { nativeSessionId: session.nativeSessionId }),
|
|
@@ -202,7 +329,6 @@ export function durableSessionFacts(store) {
|
|
|
202
329
|
roleName: set.owner.roleName,
|
|
203
330
|
agentId: history.agentId,
|
|
204
331
|
adapterId: history.adapterId,
|
|
205
|
-
...(history.runtimeGenerationId === undefined ? {} : { runtimeGenerationId: history.runtimeGenerationId }),
|
|
206
332
|
...(history.nativeSessionId === undefined
|
|
207
333
|
? {}
|
|
208
334
|
: { nativeSessionId: history.nativeSessionId }),
|
|
@@ -219,7 +345,6 @@ export function durableSessionFacts(store) {
|
|
|
219
345
|
roleName: set.owner.roleName,
|
|
220
346
|
agentId,
|
|
221
347
|
adapterId: session.adapterId,
|
|
222
|
-
...(session.runtimeGenerationId === undefined ? {} : { runtimeGenerationId: session.runtimeGenerationId }),
|
|
223
348
|
...(session.nativeSessionId === undefined
|
|
224
349
|
? {}
|
|
225
350
|
: { nativeSessionId: session.nativeSessionId }),
|
|
@@ -234,7 +359,6 @@ export function durableSessionFacts(store) {
|
|
|
234
359
|
roleName: set.owner.roleName,
|
|
235
360
|
agentId: session.agentId,
|
|
236
361
|
adapterId: session.adapterId,
|
|
237
|
-
...(session.runtimeGenerationId === undefined ? {} : { runtimeGenerationId: session.runtimeGenerationId }),
|
|
238
362
|
...(session.nativeSessionId === undefined
|
|
239
363
|
? {}
|
|
240
364
|
: { nativeSessionId: session.nativeSessionId }),
|
|
@@ -296,8 +420,8 @@ export function observeSessionOwnerPhysical(record) {
|
|
|
296
420
|
childCount: Math.max(0, tree.length - 1)
|
|
297
421
|
};
|
|
298
422
|
}
|
|
299
|
-
/** Reads the latest termination outcome recorded for one
|
|
300
|
-
export function lastSessionTerminationOutcome(store, taskId, roleName
|
|
423
|
+
/** Reads the latest termination outcome recorded for one Role. */
|
|
424
|
+
export function lastSessionTerminationOutcome(store, taskId, roleName) {
|
|
301
425
|
if (taskId === undefined)
|
|
302
426
|
return undefined;
|
|
303
427
|
let latest;
|
|
@@ -306,12 +430,6 @@ export function lastSessionTerminationOutcome(store, taskId, roleName, runtimeGe
|
|
|
306
430
|
continue;
|
|
307
431
|
if (event.payload.roleName !== roleName)
|
|
308
432
|
continue;
|
|
309
|
-
if (runtimeGenerationId !== ""
|
|
310
|
-
&& event.payload.runtimeGenerationId !== undefined
|
|
311
|
-
&& event.payload.runtimeGenerationId !== ""
|
|
312
|
-
&& event.payload.runtimeGenerationId !== runtimeGenerationId) {
|
|
313
|
-
continue;
|
|
314
|
-
}
|
|
315
433
|
latest = event.payload.outcome;
|
|
316
434
|
}
|
|
317
435
|
return latest;
|