@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
|
@@ -14,6 +14,7 @@ import { acknowledgeUnknownDurableJob, createDurableJob, durableJobIdempotencyKe
|
|
|
14
14
|
import { activeLiveRoleAgentSession } from "../executor/agentExecutor.js";
|
|
15
15
|
import { CallAuthority } from "../kernel/callAuthority.js";
|
|
16
16
|
import { redactLaunchText } from "../runtime/launchDiagnostics.js";
|
|
17
|
+
import { requireManagedTaskCaller } from "../runtime/managedCaller.js";
|
|
17
18
|
export function createDurableJobControl(store) {
|
|
18
19
|
const authority = createJobCallAuthority(store);
|
|
19
20
|
return {
|
|
@@ -158,16 +159,22 @@ function jobAuthorityBinding(store, scope, roleName, taskId) {
|
|
|
158
159
|
// Authenticate the live launch at ingress, but bind accepted Jobs to the
|
|
159
160
|
// caller's durable Session identity, not its disposable Host generation.
|
|
160
161
|
if (scope === "task") {
|
|
161
|
-
const role = store.getRole(taskId, roleName);
|
|
162
162
|
const sessions = store.getTaskRoleSessionSet(taskId, roleName);
|
|
163
163
|
const session = activeLiveRoleAgentSession(sessions);
|
|
164
|
-
|
|
165
|
-
if (hash === null || role === null || sessions?.activeAgentId !== role.activeAgentId
|
|
166
|
-
|| session === null || session.agentId !== role.activeAgentId) {
|
|
164
|
+
if (session === null) {
|
|
167
165
|
throw jobDomainError("Current Job caller Session is unavailable.");
|
|
168
166
|
}
|
|
167
|
+
try {
|
|
168
|
+
requireManagedTaskCaller(store, {
|
|
169
|
+
YUI_SESSION_SCOPE: "task", YUI_TASK_ID: taskId, YUI_ROLE: roleName,
|
|
170
|
+
YUI_NATIVE_SESSION_ID: session.nativeSessionId
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
throw jobDomainError("Job caller binding was revoked; no execution was started.");
|
|
175
|
+
}
|
|
169
176
|
return createHash("sha256").update(JSON.stringify([
|
|
170
|
-
|
|
177
|
+
session.agentId, session.adapterId, session.nativeSessionId
|
|
171
178
|
])).digest("hex");
|
|
172
179
|
}
|
|
173
180
|
const role = store.getGlobalRole(roleName);
|
|
@@ -212,6 +219,12 @@ function assertNonSecretJobInput(params) {
|
|
|
212
219
|
function validateStartParams(store, params) {
|
|
213
220
|
validateJobTarget(store, params);
|
|
214
221
|
assertCallerAuthorized(store, params.caller, params.taskId);
|
|
222
|
+
if (params.caller.scope === "task") {
|
|
223
|
+
const session = store.getTaskRoleSessionSet(params.taskId, params.caller.role);
|
|
224
|
+
if (session?.sessions[session.activeAgentId]?.effective.executionAuthority !== "delivery") {
|
|
225
|
+
throw jobControlError("UNAUTHORIZED", "Managed workspace Jobs require a delivery Session; Task activation does not upgrade planning authority.");
|
|
226
|
+
}
|
|
227
|
+
}
|
|
215
228
|
}
|
|
216
229
|
function validateJobTarget(store, params) {
|
|
217
230
|
// The Task must be active — a terminal Task cannot run jobs.
|
|
@@ -303,69 +316,39 @@ function validateJobTarget(store, params) {
|
|
|
303
316
|
/**
|
|
304
317
|
* rr8/rr12: Bind the declared job owner to the caller's managed identity. The
|
|
305
318
|
* Controller validates the declared owner/workspace and verifies the caller
|
|
306
|
-
* against durable
|
|
319
|
+
* against durable AgentRun/Session state — a self-reported role or scope is never
|
|
307
320
|
* authority on its own. The rules:
|
|
308
321
|
*
|
|
309
322
|
* - `user` (non-managed): rejected because it has no managed Session identity.
|
|
310
323
|
* - `global`: full Task authority after current Role Session verification.
|
|
311
324
|
* - `task` + mismatched taskId: rejected.
|
|
312
|
-
* -
|
|
313
|
-
* -
|
|
314
|
-
*
|
|
315
|
-
*
|
|
316
|
-
* per-Session caller-key verification; Role does not narrow it.
|
|
325
|
+
* - A non-Leader Task caller requires its current active Assignment.
|
|
326
|
+
* - A Leader Task caller requires its current, unrevoked native Session.
|
|
327
|
+
* - `task`: authority inside the matching Task after current Session and
|
|
328
|
+
* native Session verification; Role does not narrow it.
|
|
317
329
|
*/
|
|
318
330
|
/**
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
* same authoritative Controller. The channel itself is therefore not
|
|
323
|
-
* authenticated by those claims alone. A non-replayable per-Session caller key
|
|
324
|
-
* closes the gap:
|
|
325
|
-
*
|
|
326
|
-
* - `user` scope: **rejected outright** for start/cancel. A bare shell or a
|
|
327
|
-
* managed Session that sheds its identity has no managed Session binding.
|
|
328
|
-
* - `global` scope: verified against the current global Role Session.
|
|
329
|
-
* - `task` scope: the caller must present `callerKey` — the
|
|
330
|
-
* `YUI_JOB_CALLER_KEY` injected at its native Session launch. The Controller
|
|
331
|
-
* hashes it (SHA-256) and compares against the durable `jobCallerKeyHashes`
|
|
332
|
-
* map for the caller's Role + Agent. An absent hash or a
|
|
333
|
-
* mismatched key is UNAUTHORIZED.
|
|
334
|
-
*
|
|
335
|
-
* The existing Turn binding checks run after the key check, so a forged
|
|
336
|
-
* identity that also lacks the key is rejected at the channel boundary.
|
|
331
|
+
* Verify the caller's current native Session and Task scope. This local Home
|
|
332
|
+
* identity contract does not defend against another process with the same
|
|
333
|
+
* user's filesystem access. Bare user calls cannot start or cancel Jobs.
|
|
337
334
|
*/
|
|
338
335
|
function assertCallerAuthorized(store, caller, taskId) {
|
|
339
336
|
if (caller.scope === "user") {
|
|
340
337
|
// rr13: A user-scope caller has no per-Session channel binding. Every
|
|
341
338
|
// durable-state claim it could carry is replayable
|
|
342
339
|
// by any client in the same Home. Reject outright (fail-closed).
|
|
343
|
-
throw jobControlError("UNAUTHORIZED", "job.start/job.cancel requires a managed Session
|
|
340
|
+
throw jobControlError("UNAUTHORIZED", "job.start/job.cancel requires a managed native Session; user scope is rejected.");
|
|
344
341
|
}
|
|
345
342
|
if (caller.scope === "global") {
|
|
346
343
|
const roleName = caller.role;
|
|
347
|
-
const agentId =
|
|
344
|
+
const agentId = roleName === undefined ? undefined : store.getGlobalRole(roleName)?.activeAgentId;
|
|
348
345
|
const role = roleName === undefined ? null : store.getGlobalRole(roleName);
|
|
349
346
|
const binding = role === null || agentId === undefined
|
|
350
347
|
? undefined
|
|
351
348
|
: role.agentBindings[role.activeAgentId];
|
|
352
349
|
const sessions = roleName === undefined ? null : store.getGlobalRoleSessionSet(roleName);
|
|
353
350
|
const session = activeLiveRoleAgentSession(sessions);
|
|
354
|
-
if (role === null
|
|
355
|
-
|| binding === undefined
|
|
356
|
-
|| agentId === undefined
|
|
357
|
-
|| caller.adapterId === undefined
|
|
358
|
-
|| caller.runtimeGenerationId === undefined
|
|
359
|
-
|| sessions === null
|
|
360
|
-
|| sessions.activeAgentId !== role.activeAgentId
|
|
361
|
-
|| session === null
|
|
362
|
-
|| binding.agentId !== agentId
|
|
363
|
-
|| binding.adapterId !== caller.adapterId
|
|
364
|
-
|| session.agentId !== agentId
|
|
365
|
-
|| session.adapterId !== caller.adapterId
|
|
366
|
-
|| session.runtimeGenerationId !== caller.runtimeGenerationId
|
|
367
|
-
|| (caller.nativeSessionId !== undefined
|
|
368
|
-
&& session.nativeSessionId !== caller.nativeSessionId)) {
|
|
351
|
+
if (role === null || binding === undefined || agentId === undefined || sessions === null || sessions.activeAgentId !== role.activeAgentId || session === null || binding.agentId !== agentId || session.agentId !== agentId || session.adapterId !== binding.adapterId || caller.nativeSessionId === undefined || session.nativeSessionId !== caller.nativeSessionId) {
|
|
369
352
|
throw jobControlError("UNAUTHORIZED", "DurableJob control requires the current managed global Agent Session.");
|
|
370
353
|
}
|
|
371
354
|
return;
|
|
@@ -373,37 +356,29 @@ function assertCallerAuthorized(store, caller, taskId) {
|
|
|
373
356
|
if (caller.taskId !== taskId) {
|
|
374
357
|
throw jobControlError("UNAUTHORIZED", "A managed Task Session may not start or cancel Jobs for a different Task.");
|
|
375
358
|
}
|
|
376
|
-
//
|
|
377
|
-
//
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
359
|
+
// A long-lived Session is the Leader's identity, not its execution
|
|
360
|
+
// occupancy. Non-Leader callers still require their active Assignment.
|
|
361
|
+
const current = (() => {
|
|
362
|
+
try {
|
|
363
|
+
return requireManagedTaskCaller(store, {
|
|
364
|
+
YUI_SESSION_SCOPE: "task", YUI_TASK_ID: taskId, YUI_ROLE: caller.role,
|
|
365
|
+
YUI_NATIVE_SESSION_ID: caller.nativeSessionId
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
catch (error) {
|
|
369
|
+
throw jobControlError("UNAUTHORIZED", error instanceof Error ? error.message : String(error));
|
|
370
|
+
}
|
|
371
|
+
})();
|
|
372
|
+
if (current.roleName !== "leader" && current.currentRunId === undefined) {
|
|
373
|
+
throw jobControlError("UNAUTHORIZED", "A managed Task Session's Role is not bound to an active AgentRun.");
|
|
374
|
+
}
|
|
375
|
+
const sessions = store.getTaskRoleSessionSet(taskId, current.roleName);
|
|
387
376
|
const session = activeLiveRoleAgentSession(sessions);
|
|
388
|
-
if (sessions?.activeAgentId !==
|
|
389
|
-
|| session.agentId !==
|
|
377
|
+
if (sessions?.activeAgentId !== current.agentId || session === null
|
|
378
|
+
|| session.agentId !== current.agentId || session.adapterId !== current.adapterId
|
|
379
|
+
|| caller.nativeSessionId === undefined || session.nativeSessionId !== caller.nativeSessionId) {
|
|
390
380
|
throw jobControlError("UNAUTHORIZED", "DurableJob control requires the current live Task Session.");
|
|
391
381
|
}
|
|
392
|
-
// rr13: Verify the non-replayable per-Session caller key. The key is injected
|
|
393
|
-
// at native Session launch and never persisted in plaintext; only its SHA-256
|
|
394
|
-
// hash is durable. A client with database read access can see the hash but cannot
|
|
395
|
-
// recover the key.
|
|
396
|
-
if (caller.callerKey === undefined) {
|
|
397
|
-
throw jobControlError("UNAUTHORIZED", "job.start/job.cancel requires a managed Session caller key.");
|
|
398
|
-
}
|
|
399
|
-
const expectedHash = store.getJobCallerKeyHash(taskId, caller.role ?? "", currentRole.activeAgentId);
|
|
400
|
-
if (expectedHash === null) {
|
|
401
|
-
throw jobControlError("UNAUTHORIZED", "The managed Session has no durable caller key; it must be relaunched.");
|
|
402
|
-
}
|
|
403
|
-
const presentedHash = createHash("sha256").update(caller.callerKey).digest("hex");
|
|
404
|
-
if (presentedHash !== expectedHash) {
|
|
405
|
-
throw jobControlError("UNAUTHORIZED", "The managed Session caller key does not match the durable hash.");
|
|
406
|
-
}
|
|
407
382
|
}
|
|
408
383
|
/**
|
|
409
384
|
* Resolve the managed workspace for the job's owner. Returns null if no
|
|
@@ -448,7 +423,7 @@ function readGitHead(path) {
|
|
|
448
423
|
}
|
|
449
424
|
}
|
|
450
425
|
function isTerminalWorkItemStatus(status) {
|
|
451
|
-
return status === "
|
|
426
|
+
return status === "accepted" || status === "retired";
|
|
452
427
|
}
|
|
453
428
|
/**
|
|
454
429
|
* Strict `job.start` params parsing. Throws CoreApplicationError-shaped errors
|
|
@@ -617,8 +592,8 @@ function parseCaller(value) {
|
|
|
617
592
|
}
|
|
618
593
|
const record = value;
|
|
619
594
|
const allowed = new Set([
|
|
620
|
-
"scope", "taskId", "role", "agentId", "adapterId", "
|
|
621
|
-
"
|
|
595
|
+
"scope", "taskId", "role", "agentId", "adapterId", "nativeSessionId",
|
|
596
|
+
"runId"
|
|
622
597
|
]);
|
|
623
598
|
for (const key of Object.keys(record)) {
|
|
624
599
|
if (!allowed.has(key)) {
|
|
@@ -638,22 +613,16 @@ function parseCaller(value) {
|
|
|
638
613
|
const role = optionalId("role");
|
|
639
614
|
const agentId = optionalId("agentId");
|
|
640
615
|
const adapterId = optionalId("adapterId");
|
|
641
|
-
const runtimeGenerationId = optionalId("runtimeGenerationId");
|
|
642
616
|
const nativeSessionId = optionalId("nativeSessionId");
|
|
643
|
-
const
|
|
644
|
-
const callerKey = record.callerKey === undefined
|
|
645
|
-
? undefined
|
|
646
|
-
: requiredId(record.callerKey, "job caller callerKey");
|
|
617
|
+
const runId = optionalId("runId");
|
|
647
618
|
return {
|
|
648
619
|
scope: record.scope,
|
|
649
620
|
...(taskId === undefined ? {} : { taskId }),
|
|
650
621
|
...(role === undefined ? {} : { role }),
|
|
651
622
|
...(agentId === undefined ? {} : { agentId }),
|
|
652
623
|
...(adapterId === undefined ? {} : { adapterId }),
|
|
653
|
-
...(runtimeGenerationId === undefined ? {} : { runtimeGenerationId }),
|
|
654
624
|
...(nativeSessionId === undefined ? {} : { nativeSessionId }),
|
|
655
|
-
...(
|
|
656
|
-
...(callerKey === undefined ? {} : { callerKey })
|
|
625
|
+
...(runId === undefined ? {} : { runId })
|
|
657
626
|
};
|
|
658
627
|
}
|
|
659
628
|
function parseStringMap(value, label) {
|
|
@@ -32,11 +32,10 @@ export function createRuntimeResourceActivityTracker() {
|
|
|
32
32
|
|| roleKey === undefined)
|
|
33
33
|
return reject();
|
|
34
34
|
const identityKey = JSON.stringify([
|
|
35
|
-
identity.
|
|
35
|
+
identity.runId,
|
|
36
36
|
identity.agentId,
|
|
37
37
|
identity.adapterId,
|
|
38
|
-
identity.nativeSessionId ?? null
|
|
39
|
-
identity.runtimeGenerationId ?? null
|
|
38
|
+
identity.nativeSessionId ?? null
|
|
40
39
|
]);
|
|
41
40
|
const current = {
|
|
42
41
|
identity: identityKey,
|
|
@@ -113,7 +112,7 @@ export function buildControllerResourceInventory(facts) {
|
|
|
113
112
|
for (const process of paneProcesses)
|
|
114
113
|
claimed.add(process.pid);
|
|
115
114
|
const role = findRole(homeFact.roles, pane);
|
|
116
|
-
const terminalIsolation = role?.taskStatus === "
|
|
115
|
+
const terminalIsolation = (role?.taskStatus === "cancelled" && role.taskRetirementIsolated === true)
|
|
117
116
|
|| role?.taskStatus === "archived";
|
|
118
117
|
resources.push(processResource({
|
|
119
118
|
kind: "agent-session",
|
|
@@ -123,7 +122,7 @@ export function buildControllerResourceInventory(facts) {
|
|
|
123
122
|
: terminalIsolation ? "safe" : "protected",
|
|
124
123
|
reasonCode: role === undefined
|
|
125
124
|
? pane.dead ? "dead-orphan-pane" : "orphan-pane"
|
|
126
|
-
: terminalIsolation ?
|
|
125
|
+
: terminalIsolation ? (role.taskStatus === "cancelled" ? "retired-task-pane" : "archived-task-pane") : "owned-role-pane",
|
|
127
126
|
yuiHome,
|
|
128
127
|
owner: role === undefined ? { kind: "none" } : roleOwner(role),
|
|
129
128
|
processes: paneProcesses,
|
|
@@ -261,8 +260,7 @@ function roleOwner(role) {
|
|
|
261
260
|
agentId: role.agentId,
|
|
262
261
|
...(role.adapterId === undefined ? {} : { adapterId: role.adapterId }),
|
|
263
262
|
...(role.nativeSessionId === undefined ? {} : { nativeSessionId: role.nativeSessionId }),
|
|
264
|
-
...(role.
|
|
265
|
-
...(role.turnId === undefined ? {} : { turnId: role.turnId })
|
|
263
|
+
...(role.runId === undefined ? {} : { runId: role.runId })
|
|
266
264
|
};
|
|
267
265
|
}
|
|
268
266
|
return {
|
|
@@ -274,8 +272,7 @@ function roleOwner(role) {
|
|
|
274
272
|
agentId: role.agentId,
|
|
275
273
|
...(role.adapterId === undefined ? {} : { adapterId: role.adapterId }),
|
|
276
274
|
...(role.nativeSessionId === undefined ? {} : { nativeSessionId: role.nativeSessionId }),
|
|
277
|
-
...(role.
|
|
278
|
-
...(role.turnId === undefined ? {} : { turnId: role.turnId })
|
|
275
|
+
...(role.runId === undefined ? {} : { runId: role.runId })
|
|
279
276
|
};
|
|
280
277
|
}
|
|
281
278
|
function processTree(processes, rootPid) {
|
|
@@ -432,34 +429,18 @@ function optionalCounterFields(processes, field) {
|
|
|
432
429
|
: { ioWriteBytes: sum(values) };
|
|
433
430
|
}
|
|
434
431
|
function matchesResourceIdentity(identity, owner) {
|
|
435
|
-
if (identity === undefined
|
|
436
|
-
|| typeof identity.taskId !== "string"
|
|
437
|
-
|| identity.taskId.length === 0
|
|
438
|
-
|| typeof identity.roleName !== "string"
|
|
439
|
-
|| identity.roleName.length === 0
|
|
440
|
-
|| typeof identity.turnId !== "string"
|
|
441
|
-
|| identity.turnId.length === 0
|
|
442
|
-
|| typeof identity.agentId !== "string"
|
|
443
|
-
|| identity.agentId.length === 0
|
|
444
|
-
|| typeof identity.adapterId !== "string"
|
|
445
|
-
|| identity.adapterId.length === 0
|
|
446
|
-
|| (identity.nativeSessionId !== undefined && !hasIdentityText(identity.nativeSessionId))
|
|
447
|
-
|| (identity.runtimeGenerationId !== undefined && !hasIdentityText(identity.runtimeGenerationId)))
|
|
432
|
+
if (identity === undefined || typeof identity.taskId !== "string" || identity.taskId.length === 0 || typeof identity.roleName !== "string" || identity.roleName.length === 0 || typeof identity.runId !== "string" || identity.runId.length === 0 || typeof identity.agentId !== "string" || identity.agentId.length === 0 || typeof identity.adapterId !== "string" || identity.adapterId.length === 0 || !hasIdentityText(identity.nativeSessionId))
|
|
448
433
|
return false;
|
|
449
434
|
if (owner.kind !== "task-role"
|
|
450
435
|
|| owner.taskId !== identity.taskId
|
|
451
436
|
|| owner.roleName !== identity.roleName
|
|
452
|
-
|| owner.
|
|
437
|
+
|| owner.runId !== identity.runId
|
|
453
438
|
|| owner.agentId !== identity.agentId
|
|
454
439
|
|| owner.adapterId !== identity.adapterId)
|
|
455
440
|
return false;
|
|
456
|
-
if (!hasIdentityText(identity.nativeSessionId) && !hasIdentityText(identity.runtimeGenerationId))
|
|
457
|
-
return false;
|
|
458
441
|
if (identity.nativeSessionId !== undefined
|
|
459
442
|
&& owner.nativeSessionId !== identity.nativeSessionId)
|
|
460
443
|
return false;
|
|
461
|
-
if (identity.runtimeGenerationId !== undefined && owner.runtimeGenerationId !== identity.runtimeGenerationId)
|
|
462
|
-
return false;
|
|
463
444
|
return true;
|
|
464
445
|
}
|
|
465
446
|
function hasIdentityText(value) {
|
|
@@ -14,7 +14,7 @@ import { readHomeFilesystemId } from "../core/homeFilesystemIdentity.js";
|
|
|
14
14
|
import { buildControllerResourceInventory } from "./resourceInventory.js";
|
|
15
15
|
import { CONTROLLER_DOMAIN_PATH, EPHEMERAL_DOMAIN_GRACE_MS, ephemeralDomainFingerprint, readEphemeralDomainIdentity, readLinuxProcessStartIdentity } from "./domainIdentity.js";
|
|
16
16
|
const LINUX_PROCESS_SCAN_BATCH_SIZE = 64;
|
|
17
|
-
export const
|
|
17
|
+
export const INVENTORY_EVENT_LOOP_RUN_BUDGET_MS = 25;
|
|
18
18
|
export async function scanControllerResourceInventory(options) {
|
|
19
19
|
const currentHome = resolve(options.currentHome);
|
|
20
20
|
const environment = options.environment ?? process.env;
|
|
@@ -282,17 +282,17 @@ export async function forEachInEventLoopBatches(entries, batchSize, visit, timin
|
|
|
282
282
|
throw new Error("Event-loop batch size must be a positive integer.");
|
|
283
283
|
}
|
|
284
284
|
const now = timing.now ?? (() => performance.now());
|
|
285
|
-
let
|
|
286
|
-
let
|
|
285
|
+
let runStartedAt = now();
|
|
286
|
+
let entriesInRun = 0;
|
|
287
287
|
for (let index = 0; index < entries.length; index += 1) {
|
|
288
288
|
visit(entries[index], index);
|
|
289
|
-
|
|
289
|
+
entriesInRun += 1;
|
|
290
290
|
if (index + 1 < entries.length
|
|
291
|
-
&& (
|
|
292
|
-
|| now() -
|
|
291
|
+
&& (entriesInRun >= batchSize
|
|
292
|
+
|| now() - runStartedAt >= INVENTORY_EVENT_LOOP_RUN_BUDGET_MS)) {
|
|
293
293
|
await new Promise((resolve) => setImmediate(resolve));
|
|
294
|
-
|
|
295
|
-
|
|
294
|
+
runStartedAt = now();
|
|
295
|
+
entriesInRun = 0;
|
|
296
296
|
}
|
|
297
297
|
}
|
|
298
298
|
}
|
|
@@ -634,13 +634,12 @@ function loadHomeState(home, warnings, options) {
|
|
|
634
634
|
agentId,
|
|
635
635
|
...(adapterId === undefined ? {} : { adapterId }),
|
|
636
636
|
...(session === null ? {} : { nativeSessionId: session.nativeSessionId }),
|
|
637
|
-
...(session?.runtimeGenerationId === undefined ? {} : { runtimeGenerationId: session.runtimeGenerationId })
|
|
638
637
|
};
|
|
639
638
|
});
|
|
640
639
|
const appendTaskRole = (task, role) => {
|
|
641
640
|
const session = activeLiveRoleAgentSession(store.getRoleSessionSet(task.id, role.name));
|
|
642
641
|
const binding = role.agentBindings[role.activeAgentId];
|
|
643
|
-
const run = store.
|
|
642
|
+
const run = store.getActiveRun(task.id, role.name);
|
|
644
643
|
const agentId = session?.effective.agentId ?? role.activeAgentId;
|
|
645
644
|
const adapterId = session?.effective.adapterId ?? binding?.adapterId;
|
|
646
645
|
roles.push({
|
|
@@ -648,17 +647,17 @@ function loadHomeState(home, warnings, options) {
|
|
|
648
647
|
taskId: task.id,
|
|
649
648
|
taskTitle: task.title,
|
|
650
649
|
taskStatus: task.status,
|
|
650
|
+
taskRetirementIsolated: task.retirementIsolation === true,
|
|
651
651
|
roleName: role.name,
|
|
652
652
|
agentId,
|
|
653
653
|
...(adapterId === undefined ? {} : { adapterId }),
|
|
654
654
|
...(session === null ? {} : { nativeSessionId: session.nativeSessionId }),
|
|
655
|
-
...(
|
|
656
|
-
...(run === null ? {} : { turnId: run.id })
|
|
655
|
+
...(run === null ? {} : { runId: run.id })
|
|
657
656
|
});
|
|
658
657
|
};
|
|
659
658
|
// The current SQLite store owns bounded active-Task and current-Session
|
|
660
659
|
// indexes. Use them only as selectors, then point-read the authoritative
|
|
661
|
-
// Task/Role/Session/
|
|
660
|
+
// Task/Role/Session/AgentRun records so an index row cannot bypass ownership
|
|
662
661
|
// fences.
|
|
663
662
|
const indexedTaskIds = [...new Set(store.listActiveTaskIds())].sort(numericCompare);
|
|
664
663
|
const sessionCandidates = store.listRuntimeSessionCandidates({ scope: "task" });
|