@zq-silk/yui 0.15.12 → 0.16.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.
- package/ARCHITECTURE.md +3 -2
- package/ARCHITECTURE.zh-CN.md +3 -2
- package/dist/artifacts/artifactCommitLock.js +16 -55
- package/dist/artifacts/taskArtifactRepository.js +3 -3
- package/dist/cli/agentConfigurationPicker.js +1 -1
- package/dist/cli/commandCatalog.js +57 -41
- package/dist/cli/completion.js +18 -18
- package/dist/cli/completionWizard.js +1 -1
- package/dist/cli/dynamicCompletion.js +1 -1
- package/dist/cli/interactionPolicy.js +7 -3
- package/dist/cli/invocationAuthority.js +64 -0
- package/dist/cli/managedDiagnostics.js +1 -1
- package/dist/cli/parseRepeatable.js +35 -0
- package/dist/cli/updatePorts.js +26 -5
- package/dist/cli.js +1280 -1243
- package/dist/commands/agentCommands.js +4 -4
- package/dist/commands/capabilityCommands.js +1 -1
- package/dist/commands/configCommands.js +6 -57
- package/dist/commands/configOverview.js +2 -2
- package/dist/commands/durableJobCommands.js +12 -6
- package/dist/commands/globalRoleCommands.js +53 -29
- package/dist/commands/grantCommands.js +0 -3
- package/dist/commands/jobCommands.js +1 -4
- package/dist/commands/operatorCommands.js +3 -3
- package/dist/commands/projectCommands.js +1 -10
- package/dist/commands/resourcesCommands.js +10 -40
- package/dist/commands/roleConfiguration.js +2 -6
- package/dist/commands/taskActivationCommands.js +4 -8
- package/dist/commands/taskAgentCapabilities.js +9 -0
- package/dist/commands/taskCommandSupport.js +155 -0
- package/dist/commands/taskCommandTypes.js +1 -0
- package/dist/commands/taskCommands.js +271 -710
- package/dist/commands/taskCompletionGate.js +1 -1
- package/dist/commands/taskExecutionCommands.js +1 -1
- package/dist/commands/taskFactCommands.js +325 -0
- package/dist/commands/taskInputCommands.js +12 -42
- package/dist/commands/taskIntegrationCommands.js +17 -57
- package/dist/commands/taskNextActionCommand.js +7 -6
- package/dist/commands/taskPublicationAdoptCommand.js +3 -3
- package/dist/commands/taskPublicationCommands.js +1 -1
- package/dist/commands/taskPublicationVerifyCommand.js +1 -1
- package/dist/commands/taskRemoteDeliveryCommand.js +2 -94
- package/dist/commands/taskUpstreamCommands.js +19 -8
- package/dist/commands/workflowCommands.js +6 -1
- package/dist/completion/completionInstaller.js +26 -26
- package/dist/completion/completionState.js +26 -26
- package/dist/completion/fileCompletionManager.js +6 -11
- package/dist/config/configCatalog.js +0 -2
- package/dist/config/timeZone.js +14 -0
- package/dist/config/yuiConfig.js +0 -29
- package/dist/context/runContextPack.js +2 -3
- package/dist/context/taskCatalog.js +3 -5
- package/dist/context/taskContext.js +139 -151
- package/dist/context/wakeRunReferences.js +11 -0
- package/dist/controller/agentCapabilities.js +58 -0
- package/dist/controller/agentRuntimeObserver.js +6 -11
- package/dist/controller/clientRuntime.js +22 -14
- package/dist/controller/controller.js +9 -22
- package/dist/controller/fileSchedulerStoreAdapter.js +117 -212
- package/dist/controller/jobClient.js +4 -4
- package/dist/controller/jobControl.js +60 -25
- package/dist/controller/jobSupervisor.js +4 -4
- package/dist/controller/providerRetryDelivery.js +7 -7
- package/dist/controller/runtime.js +51 -44
- package/dist/controller/runtimeEventProcessor.js +0 -5
- package/dist/controller/sessionOwnerReconciliation.js +5 -0
- package/dist/controller/taskAgentError.js +35 -0
- package/dist/coordination/workMailboxQueue.js +2 -24
- package/dist/core/controllerClient.js +2 -2
- package/dist/core/fileLockOwner.js +74 -0
- package/dist/decision/decision.js +17 -0
- package/dist/doctor/doctor.js +18 -9
- package/dist/event/taskEvent.js +12 -0
- package/dist/execution/workItemExecutionProjection.js +2 -2
- package/dist/executor/agentCapabilityConfig.js +43 -0
- package/dist/executor/agentConfigurationCatalog.js +49 -11
- package/dist/executor/agentExecutor.js +5 -8
- package/dist/executor/fileRoleLaunchPlanner.js +11 -53
- package/dist/executor/taskAgentCapabilities.js +64 -0
- package/dist/integration/deliveryObligation.js +1 -69
- package/dist/integration/gitIntegrationService.js +60 -84
- package/dist/integration/integrationAttempt.js +3 -14
- package/dist/integration/integrationSourceApplication.js +4 -12
- package/dist/integration/manifestTags.js +2 -2
- package/dist/job/durableJob.js +4 -25
- package/dist/job/jobAssignmentScope.js +22 -0
- package/dist/job/jobOperation.js +16 -0
- package/dist/job/jobRunner.js +2 -1
- package/dist/job/stepDirectory.js +15 -0
- package/dist/kernel/builtinCapabilities.js +15 -11
- package/dist/kernel/kernelPorts.js +1 -17
- package/dist/lifecycle/exactRunTerminalization.js +1 -9
- package/dist/message/inputControlResolution.js +3 -4
- package/dist/message/message.js +17 -20
- package/dist/message/messageContinuation.js +1 -1
- package/dist/milestone/milestone.js +11 -0
- package/dist/observability/orchestrationMetrics.js +24 -1
- package/dist/observability/runtimeIdentity.js +1 -17
- package/dist/output/agentConfigurationPresentation.js +2 -0
- package/dist/output/timePresentation.js +1 -14
- package/dist/plugins/pluginService.js +12 -4
- package/dist/release/releaseWorkflowPorts.js +45 -96
- package/dist/release/runtimeRelease.js +9 -15
- package/dist/repository/projectMaintenanceLock.js +23 -64
- package/dist/repository/taskBaseFreshness.js +1 -1
- package/dist/repository/taskWorkspaceCoordinator.js +13 -22
- package/dist/repository/taskWorkspacePreparer.js +29 -25
- package/dist/repository/workspaceCleanupInspection.js +5 -5
- package/dist/resources/autoResourceGc.js +4 -77
- package/dist/resources/liveReferences.js +7 -54
- package/dist/resources/resourceDiscovery.js +5 -118
- package/dist/resources/resourceGc.js +233 -181
- package/dist/resources/resourceRegistrar.js +5 -4
- package/dist/resources/resourceRegistry.js +3 -37
- package/dist/resources/resourceRegistryStore.js +13 -36
- package/dist/resources/sqliteResourceRegistry.js +43 -26
- package/dist/review/deltaRecheck.js +1 -1
- package/dist/review/reviewAcceptance.js +1 -1
- package/dist/review/reviewDecision.js +1 -1
- package/dist/review/reviewRound.js +8 -7
- package/dist/review/taskFinalReviewContractResolution.js +1 -1
- package/dist/runtime/acpProtocol.js +4 -51
- package/dist/runtime/acpSession.js +10 -75
- package/dist/runtime/acpSessionConfiguration.js +1 -8
- package/dist/runtime/agentEndpoint.js +3 -2
- package/dist/runtime/agentFailureContext.js +43 -0
- package/dist/runtime/agentHost.js +15 -15
- package/dist/runtime/codexInteractiveHost.js +2 -2
- package/dist/runtime/index.js +0 -1
- package/dist/runtime/managedCaller.js +21 -1
- package/dist/runtime/providerErrors.js +38 -0
- package/dist/runtime/runtimeObservation.js +0 -5
- package/dist/runtime/runtimeSessionCandidate.js +2 -3
- package/dist/runtime/sessionOwnerIdentity.js +1 -1
- package/dist/runtime/structuredProviderHost.js +4 -41
- package/dist/runtime/tmuxAdapters.js +6 -8
- package/dist/scheduler/activeRoleRunDelivery.js +7 -7
- package/dist/scheduler/leaderWakeupProcessor.js +19 -6
- package/dist/scheduler/operatorEvent.js +12 -20
- package/dist/scheduler/operatorInputNotificationProcessor.js +1 -1
- package/dist/scheduler/ports.js +5 -8
- package/dist/scheduler/roleRunLiveness.js +4 -4
- package/dist/scheduler/roleRunStall.js +16 -23
- package/dist/scheduler/taskExecutionProjection.js +25 -33
- package/dist/scheduler/taskObservabilityProjection.js +0 -1
- package/dist/scheduler/taskWake.js +5 -10
- package/dist/scheduler/wakeReason.js +2 -0
- package/dist/scheduler/wakeupQueue.js +2 -4
- package/dist/setup/setupCommand.js +1 -1
- package/dist/storage/contextRecords.js +106 -0
- package/dist/storage/currentTaskStore.js +1 -1
- package/dist/storage/homeLayout.js +13 -17
- package/dist/storage/migrations/agentFailureContext.js +22 -0
- package/dist/storage/migrations/currentInputContract.js +86 -0
- package/dist/storage/migrations/currentRuntimeContract.js +228 -0
- package/dist/storage/migrations/historicalVerificationPlan.js +35 -0
- package/dist/storage/migrations/integrationContinuation.js +5 -4
- package/dist/storage/migrations/narrowAgentFailureContext.js +65 -0
- package/dist/storage/migrations/notificationOnlyWakes.js +74 -0
- package/dist/storage/migrations/verificationPlanV1.js +162 -0
- package/dist/storage/migrations/verificationPolicy.js +74 -0
- package/dist/storage/migrations/workItemHistory.js +46 -0
- package/dist/storage/persistenceWorker.js +12 -4
- package/dist/storage/recordValidation.js +87 -0
- package/dist/storage/sqliteSchema.js +142 -1
- package/dist/storage/sqliteStore.js +156 -162
- package/dist/storage/storageSchema.js +2 -14
- package/dist/storage/storageVersions.js +1 -1
- package/dist/storage/storeRpc.js +15 -7
- package/dist/storage/taskStore.js +3 -7
- package/dist/storage/upgrade/upgradeOrchestrator.js +25 -37
- package/dist/task/completionReadiness.js +5 -24
- package/dist/task/draftPlan.js +0 -53
- package/dist/task/nextAction.js +7 -13
- package/dist/task/remoteDeliveryService.js +89 -0
- package/dist/task/taskActivation.js +2 -25
- package/dist/task/taskActivationService.js +0 -2
- package/dist/task/taskRecordReference.js +0 -1
- package/dist/task/taskSubmission.js +3 -14
- package/dist/telemetry/sqliteTelemetryBatch.js +29 -0
- package/dist/telemetry/sqliteTelemetryStore.js +49 -49
- package/dist/telemetry/telemetryWiring.js +4 -3
- package/dist/tmux/tmuxManager.js +29 -20
- package/dist/verification/gateArtifact.js +15 -24
- package/dist/verification/gateArtifactStore.js +14 -7
- package/dist/verification/verificationGateService.js +29 -88
- package/dist/verification/verificationPlan.js +27 -72
- package/dist/web/assets/client/app.js +1 -1
- package/dist/web/assets/client/taskSurface.js +4 -4
- package/dist/web/webServer.js +4 -6
- package/dist/web/webSnapshot.js +3 -83
- package/dist/web/webTaskSurface.js +17 -46
- package/dist/workItem/workItem.js +1 -12
- package/docs/architecture/capabilities-and-resources.md +14 -2
- package/docs/architecture/capabilities-and-resources.zh-CN.md +11 -1
- package/docs/managed-turn-and-session-runtime.md +83 -10
- package/docs/managed-turn-and-session-runtime.zh-CN.md +65 -11
- package/docs/plugin-sdk.md +4 -2
- package/docs/provider-runtime.md +3 -1
- package/docs/provider-runtime.zh-CN.md +4 -2
- package/docs/release-workflow.md +190 -7
- package/docs/release-workflow.zh-CN.md +139 -5
- package/docs/roles-and-configuration.md +29 -0
- package/docs/roles-and-configuration.zh-CN.md +21 -0
- package/docs/sqlite-control-plane-design.md +16 -3
- package/docs/sqlite-control-plane-design.zh-CN.md +13 -2
- package/docs/task-dag-semantics.md +3 -3
- package/docs/task-dag-semantics.zh-CN.md +2 -2
- package/docs/task-delivery.md +91 -5
- package/docs/task-delivery.zh-CN.md +72 -4
- package/docs/task-discovery.md +10 -11
- package/docs/task-discovery.zh-CN.md +8 -9
- package/docs/testing/verification-levels.md +145 -9
- package/docs/testing/verification-levels.zh-CN.md +103 -8
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +5 -0
- package/skills/yui-leader/references/integration.md +9 -5
- package/skills/yui-leader/references/planning.md +9 -3
- package/skills/yui-operator/SKILL.md +15 -10
- package/skills/yui-runtime/SKILL.md +6 -6
- package/skills/yui-runtime/references/recovery.md +47 -0
- package/dist/agent/agentRegistry.js +0 -10
- package/dist/agentRun/runIdentity.js +0 -22
- package/dist/commands/deliveryGuardPreflight.js +0 -30
- package/dist/commands/taskIntegrationQueueCommands.js +0 -226
- package/dist/commands/taskOverviewCommand.js +0 -377
- package/dist/completion/completionWizard.js +0 -125
- package/dist/context/dispatchContext.js +0 -110
- package/dist/context/wakeNotification.js +0 -144
- package/dist/integration/integrationCheckEvidenceReuse.js +0 -53
- package/dist/integration/integrationQueueEntry.js +0 -191
- package/dist/integration/integrationQueueService.js +0 -810
- package/dist/release/fakeReleasePorts.js +0 -55
- package/dist/runtime/sessionOwnerRegistry.js +0 -137
- package/dist/task/deliveryGuard.js +0 -226
- /package/dist/{commands/taskActor.js → task/taskAuthority.js} +0 -0
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
2
|
import { chmodSync, mkdirSync, rmSync } from "node:fs";
|
|
3
|
-
import { tmpdir, homedir } from "node:os";
|
|
4
|
-
import { dirname, join, resolve } from "node:path";
|
|
5
3
|
import { createConnection, createServer } from "node:net";
|
|
4
|
+
import { homedir, tmpdir } from "node:os";
|
|
5
|
+
import { dirname, join, resolve } from "node:path";
|
|
6
6
|
import { createInterface } from "node:readline";
|
|
7
7
|
import { withSessionContextPointer } from "../context/sessionBootstrapManifest.js";
|
|
8
|
+
import { publishStructuredConversationRecoverability, publishStructuredProviderAccepted, publishStructuredProviderActivity, publishStructuredProviderAttachmentExit, publishStructuredProviderConnection, publishStructuredProviderGoal, publishStructuredProviderInputObserved, publishStructuredProviderInputSettlement, publishStructuredProviderOpened, publishStructuredProviderStarted, publishStructuredProviderTerminal, structuredProviderEventDelivery } from "../controller/structuredProviderObservation.js";
|
|
8
9
|
import { callController, controllerCallMayHaveApplied, ControllerClientError } from "../core/controllerClient.js";
|
|
9
10
|
import { readHomeFilesystemId } from "../core/homeFilesystemIdentity.js";
|
|
11
|
+
import { FILE_TASK_CONTROLLER_PROTOCOL_VERSION } from "../core/protocol.js";
|
|
10
12
|
import { isForeignHandoverLockHeld } from "../release/runtimeRelease.js";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { ProviderDeliveryUnknownError, ProviderConversationMissingError, ProviderTurnBusyError, ProviderTurnRejectedError } from "./structuredProviderHost.js";
|
|
13
|
+
import { yuiTmuxServerName, yuiTmuxSessionName } from "../tmux/tmuxManager.js";
|
|
14
|
+
import { tmuxSocketDirectory } from "../tmux/tmuxSocketEndpoint.js";
|
|
14
15
|
import { createAgentEndpointOwner } from "./agentEndpointOwnership.js";
|
|
15
|
-
import {
|
|
16
|
+
import { providerDeliveryFailure, providerDeliveryFailureFrom, redactAgentErrorText, serializeAgentErrorRaw } from "./agentError.js";
|
|
17
|
+
import { AGENT_HOST_CONTROL_PROTOCOL, AGENT_HOST_EVENT_PROTOCOL } from "./agentHostProtocol.js";
|
|
18
|
+
import { readAgentRunConfigurationObservation, unknownAgentRunConfiguration } from "./agentRunConfiguration.js";
|
|
19
|
+
import { CodexPreSubmissionError } from "./codexAppServerRuntime.js";
|
|
20
|
+
import { runCodexInteractiveHost } from "./codexInteractiveHost.js";
|
|
21
|
+
import { validateAgentHostLaunchPayload } from "./launchBroker.js";
|
|
16
22
|
import { validateRuntimeProcessExitObservation } from "./processExitObservation.js";
|
|
17
23
|
import { persistRuntimeProcessExitObservation, replayRuntimeProcessExitOutbox } from "./processExitOutbox.js";
|
|
24
|
+
import { sameProviderAuthorityFence, validateProviderAuthorityFence } from "./providerAuthorityFence.js";
|
|
25
|
+
import { ProviderConversationMissingError, ProviderDeliveryUnknownError, ProviderTurnBusyError, ProviderTurnRejectedError } from "./providerErrors.js";
|
|
18
26
|
import { AGENT_HOST_CLIENT_EXIT_GRACE_MS, AGENT_HOST_CONTROL_TIMEOUT_MS, AGENT_HOST_READY_TIMEOUT_MS, ENDPOINT_DRAIN_TIMEOUT_MS, PROVIDER_ACCEPT_TIMEOUT_MS } from "./runtimeDeadlines.js";
|
|
19
|
-
import { providerDeliveryFailure, providerDeliveryFailureFrom, redactAgentErrorText, serializeAgentErrorRaw } from "./agentError.js";
|
|
20
|
-
import { runCodexInteractiveHost } from "./codexInteractiveHost.js";
|
|
21
|
-
import { CodexPreSubmissionError } from "./codexAppServerRuntime.js";
|
|
22
|
-
import { readAgentRunConfigurationObservation, unknownAgentRunConfiguration } from "./agentRunConfiguration.js";
|
|
23
27
|
import { createSessionOwnerIdentity, readLinuxProcessIdentity } from "./sessionOwnerIdentity.js";
|
|
24
|
-
import { yuiTmuxServerName, yuiTmuxSessionName } from "../tmux/tmuxManager.js";
|
|
25
|
-
import { tmuxSocketDirectory } from "../tmux/tmuxSocketEndpoint.js";
|
|
26
|
-
import { AGENT_HOST_CONTROL_PROTOCOL, AGENT_HOST_EVENT_PROTOCOL } from "./agentHostProtocol.js";
|
|
27
|
-
import { FILE_TASK_CONTROLLER_PROTOCOL_VERSION } from "../core/protocol.js";
|
|
28
28
|
export { AGENT_HOST_CONTROL_PROTOCOL } from "./agentHostProtocol.js";
|
|
29
29
|
const HOST_CONTROL_MAX_BYTES = 32 * 1024;
|
|
30
30
|
const CODEX_CLIENT_STABLE_MS = 5_000;
|
|
@@ -77,7 +77,7 @@ export async function runAgentHost(input) {
|
|
|
77
77
|
if (payload.environment.YUI_SESSION_SCOPE === "global"
|
|
78
78
|
&& payload.environment.YUI_ADAPTER_ID === "codex"
|
|
79
79
|
&& payload.providerControl === undefined) {
|
|
80
|
-
return runCodexInteractiveHost(input.home, payload);
|
|
80
|
+
return runCodexInteractiveHost(input.home, payload, openAgentHostControl);
|
|
81
81
|
}
|
|
82
82
|
let session;
|
|
83
83
|
// This process really holds the Endpoint code its Session runs on. The lease
|
|
@@ -2,7 +2,7 @@ import { spawn } from "node:child_process";
|
|
|
2
2
|
import { randomBytes } from "node:crypto";
|
|
3
3
|
import { once } from "node:events";
|
|
4
4
|
import WebSocket, { WebSocketServer } from "ws";
|
|
5
|
-
import { AGENT_HOST_CONTROL_PROTOCOL
|
|
5
|
+
import { AGENT_HOST_CONTROL_PROTOCOL } from "./agentHostProtocol.js";
|
|
6
6
|
import { openCodexInteractiveConnection } from "./structuredProviderHost.js";
|
|
7
7
|
/**
|
|
8
8
|
* Keep the native TUI and its transparent App Server attachment in one pane.
|
|
@@ -13,7 +13,7 @@ import { openCodexInteractiveConnection } from "./structuredProviderHost.js";
|
|
|
13
13
|
* until its first message. Observing the TUI's own startup avoids creating a
|
|
14
14
|
* second Thread or manufacturing a bootstrap message to materialize history.
|
|
15
15
|
*/
|
|
16
|
-
export async function runCodexInteractiveHost(home, payload) {
|
|
16
|
+
export async function runCodexInteractiveHost(home, payload, openAgentHostControl) {
|
|
17
17
|
const environment = payload.environment;
|
|
18
18
|
if (environment.YUI_SESSION_SCOPE !== "global" || environment.YUI_ADAPTER_ID !== "codex"
|
|
19
19
|
|| payload.providerControl !== undefined) {
|
package/dist/runtime/index.js
CHANGED
|
@@ -9,7 +9,6 @@ export { promptPushOutcome, RuntimeHostContentionError, RuntimeHostUnavailableEr
|
|
|
9
9
|
export { AgentHostPromptPushAdapter, TmuxSessionHost } from "./tmuxAdapters.js";
|
|
10
10
|
export { FileTaskRuntimeIsolation, YUI_TASK_RUNTIME_ISOLATION_DESCRIPTOR, YUI_TASK_RUNTIME_SERVICE_NAMESPACE, assertTaskRuntimeIsolationPreflight, createTaskRuntimeIsolationDescriptor, parseTaskRuntimeIsolationDescriptor, planTaskRuntimeCleanup, taskRuntimeIsolationEnvironment, taskRuntimeIsolationFingerprint } from "./taskRuntimeIsolation.js";
|
|
11
11
|
export { createSessionOwnerIdentity, isLinuxProcessLive, listOwnedProcessTree, readLinuxProcessIdentity } from "./sessionOwnerIdentity.js";
|
|
12
|
-
export { FileSessionOwnerRegistry } from "./sessionOwnerRegistry.js";
|
|
13
12
|
export { formatRuntimeLaunchDiagnostic, redactLaunchArgument, redactLaunchText, RuntimeLaunchFailure, toRuntimeLaunchFailure } from "./launchDiagnostics.js";
|
|
14
13
|
export { DEFAULT_FORCED_GRACE_MS, DEFAULT_GRACEFUL_GRACE_MS, terminateSessionOwners } from "./sessionTerminationGuard.js";
|
|
15
14
|
export { ProviderContinuationReconciliationService } from "./providerContinuationReconciliationService.js";
|
|
@@ -2,6 +2,26 @@ import { activeRoleAgentBinding } from "../role/role.js";
|
|
|
2
2
|
import { currentProviderConversation } from "./providerRuntimeIdentity.js";
|
|
3
3
|
/** Native Session identity supplied by the Agent transport. */
|
|
4
4
|
export const MANAGED_NATIVE_SESSION_ENV = "YUI_NATIVE_SESSION_ID";
|
|
5
|
+
/** Global writes use the same command-time native identity as Task writes.
|
|
6
|
+
* A Manifest locates context; it is not continuing mutation authority. */
|
|
7
|
+
export function requireManagedGlobalCaller(store, env) {
|
|
8
|
+
const name = identity(env.YUI_ROLE);
|
|
9
|
+
const role = name === undefined ? null : store.getGlobalRole(name);
|
|
10
|
+
const binding = role?.agentBindings[role.activeAgentId];
|
|
11
|
+
const set = name === undefined ? null : store.getGlobalRoleSessionSet(name);
|
|
12
|
+
const session = set?.sessions[set.activeAgentId];
|
|
13
|
+
const nativeSessionId = identity(binding?.adapterId === "codex"
|
|
14
|
+
? env.CODEX_THREAD_ID ?? env.YUI_NATIVE_SESSION_ID : env.YUI_NATIVE_SESSION_ID);
|
|
15
|
+
if (env.YUI_SESSION_SCOPE !== "global" || env.YUI_TASK_ID !== undefined
|
|
16
|
+
|| !role || !binding || !set || !session || session.status !== "active"
|
|
17
|
+
|| set.activeAgentId !== role.activeAgentId || session.agentId !== binding.agentId
|
|
18
|
+
|| session.adapterId !== binding.adapterId || nativeSessionId !== session.nativeSessionId
|
|
19
|
+
|| (env.YUI_AGENT_ID !== undefined && env.YUI_AGENT_ID !== session.agentId)
|
|
20
|
+
|| (env.YUI_ADAPTER_ID !== undefined && env.YUI_ADAPTER_ID !== session.adapterId)) {
|
|
21
|
+
throw new ManagedRuntimeDriftError("This command requires the current managed global native Session; the previous Session has no write authority.");
|
|
22
|
+
}
|
|
23
|
+
return { roleName: role.name, agentId: session.agentId, adapterId: session.adapterId, nativeSessionId };
|
|
24
|
+
}
|
|
5
25
|
/**
|
|
6
26
|
* A managed Session presented valid self-identity but is no longer the current
|
|
7
27
|
* runtime of its Task Role. This is a bounded diagnosis rather than a bare
|
|
@@ -119,7 +139,7 @@ function requireCurrentRuntime(store, self) {
|
|
|
119
139
|
throw new ManagedRuntimeDriftError(`This managed Session carries no native session id, so it cannot be recognized `
|
|
120
140
|
+ `as the current runtime of ${self.taskId}/${self.roleName}.`);
|
|
121
141
|
}
|
|
122
|
-
if (role.name === "leader" && store.
|
|
142
|
+
if (role.name === "leader" && store.listEventsByType(self.taskId, ["role.agent-bound"]).some((event) => event.type === "role.agent-bound" && event.payload.role === role.name
|
|
123
143
|
&& event.payload.revokedNativeSessionId === self.nativeSessionId)) {
|
|
124
144
|
throw new ManagedRuntimeDriftError("This Leader native Session's management authority was explicitly revoked.");
|
|
125
145
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export class ProviderDeliveryUnknownError extends Error {
|
|
2
|
+
attemptId;
|
|
3
|
+
name = "ProviderDeliveryUnknownError";
|
|
4
|
+
constructor(message, attemptId,
|
|
5
|
+
// Wrapping must not become the end of the causal chain: the original
|
|
6
|
+
// transport or Controller failure is the reason a reader needs.
|
|
7
|
+
options) {
|
|
8
|
+
super(message, options);
|
|
9
|
+
this.attemptId = attemptId;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export class ProviderTurnRejectedError extends Error {
|
|
13
|
+
attemptId;
|
|
14
|
+
name = "ProviderTurnRejectedError";
|
|
15
|
+
constructor(message, attemptId, options) {
|
|
16
|
+
super(message, options);
|
|
17
|
+
this.attemptId = attemptId;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** Another ordinary client currently owns the thread's active Turn. */
|
|
21
|
+
export class ProviderTurnBusyError extends Error {
|
|
22
|
+
attemptId;
|
|
23
|
+
activeTurnId;
|
|
24
|
+
name = "ProviderTurnBusyError";
|
|
25
|
+
constructor(message, attemptId, activeTurnId) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.attemptId = attemptId;
|
|
28
|
+
this.activeTurnId = activeTurnId;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export class ProviderConversationMissingError extends Error {
|
|
32
|
+
conversationId;
|
|
33
|
+
name = "ProviderConversationMissingError";
|
|
34
|
+
constructor(conversationId, message) {
|
|
35
|
+
super(message);
|
|
36
|
+
this.conversationId = conversationId;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -547,11 +547,6 @@ function requireTimestamp(value, label) {
|
|
|
547
547
|
throw new Error(`${label} is invalid.`);
|
|
548
548
|
return timestamp;
|
|
549
549
|
}
|
|
550
|
-
function requireNonNegativeInteger(value, minimum, label) {
|
|
551
|
-
if (!Number.isSafeInteger(value) || value < minimum)
|
|
552
|
-
throw new Error(`${label} is invalid.`);
|
|
553
|
-
return value;
|
|
554
|
-
}
|
|
555
550
|
function requireIdentity(value, label) {
|
|
556
551
|
const identity = requireText(value, label);
|
|
557
552
|
if (identity.includes("/../") || identity === "__proto__")
|
|
@@ -18,11 +18,10 @@ export function projectRuntimeSessionCandidate(sessions) {
|
|
|
18
18
|
sessionUpdatedAt: active.updatedAt
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
|
-
/** Deterministic owner order
|
|
21
|
+
/** Deterministic owner order for current runtime discovery. */
|
|
22
22
|
export function compareRuntimeSessionCandidates(left, right) {
|
|
23
23
|
if (left.owner.scope !== right.owner.scope) {
|
|
24
|
-
//
|
|
25
|
-
// bounded global Role set.
|
|
24
|
+
// Task owners precede the bounded global Role set.
|
|
26
25
|
return left.owner.scope === "task" ? -1 : 1;
|
|
27
26
|
}
|
|
28
27
|
if (left.owner.scope === "task" && right.owner.scope === "task") {
|
|
@@ -17,7 +17,7 @@ export function createSessionOwnerIdentity(input) {
|
|
|
17
17
|
throw new TypeError("Global session owner must not carry a task id.");
|
|
18
18
|
}
|
|
19
19
|
const providerRoot = input.providerRoot;
|
|
20
|
-
if (!["
|
|
20
|
+
if (!["pane-pid", "owned-child"].includes(providerRoot.attribution)) {
|
|
21
21
|
throw new TypeError("Session owner process attribution is invalid.");
|
|
22
22
|
}
|
|
23
23
|
if (!Number.isSafeInteger(providerRoot.pid) || providerRoot.pid <= 0) {
|
|
@@ -2,13 +2,14 @@ import { spawn } from "node:child_process";
|
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { Duplex } from "node:stream";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { ProviderConversationMissingError, ProviderDeliveryUnknownError, ProviderTurnBusyError, ProviderTurnRejectedError } from "./providerErrors.js";
|
|
5
6
|
import WebSocket from "ws";
|
|
6
|
-
import {
|
|
7
|
-
import { serializeAgentErrorRaw } from "./agentError.js";
|
|
7
|
+
import { YUI_VERSION } from "../version.js";
|
|
8
8
|
import { AcpStructuredProviderSession } from "./acpSession.js";
|
|
9
9
|
import { acpDesiredSessionConfiguration } from "./acpSessionConfiguration.js";
|
|
10
|
+
import { serializeAgentErrorRaw } from "./agentError.js";
|
|
10
11
|
import { unsupportedAgentRunConfiguration } from "./agentRunConfiguration.js";
|
|
11
|
-
import {
|
|
12
|
+
import { codexAppServerErrorIsMissing, CodexAppServerRequestError, CodexAppServerRuntime, codexClientInitialization, codexGoalNotification, codexTurnInput, codexTurnOutput } from "./codexAppServerRuntime.js";
|
|
12
13
|
import { JsonLineChannel, PROVIDER_MESSAGE_MAX_BYTES, terminateProcessGroup } from "./jsonLineChannel.js";
|
|
13
14
|
import { PROVIDER_ACCEPT_TIMEOUT_MS } from "./runtimeDeadlines.js";
|
|
14
15
|
const CODEX_PROXY_HANDSHAKE_TIMEOUT_MS = 10_000;
|
|
@@ -18,44 +19,6 @@ const CODEX_PROXY_HANDSHAKE_TIMEOUT_MS = 10_000;
|
|
|
18
19
|
*/
|
|
19
20
|
const CODEX_RUN_CONFIGURATION = unsupportedAgentRunConfiguration("The Codex app-server protocol");
|
|
20
21
|
const CLAUDE_RUN_CONFIGURATION = unsupportedAgentRunConfiguration("Claude Code's stream-json interface");
|
|
21
|
-
export class ProviderDeliveryUnknownError extends Error {
|
|
22
|
-
attemptId;
|
|
23
|
-
name = "ProviderDeliveryUnknownError";
|
|
24
|
-
constructor(message, attemptId,
|
|
25
|
-
// Wrapping must not become the end of the causal chain: the original
|
|
26
|
-
// transport or Controller failure is the reason a reader needs.
|
|
27
|
-
options) {
|
|
28
|
-
super(message, options);
|
|
29
|
-
this.attemptId = attemptId;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
export class ProviderTurnRejectedError extends Error {
|
|
33
|
-
attemptId;
|
|
34
|
-
name = "ProviderTurnRejectedError";
|
|
35
|
-
constructor(message, attemptId, options) {
|
|
36
|
-
super(message, options);
|
|
37
|
-
this.attemptId = attemptId;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
/** Another ordinary client currently owns the thread's active Turn. */
|
|
41
|
-
export class ProviderTurnBusyError extends Error {
|
|
42
|
-
attemptId;
|
|
43
|
-
activeTurnId;
|
|
44
|
-
name = "ProviderTurnBusyError";
|
|
45
|
-
constructor(message, attemptId, activeTurnId) {
|
|
46
|
-
super(message);
|
|
47
|
-
this.attemptId = attemptId;
|
|
48
|
-
this.activeTurnId = activeTurnId;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
export class ProviderConversationMissingError extends Error {
|
|
52
|
-
conversationId;
|
|
53
|
-
name = "ProviderConversationMissingError";
|
|
54
|
-
constructor(conversationId, message) {
|
|
55
|
-
super(message);
|
|
56
|
-
this.conversationId = conversationId;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
22
|
export async function startStructuredProviderSession(payload, input = {}) {
|
|
60
23
|
const control = payload.providerControl;
|
|
61
24
|
if (control === undefined) {
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { fileURLToPath } from "node:url";
|
|
3
2
|
import { resolve } from "node:path";
|
|
4
|
-
import {
|
|
5
|
-
import { normalizeRuntimeOwner } from "./runtimeOwner.js";
|
|
6
|
-
import { RuntimeHostContentionError, RuntimeHostUnavailableError, promptPushOutcome } from "./ports.js";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
7
4
|
import { providerDeliveryFailureFrom } from "./agentError.js";
|
|
5
|
+
import { AGENT_HOST_CONTROL_PROTOCOL, sendAgentHostLaunchControl, sendAgentHostRunControl, sendAgentHostSteerControl, waitForAgentHostLaunchAck } from "./agentHost.js";
|
|
6
|
+
import { launchBrokerForHome } from "./launchBroker.js";
|
|
8
7
|
import { toRuntimeLaunchFailure } from "./launchDiagnostics.js";
|
|
8
|
+
import { RuntimeHostContentionError, RuntimeHostUnavailableError, promptPushOutcome } from "./ports.js";
|
|
9
|
+
import { createRuntimeBinding } from "./runtimeBinding.js";
|
|
10
|
+
import { normalizeRuntimeOwner } from "./runtimeOwner.js";
|
|
9
11
|
import { requireSafeIdentity } from "./validation.js";
|
|
10
|
-
import { launchBrokerForHome } from "./launchBroker.js";
|
|
11
|
-
import { AGENT_HOST_CONTROL_PROTOCOL, sendAgentHostLaunchControl, sendAgentHostRunControl, sendAgentHostSteerControl, waitForAgentHostLaunchAck } from "./agentHost.js";
|
|
12
12
|
const DEFAULT_INACTIVITY_TIMEOUT_MS = 300_000;
|
|
13
13
|
/**
|
|
14
14
|
* Runtime lifecycle adapter for the current tmux host. The returned hostRef is
|
|
@@ -656,8 +656,6 @@ async function killRole(tmux, hostId, roleName) {
|
|
|
656
656
|
await tmux.killRoleAsync(hostId, roleName);
|
|
657
657
|
}
|
|
658
658
|
async function stopExactRole(tmux, hostId, roleName) {
|
|
659
|
-
if (await probeRoleStatus(tmux, hostId, roleName) !== "running")
|
|
660
|
-
return;
|
|
661
659
|
try {
|
|
662
660
|
await killRole(tmux, hostId, roleName);
|
|
663
661
|
}
|
|
@@ -25,7 +25,7 @@ export async function processActiveRoleRunDeliveries(store, delivery, now, selec
|
|
|
25
25
|
for (const task of selectedActiveSchedulerTasks(store, selection, {
|
|
26
26
|
includePlanningDrafts: true
|
|
27
27
|
})) {
|
|
28
|
-
store.prepareMessageContinuations
|
|
28
|
+
store.prepareMessageContinuations(task.id, now);
|
|
29
29
|
for (const role of selectedSchedulerRoles(store, task.id, selection)) {
|
|
30
30
|
const run = store.getActiveRun(task.id, role.name);
|
|
31
31
|
if (run === null)
|
|
@@ -49,7 +49,7 @@ async function deliverActiveRun(store, delivery, task, role, run, now) {
|
|
|
49
49
|
roleName: role.name,
|
|
50
50
|
runId: run.id
|
|
51
51
|
});
|
|
52
|
-
const sessionSet = store.getTaskRoleSessionSet
|
|
52
|
+
const sessionSet = store.getTaskRoleSessionSet(task.id, role.name);
|
|
53
53
|
const binding = sessionSet?.providerBinding ?? null;
|
|
54
54
|
if (binding?.retry !== undefined && (binding.retry.successorRunId === run.id
|
|
55
55
|
|| binding.retry.successorReviewRoundId !== undefined && binding.retry.successorReviewRoundId === run.reviewRoundId)
|
|
@@ -97,7 +97,7 @@ async function deliverActiveRun(store, delivery, task, role, run, now) {
|
|
|
97
97
|
// report. Keep the exact input fenced; never submit it again.
|
|
98
98
|
return { ...base, status: "skipped", reason: "delivery-uncertain", error: reason };
|
|
99
99
|
}
|
|
100
|
-
const lastSubmitError =
|
|
100
|
+
const lastSubmitError = store.listEvents(task.id).filter((event) => event.type === "runtime.agent-error" && event.payload.runId === run.id
|
|
101
101
|
&& event.payload.roleName === role.name && event.payload.phase === "turn-submit").at(-1);
|
|
102
102
|
if (currentProviderTurn === null && lastSubmitError?.payload.inputDisposition === "unknown") {
|
|
103
103
|
return { ...base, status: "skipped", reason: "delivery-uncertain", error: lastSubmitError.payload.message };
|
|
@@ -114,7 +114,7 @@ async function deliverActiveRun(store, delivery, task, role, run, now) {
|
|
|
114
114
|
// The first attempted admission may already have opened this fixed native
|
|
115
115
|
// Session. A busy retry resumes it; it does not repeat the original launch.
|
|
116
116
|
const preparedHere = existingSession?.nativeSessionId !== undefined
|
|
117
|
-
&&
|
|
117
|
+
&& store.listEvents(task.id).some((event) => event.type === "run.session-prepared"
|
|
118
118
|
&& event.payload.runId === run.id && event.payload.nativeSessionId === existingSession.nativeSessionId);
|
|
119
119
|
const mode = (currentProviderTurn?.status === "deferred" || preparedHere) && existingSession?.nativeSessionId !== undefined
|
|
120
120
|
? "resume" : run.mode;
|
|
@@ -183,7 +183,7 @@ async function deliverActiveRun(store, delivery, task, role, run, now) {
|
|
|
183
183
|
}
|
|
184
184
|
if (outcome.status === "busy" || outcome.status === "unavailable") {
|
|
185
185
|
if (outcome.status === "busy" && outcome.failure?.inputDisposition === "not-accepted") {
|
|
186
|
-
store.recordAgentError
|
|
186
|
+
store.recordAgentError({ taskId: task.id, roleName: role.name, runId: run.id,
|
|
187
187
|
source: "host", phase: "turn-submit", message: outcome.failure.detail,
|
|
188
188
|
raw: outcome.failure.raw ?? serializeAgentErrorRaw(outcome.failure),
|
|
189
189
|
inputDisposition: "not-accepted", ...providerDeliveryFailureFacts(outcome.failure),
|
|
@@ -208,7 +208,7 @@ async function deliverActiveRun(store, delivery, task, role, run, now) {
|
|
|
208
208
|
: formatProviderDeliveryFailure(failure);
|
|
209
209
|
// This path is the common Provider write failure and previously left no
|
|
210
210
|
// durable fact at all, so the cause was unrecoverable after the fact.
|
|
211
|
-
store.recordAgentError
|
|
211
|
+
store.recordAgentError({
|
|
212
212
|
taskId: task.id,
|
|
213
213
|
roleName: role.name,
|
|
214
214
|
runId: run.id,
|
|
@@ -238,7 +238,7 @@ async function deliverActiveRun(store, delivery, task, role, run, now) {
|
|
|
238
238
|
const message = error instanceof Error ? error.message : String(error);
|
|
239
239
|
// Preserve the structured cause alongside the readable diagnosis.
|
|
240
240
|
const causeName = innermostCauseName(error);
|
|
241
|
-
store.recordAgentError
|
|
241
|
+
store.recordAgentError({
|
|
242
242
|
taskId: task.id,
|
|
243
243
|
roleName: role.name,
|
|
244
244
|
runId: run.id,
|
|
@@ -4,6 +4,9 @@ import { isSchedulerTaskWorkspaceReady } from "./ports.js";
|
|
|
4
4
|
import { taskOwnsManagedWorkspace } from "../task/task.js";
|
|
5
5
|
import { hasImmediateWakeReason } from "./wakeReason.js";
|
|
6
6
|
import { providerRetryPending } from "../runtime/providerRetry.js";
|
|
7
|
+
import { RuntimeLaunchError } from "../runtime/ports.js";
|
|
8
|
+
import { RuntimeLifecycleBusyError } from "../runtime/lifecycleReservation.js";
|
|
9
|
+
import { redactAgentErrorText } from "../runtime/agentError.js";
|
|
7
10
|
export const LEADER_WAKE_AGGREGATION_MS = 60_000;
|
|
8
11
|
/** Deliver a durable mailbox notification, not an implicit execution assignment.
|
|
9
12
|
* Acceptance settles only its claimed batch; no Agent report is required.
|
|
@@ -29,11 +32,11 @@ export async function processLeaderWakeups(store, delivery, now, selection) {
|
|
|
29
32
|
results.push({ ...base, status: "skipped", reason: "aggregating" });
|
|
30
33
|
continue;
|
|
31
34
|
}
|
|
32
|
-
if (task.status === "draft" && store.prepareDraftPlanning
|
|
35
|
+
if (task.status === "draft" && store.prepareDraftPlanning(task.id, now)) {
|
|
33
36
|
results.push({ ...base, status: "skipped", reason: "not-ready" });
|
|
34
37
|
continue;
|
|
35
38
|
}
|
|
36
|
-
const sessions = store.getTaskRoleSessionSet
|
|
39
|
+
const sessions = store.getTaskRoleSessionSet(task.id, role.name);
|
|
37
40
|
const provider = sessions?.providerBinding;
|
|
38
41
|
if (providerRetryPending(provider)) {
|
|
39
42
|
results.push({ ...base, status: "skipped", reason: "not-ready" });
|
|
@@ -55,13 +58,17 @@ export async function processLeaderWakeups(store, delivery, now, selection) {
|
|
|
55
58
|
...(notification.disposition === "unknown" ? {
|
|
56
59
|
error: `Notification acceptance is unknown; the fixed wake is retained and will not be replayed. `
|
|
57
60
|
+ `After establishing native quiescence, release only this claim with yui task wake resolve ${task.id} ${notification.wakeId} --reason <evidence>.`
|
|
61
|
+
} : notification.disposition === "rejected" ? {
|
|
62
|
+
error: `Notification was rejected; inspect yui task wake show ${task.id} ${notification.wakeId}. `
|
|
63
|
+
+ `After correcting the cause, retry with yui task wake retry ${task.id} ${notification.wakeId} --reason <correction>.`
|
|
58
64
|
} : {}) });
|
|
59
65
|
continue;
|
|
60
66
|
}
|
|
61
67
|
let attempted = false;
|
|
68
|
+
let effective = role.effective;
|
|
62
69
|
try {
|
|
63
70
|
const session = store.getRoleSession(task.id, role.name, role.effective.agentId);
|
|
64
|
-
|
|
71
|
+
effective = session?.status === "active" ? session.effective : role.effective;
|
|
65
72
|
if (session?.status === "active" && !roleSessionMayContinue(session.effective, role.effective)) {
|
|
66
73
|
throw new Error("Leader Session configuration changed; explicitly apply it before notification delivery.");
|
|
67
74
|
}
|
|
@@ -96,12 +103,18 @@ export async function processLeaderWakeups(store, delivery, now, selection) {
|
|
|
96
103
|
: outcome.status === "rejected" ? "rejected"
|
|
97
104
|
: outcome.status === "pending" ? null : "deferred";
|
|
98
105
|
if (disposition !== null)
|
|
99
|
-
store.settleLeaderNotification(task.id, notification.attemptId, disposition, now, outcome.failure?.detail
|
|
106
|
+
store.settleLeaderNotification(task.id, notification.attemptId, disposition, now, outcome.failure?.detail, { effective, raw: outcome.failure?.raw ?? outcome.failure?.detail ?? `Notification ${disposition}.`,
|
|
107
|
+
phase: "turn-submit" });
|
|
100
108
|
results.push({ ...base, status: accepted ? "dispatched" : "skipped", reason: accepted ? undefined : "not-ready" });
|
|
101
109
|
}
|
|
102
110
|
catch (error) {
|
|
103
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
104
|
-
|
|
111
|
+
const detail = redactAgentErrorText(error instanceof Error ? error.message : String(error));
|
|
112
|
+
// Match explicit AgentRun admission: only positive, typed backpressure
|
|
113
|
+
// permits another automatic launch. A config/auth/executable failure
|
|
114
|
+
// needs correction; an exception after submit cannot authorize replay.
|
|
115
|
+
const retryable = error instanceof RuntimeLifecycleBusyError
|
|
116
|
+
|| (error instanceof RuntimeLaunchError && error.retryable);
|
|
117
|
+
store.settleLeaderNotification(task.id, notification.attemptId, attempted ? "unknown" : retryable ? "deferred" : "rejected", now, detail, { effective, raw: detail, phase: attempted ? "turn-submit" : "session-start" });
|
|
105
118
|
results.push({ ...base, status: "failed", reason: "not-ready", error: detail });
|
|
106
119
|
}
|
|
107
120
|
finally {
|
|
@@ -1,31 +1,23 @@
|
|
|
1
1
|
import { enqueueWork } from "../coordination/workMailboxQueue.js";
|
|
2
2
|
import { createTaskEvent } from "../event/taskEvent.js";
|
|
3
|
-
import { queueLeaderWakeup } from "./wakeupQueue.js";
|
|
4
3
|
export const LEADER_ATTENTION_REQUIRED_EVENT = "leader.attention-required";
|
|
5
|
-
/**
|
|
6
|
-
export function
|
|
7
|
-
if (store.getTask
|
|
4
|
+
/** One event, one supervisor signal; the Leader wake is this mailbox's projection. */
|
|
5
|
+
export function enqueueSupervisorEvent(store, event, recipient, reason, now) {
|
|
6
|
+
if (store.getTask(event.taskId)?.status === "archived")
|
|
8
7
|
return;
|
|
9
|
-
|
|
8
|
+
const target = recipient === "operator" ? { kind: "operator" }
|
|
9
|
+
: { kind: "role", taskId: event.taskId, roleName: "leader" };
|
|
10
|
+
enqueueWork(store, target, reason, now, [
|
|
10
11
|
{ type: "event", taskId: event.taskId, id: event.id }
|
|
11
|
-
], {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
], { source: "task-event", dedupeKey: `${recipient}-event:${event.taskId}:${event.id}` });
|
|
13
|
+
}
|
|
14
|
+
/** The sole Task-event boundary into the global Operator mailbox. */
|
|
15
|
+
export function enqueueOperatorEvent(store, event, reason, now) {
|
|
16
|
+
enqueueSupervisorEvent(store, event, "operator", reason, now);
|
|
15
17
|
}
|
|
16
18
|
/** Routes one Role fact to its supervisor without exposing Provider details to Operator code. */
|
|
17
19
|
export function routeRoleEvent(store, event, roleName, reason, now) {
|
|
18
|
-
|
|
19
|
-
return;
|
|
20
|
-
if (roleName === "leader") {
|
|
21
|
-
enqueueOperatorEvent(store, event, reason, now);
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
enqueueWork(store, { kind: "role", taskId: event.taskId, roleName: "leader" }, reason, now, [{ type: "event", taskId: event.taskId, id: event.id }], {
|
|
25
|
-
source: "task-event",
|
|
26
|
-
dedupeKey: `leader-event:${event.taskId}:${event.id}`
|
|
27
|
-
});
|
|
28
|
-
queueLeaderWakeup(store, event.taskId, reason, now);
|
|
20
|
+
enqueueSupervisorEvent(store, event, roleName === "leader" ? "operator" : "leader", reason, now);
|
|
29
21
|
}
|
|
30
22
|
/** Records the semantic boundary used when a Leader can no longer continue. */
|
|
31
23
|
export function recordLeaderAttentionRequired(store, input) {
|
|
@@ -26,7 +26,7 @@ export async function processOperatorInputNotifications(store, delivery, selecti
|
|
|
26
26
|
? [{ kind: "input", request }]
|
|
27
27
|
: [];
|
|
28
28
|
}
|
|
29
|
-
if (ref.type !== "event"
|
|
29
|
+
if (ref.type !== "event")
|
|
30
30
|
return [];
|
|
31
31
|
const event = store.listEvents(ref.taskId).find(({ id }) => id === ref.id);
|
|
32
32
|
return event === undefined ? [] : [{ kind: "event", event }];
|
package/dist/scheduler/ports.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { isTaskOwnedWorkspace } from "../worktree/managedWorkspace.js";
|
|
2
1
|
import { taskOwnsManagedWorkspace } from "../task/task.js";
|
|
2
|
+
import { isTaskOwnedWorkspace } from "../worktree/managedWorkspace.js";
|
|
3
3
|
/**
|
|
4
4
|
* Whether the Task's workspace state admits a launch.
|
|
5
5
|
*
|
|
@@ -72,14 +72,11 @@ export function selectedActiveSchedulerTasks(store, selection, options) {
|
|
|
72
72
|
return planningDrafts && hasActivePlanningRun(store, task);
|
|
73
73
|
};
|
|
74
74
|
if (selection === undefined || selection.full) {
|
|
75
|
-
const indexedTaskIds = store.listActiveTaskIds
|
|
76
|
-
if (indexedTaskIds === undefined) {
|
|
77
|
-
return store.listTasks().filter((task) => (admits(task) && !selection?.blockedTaskIds?.has(task.id)));
|
|
78
|
-
}
|
|
75
|
+
const indexedTaskIds = store.listActiveTaskIds();
|
|
79
76
|
// The active index is bounded and authoritative for active Tasks; planning
|
|
80
77
|
// Drafts come from their own bounded index rather than a full-history scan.
|
|
81
78
|
const taskIds = planningDrafts
|
|
82
|
-
? [...indexedTaskIds, ...
|
|
79
|
+
? [...indexedTaskIds, ...store.listPlanningDraftTaskIds()]
|
|
83
80
|
: [...indexedTaskIds];
|
|
84
81
|
const seen = new Set();
|
|
85
82
|
return taskIds.flatMap((taskId) => {
|
|
@@ -106,9 +103,9 @@ export function selectedActiveSchedulerTasks(store, selection, options) {
|
|
|
106
103
|
function hasActivePlanningRun(store, task) {
|
|
107
104
|
if (task.status !== "draft")
|
|
108
105
|
return false;
|
|
109
|
-
const roles = store.listRoles
|
|
106
|
+
const roles = store.listRoles(task.id);
|
|
110
107
|
return roles.some((role) => {
|
|
111
|
-
const run = store.getActiveRun
|
|
108
|
+
const run = store.getActiveRun(task.id, role.name);
|
|
112
109
|
return run !== null
|
|
113
110
|
&& run.status === "active"
|
|
114
111
|
&& isSchedulerPlanningDraft(task, run.purpose);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { selectedSchedulerRoles, selectedActiveSchedulerTasks } from "./ports.js";
|
|
2
|
-
import { formatTaskRecordReference } from "../task/taskRecordReference.js";
|
|
3
1
|
import { runPurposeAdmitsTaskState } from "../agentRun/agentRun.js";
|
|
2
|
+
import { formatTaskRecordReference } from "../task/taskRecordReference.js";
|
|
3
|
+
import { selectedActiveSchedulerTasks, selectedSchedulerRoles } from "./ports.js";
|
|
4
4
|
import { currentRoleRunProgressAt, DEFAULT_WORKFLOW_STALL_CANDIDATE_AGE_MS } from "./roleRunStall.js";
|
|
5
5
|
/**
|
|
6
6
|
* Lightweight liveness only. Pane/process loss is runtime-health evidence,
|
|
@@ -85,7 +85,7 @@ export async function reconcileExitedRoleRuns(store, delivery, now, selection, e
|
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
|
-
for (const { task, role, run, session
|
|
88
|
+
for (const { task, role, run, session } of eligible) {
|
|
89
89
|
const status = batchSnapshot.statuses.get(`${task.id}\0${role.name}`);
|
|
90
90
|
if (status === undefined)
|
|
91
91
|
throw new Error("Role liveness snapshot is incomplete.");
|
|
@@ -93,7 +93,7 @@ export async function reconcileExitedRoleRuns(store, delivery, now, selection, e
|
|
|
93
93
|
continue;
|
|
94
94
|
const hostExit = batchSnapshot.hostExits.get(`${task.id}\0${role.name}`);
|
|
95
95
|
if (hostExit !== undefined) {
|
|
96
|
-
store.saveRoleHostExitObservation
|
|
96
|
+
store.saveRoleHostExitObservation({
|
|
97
97
|
taskId: task.id,
|
|
98
98
|
roleName: role.name,
|
|
99
99
|
runId: run.id,
|