@zq-silk/yui 0.13.10 → 0.14.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 +69 -428
- package/README.md +108 -298
- package/dist/agent/managedRuntimeEnvironment.js +2 -2
- package/dist/cli/commandCatalog.js +39 -77
- package/dist/cli/interactionCandidates.js +4 -4
- package/dist/cli/interactionPolicy.js +7 -10
- package/dist/cli/invocationRouter.js +1 -1
- package/dist/cli/updateCommand.js +6 -27
- package/dist/cli/updateOrchestrator.js +63 -484
- package/dist/cli/updatePorts.js +15 -333
- package/dist/cli/upgradeCommand.js +8 -65
- package/dist/cli.js +57 -242
- package/dist/commands/configCommands.js +11 -62
- package/dist/commands/executionAuditCommands.js +23 -23
- package/dist/commands/globalRoleCommands.js +2 -7
- package/dist/commands/jobCommands.js +1 -4
- package/dist/commands/projectCommands.js +5 -5
- package/dist/commands/releaseCommands.js +3 -10
- package/dist/commands/resourcesCommands.js +2 -2
- package/dist/commands/sessionCommands.js +2 -2
- package/dist/commands/taskActor.js +31 -39
- package/dist/commands/taskChangeSetCommands.js +5 -12
- package/dist/commands/taskCommands.js +464 -1249
- package/dist/commands/taskContextCommand.js +35 -36
- package/dist/commands/taskExecutionCommands.js +33 -46
- package/dist/commands/taskInputCommands.js +20 -42
- package/dist/commands/taskNextActionCommand.js +9 -9
- package/dist/commands/taskOverviewCommand.js +56 -95
- package/dist/commands/taskRoleRuntimeStatus.js +77 -107
- package/dist/commands/taskUpstreamCommands.js +3 -3
- package/dist/commands/taskWorkspaceCommands.js +7 -79
- package/dist/commands/telemetryCommands.js +32 -124
- package/dist/commands/workflowCommands.js +3 -3
- package/dist/completion/fileCompletionManager.js +1 -1
- package/dist/config/configCatalog.js +4 -6
- package/dist/config/yuiConfig.js +6 -43
- package/dist/context/dispatchContext.js +14 -30
- package/dist/context/roleSessionContext.js +2 -2
- package/dist/context/sessionBootstrapManifest.js +2 -2
- package/dist/context/{runContextPack.js → turnContextPack.js} +58 -73
- package/dist/context/turnInputContract.js +204 -0
- package/dist/context/wakeNotification.js +2 -2
- package/dist/controller/agentRuntimeObserver.js +18 -18
- package/dist/controller/clientRuntime.js +13 -20
- package/dist/controller/controller.js +89 -116
- package/dist/controller/fileSchedulerStoreAdapter.js +511 -742
- package/dist/controller/jobControl.js +17 -17
- package/dist/controller/resourceInventory.js +6 -6
- package/dist/controller/resourceInventoryLinux.js +38 -59
- package/dist/controller/resourceInventoryRpc.js +3 -3
- package/dist/controller/resourceInventoryWorker.js +1 -1
- package/dist/controller/runtime.js +46 -53
- package/dist/controller/runtimeEventInbox.js +23 -31
- package/dist/controller/runtimeEventProcessor.js +15 -15
- package/dist/controller/{runtimeHookRunFence.js → runtimeHookTurnFence.js} +87 -81
- package/dist/controller/runtimeLaunchCoordinator.js +3 -3
- package/dist/controller/runtimeObservationHook.js +11 -8
- package/dist/controller/sessionNotify.js +11 -11
- package/dist/controller/structuredProviderObservation.js +89 -16
- package/dist/coordination/workMailbox.js +309 -579
- package/dist/coordination/workMailboxQueue.js +5 -6
- package/dist/core/controllerClient.js +1 -91
- package/dist/core/controllerServer.js +3 -6
- package/dist/doctor/doctor.js +51 -314
- package/dist/execution/candidateConvergence.js +3 -3
- package/dist/execution/executionGroup.js +32 -33
- package/dist/execution/executionHealth.js +36 -38
- package/dist/execution/resourceBroker.js +12 -12
- package/dist/executor/agentExecutor.js +30 -265
- package/dist/executor/effectiveLaunch.js +9 -19
- package/dist/executor/executorRegistry.js +43 -17
- package/dist/executor/fileRoleLaunchPlanner.js +56 -56
- package/dist/executor/launchPlan.js +3 -3
- package/dist/executor/workspacePreflightClassification.js +16 -16
- package/dist/grant/capabilityGrant.js +20 -25
- package/dist/input/inputRequest.js +12 -12
- package/dist/integration/changeSet.js +9 -13
- package/dist/integration/changeSetManifest.js +1 -1
- package/dist/integration/gitIntegrationService.js +2 -2
- package/dist/integration/integrationQueueService.js +5 -21
- package/dist/integration/overlapDiagnostics.js +2 -2
- package/dist/interaction/operatorPresentation.js +1 -1
- package/dist/job/jobRunner.js +1 -1
- package/dist/lifecycle/canonicalLifecycleEvent.js +25 -25
- package/dist/lifecycle/{exactRunTerminalization.js → exactTurnTerminalization.js} +116 -232
- package/dist/message/message.js +6 -6
- package/dist/observability/executionAudit.js +74 -86
- package/dist/observability/faultClassification.js +7 -24
- package/dist/observability/orchestrationMetrics.js +5 -5
- package/dist/observability/runtimeIdentity.js +34 -101
- package/dist/profile/agentProfile.js +1 -1
- package/dist/release/cliHomeReleaseFence.js +3 -3
- package/dist/release/releaseWorkflowEngine.js +6 -10
- package/dist/release/releaseWorkflowPorts.js +2 -2
- package/dist/release/workflowFileLock.js +1 -1
- package/dist/repository/checkoutSwap.js +1 -1
- package/dist/repository/gitWorkspace.js +0 -13
- package/dist/repository/project.js +1 -1
- package/dist/repository/projectMaintenanceLock.js +1 -2
- package/dist/repository/taskBaseFreshness.js +13 -13
- package/dist/repository/taskWorkspaceCoordinator.js +21 -25
- package/dist/repository/taskWorkspaceIdentity.js +8 -21
- package/dist/repository/taskWorkspacePreparer.js +63 -620
- package/dist/resources/autoResourceGc.js +3 -3
- package/dist/resources/liveReferences.js +1 -1
- package/dist/resources/resourceGc.js +1 -1
- package/dist/resources/sqliteResourceRegistry.js +1 -1
- package/dist/review/reviewDecision.js +7 -7
- package/dist/review/reviewFindingLedger.js +1 -1
- package/dist/review/reviewOutcomeClassifier.js +35 -50
- package/dist/review/reviewRound.js +14 -25
- package/dist/review/reviewerAvailability.js +4 -4
- package/dist/review/taskFinalReviewContractResolution.js +41 -0
- package/dist/role/role.js +6 -3
- package/dist/runtime/agentDriver.js +4 -0
- package/dist/runtime/agentHost.js +151 -36
- package/dist/runtime/builtinAgentDrivers.js +79 -2
- package/dist/runtime/codexAppServerRuntime.js +122 -0
- package/dist/runtime/continuationManager.js +3 -5
- package/dist/runtime/exactControlPlane.js +17 -42
- package/dist/runtime/firstProgressAdvisory.js +1 -1
- package/dist/runtime/index.js +2 -2
- package/dist/runtime/launchDiagnostics.js +2 -2
- package/dist/runtime/lifecycleReservation.js +4 -4
- package/dist/runtime/processExitObservation.js +1 -1
- package/dist/runtime/processExitOutbox.js +0 -32
- package/dist/runtime/promptEnvelope.js +9 -9
- package/dist/runtime/providerContinuation.js +2 -2
- package/dist/runtime/providerContinuationReconciliationService.js +2 -2
- package/dist/runtime/providerRuntimeIdentity.js +76 -24
- package/dist/runtime/recentTurnIds.js +38 -0
- package/dist/runtime/runtimeContinuationProjection.js +2 -2
- package/dist/runtime/runtimeHealthPolicy.js +1 -1
- package/dist/runtime/runtimeObservation.js +58 -21
- package/dist/runtime/runtimeProjection.js +19 -27
- package/dist/runtime/sessionLaunchRequest.js +2 -2
- package/dist/runtime/structuredProviderHost.js +177 -12
- package/dist/runtime/tmuxAdapters.js +46 -11
- package/dist/scheduler/activeRoleTurnDelivery.js +245 -0
- package/dist/scheduler/leaderWakeupProcessor.js +147 -445
- package/dist/scheduler/operatorEvent.js +4 -6
- package/dist/scheduler/resourceQueueProjection.js +71 -0
- package/dist/scheduler/{roleRunLiveness.js → roleTurnLiveness.js} +24 -28
- package/dist/scheduler/{roleRunStall.js → roleTurnStall.js} +162 -247
- package/dist/scheduler/taskExecutionProjection.js +99 -99
- package/dist/scheduler/taskObservabilityProjection.js +10 -10
- package/dist/scheduler/taskWake.js +4 -4
- package/dist/scheduler/wakeReason.js +6 -10
- package/dist/scheduler/wakeupQueue.js +0 -9
- package/dist/setup/setupCommand.js +2 -2
- package/dist/storage/currentTaskStore.js +46 -0
- package/dist/storage/persistenceWorker.js +1 -1
- package/dist/storage/sqliteSchema.js +81 -485
- package/dist/storage/sqliteStore.js +206 -365
- package/dist/storage/storageSchema.js +1 -15
- package/dist/storage/storageVersions.js +8 -9
- package/dist/storage/storeRpc.js +10 -34
- package/dist/storage/taskStore.js +63 -3415
- package/dist/storage/upgrade/recordVersions.js +55 -149
- package/dist/storage/upgrade/upgradeOrchestrator.js +89 -1752
- package/dist/task/completionReadiness.js +5 -5
- package/dist/task/deliveryGuard.js +10 -10
- package/dist/task/nextAction.js +74 -77
- package/dist/task/task.js +2 -4
- package/dist/task/taskRecordReference.js +3 -3
- package/dist/task/taskRecordRetirement.js +1 -1
- package/dist/telemetry/sqliteTelemetryStore.js +53 -53
- package/dist/telemetry/telemetryConfig.js +14 -14
- package/dist/telemetry/telemetryWiring.js +8 -14
- package/dist/turn/turn.js +356 -0
- package/dist/{run/runIdentity.js → turn/turnIdentity.js} +4 -4
- package/dist/verification/gateArtifactStore.js +2 -2
- package/dist/web/assets/client/app.js +1 -1
- package/dist/web/assets/client/components.js +29 -54
- package/dist/web/assets/client/i18n.js +17 -37
- package/dist/web/assets/client/view.js +37 -37
- package/dist/web/assets/shell.js +1 -1
- package/dist/web/assets/styles/cards.js +5 -5
- package/dist/web/assets/styles/widgets.js +1 -2
- package/dist/web/webSnapshot.js +65 -60
- package/dist/workItem/workItem.js +11 -11
- package/dist/workspace/workItemChangeSetManager.js +1 -1
- package/docs/task-local-identity.md +5 -5
- package/i18n/README.zh-CN.md +41 -54
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +85 -83
- package/skills/yui-operator/SKILL.md +16 -16
- package/skills/yui-reviewer/SKILL.md +10 -10
- package/skills/yui-runtime/SKILL.md +17 -18
- package/skills/yui-worker/SKILL.md +16 -18
- package/dist/context/runContextContract.js +0 -162
- package/dist/executor/turnCompletion.js +0 -126
- package/dist/review/taskFinalReviewContractEvent.js +0 -1
- package/dist/review/taskFinalReviewContractRebind.js +0 -367
- package/dist/run/agentRun.js +0 -356
- package/dist/run/rejectedYieldAttempt.js +0 -221
- package/dist/run/runControlRequest.js +0 -50
- package/dist/run/yieldReceipt.js +0 -65
- package/dist/runtime/turnCompletion.js +0 -3
- package/dist/scheduler/actionability.js +0 -323
- package/dist/scheduler/activeRoleRunDelivery.js +0 -868
- package/dist/scheduler/activeTaskProgress.js +0 -126
- package/dist/storage/compatibleTaskStore.js +0 -248
- package/dist/storage/migration/baseline.js +0 -78
- package/dist/storage/migration/classifier.js +0 -51
- package/dist/storage/migration/compatibleCodec.js +0 -53
- package/dist/storage/migration/engine.js +0 -147
- package/dist/storage/migration/index.js +0 -33
- package/dist/storage/migration/planner.js +0 -154
- package/dist/storage/migration/productionRegistry.js +0 -3931
- package/dist/storage/migration/registry.js +0 -169
- package/dist/storage/migration/report.js +0 -54
- package/dist/storage/migration/types.js +0 -31
- package/dist/storage/upgrade/homeClassification.js +0 -353
- package/dist/storage/upgrade/homeMigrationTarget.js +0 -595
- package/dist/storage/upgrade/migrationReceipt.js +0 -67
- package/dist/storage/upgrade/offlineUpgradeInventory.js +0 -453
- package/dist/storage/upgrade/productionMigrationRegistry.js +0 -6
- package/dist/storage/upgrade/pseudoLayoutRepair.js +0 -241
- package/dist/storage/upgrade/recordVersionScan.js +0 -176
- package/dist/storage/upgrade/sqliteFileSet.js +0 -50
- package/dist/storage/upgrade/sqliteMigrationTarget.js +0 -375
- package/dist/storage/upgrade/sqliteRecordMigrationTarget.js +0 -305
- package/dist/storage/upgrade/sqliteStateMigration.js +0 -926
- package/dist/storage/upgrade/switchProgress.js +0 -80
- package/dist/storage/upgrade/upgradeReceipt.js +0 -161
- package/dist/storage/upgradeCoordination.js +0 -187
- package/dist/storage/upgradeFence.js +0 -366
- package/dist/telemetry/telemetryCompaction.js +0 -252
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { mkdirSync, realpathSync } from "node:fs";
|
|
2
2
|
import { isAbsolute, relative, resolve } from "node:path";
|
|
3
3
|
import { usageError } from "../errors/cliError.js";
|
|
4
|
-
import { DEFAULT_AGENT_LAUNCH_INACTIVITY_TIMEOUT_SECONDS, DEFAULT_CONTROLLER_TASK_CONCURRENCY, DEFAULT_DELIVERY_TIMEOUT_SECONDS, DEFAULT_LEADER_NEXT_ACTION_MODE, DEFAULT_LEADER_SEMANTIC_BUDGET_TURNS, DEFAULT_RECONCILIATION_INTERVAL_SECONDS, DEFAULT_RESOURCES_GC_MODE, DEFAULT_RESOURCES_QUARANTINE_TTL_HOURS, DEFAULT_TMUX_HISTORY_LIMIT, LEADER_NEXT_ACTION_MODES, reconciliationIntervalMilliseconds, resolveAgentLaunchInactivityTimeoutSeconds, resolveControllerTaskConcurrency,
|
|
4
|
+
import { DEFAULT_AGENT_LAUNCH_INACTIVITY_TIMEOUT_SECONDS, DEFAULT_CONTROLLER_TASK_CONCURRENCY, DEFAULT_DELIVERY_TIMEOUT_SECONDS, DEFAULT_LEADER_NEXT_ACTION_MODE, DEFAULT_LEADER_SEMANTIC_BUDGET_TURNS, DEFAULT_RECONCILIATION_INTERVAL_SECONDS, DEFAULT_RESOURCES_GC_MODE, DEFAULT_RESOURCES_QUARANTINE_TTL_HOURS, DEFAULT_TMUX_HISTORY_LIMIT, LEADER_NEXT_ACTION_MODES, reconciliationIntervalMilliseconds, resolveAgentLaunchInactivityTimeoutSeconds, resolveControllerTaskConcurrency, resolveDeliveryTimeoutSeconds, resolveLeaderNextActionMode, resolveLeaderSemanticBudgetTurns, resolveResourcesGcAutoQuarantine, resolveResourcesGcMode, resolveResourcesQuarantineTtlHours, resolveRuntimeHealth, resolveTelemetryEnabled, resolveTelemetryTurnCap, resolveTelemetryTerminalKeep, resolveTmuxBin, resolveTmuxHistoryLimit } from "../config/yuiConfig.js";
|
|
5
5
|
import { CONFIG_DEFINITIONS, CONFIG_KEYS, configDefinition, configDefinitionsForDomain } from "../config/configCatalog.js";
|
|
6
6
|
import { resolveTimeZone } from "../output/timePresentation.js";
|
|
7
7
|
import { defaultTableWidth, renderTable } from "../output/table.js";
|
|
@@ -21,7 +21,6 @@ const RECONCILIATION_SET_USAGE = "Runtime config set usage: yui config runtime s
|
|
|
21
21
|
const RESOURCES_GC_MODE_SET_USAGE = "Resources config set usage: yui config resources set resources-gc-mode <report|quarantine>.";
|
|
22
22
|
const RESOURCES_GC_AUTO_QUARANTINE_SET_USAGE = "Resources config set usage: yui config resources set resources-gc-auto-quarantine <true|false>.";
|
|
23
23
|
const LEADER_NEXT_ACTION_SET_USAGE = `Workflow config set usage: yui config workflow set leader-next-action <${LEADER_NEXT_ACTION_MODES.join("|")}>.`;
|
|
24
|
-
const CONTEXT_BUDGET_SET_USAGE = "Workflow config set usage: yui config workflow set context-budget [--soft-tokens <n>] [--hard-tokens <n>].";
|
|
25
24
|
const REVIEW_SET_USAGE = "Workflow config set usage: yui config workflow set review --role <global-role> --trigger <always|leader|final> "
|
|
26
25
|
+ "[--finding-ledger <shadow|enforce>].";
|
|
27
26
|
export function runConfigCommand(domain, args, store) {
|
|
@@ -57,7 +56,6 @@ function renderConfigShow(domain, config) {
|
|
|
57
56
|
}
|
|
58
57
|
/** Effective values for every user-configurable system field. */
|
|
59
58
|
export function effectiveConfigData(config, domain) {
|
|
60
|
-
const budget = resolveContextBudget(config.contextBudget);
|
|
61
59
|
const health = resolveRuntimeHealth(config.runtimeHealth);
|
|
62
60
|
const all = {
|
|
63
61
|
schemaVersion: config.schemaVersion,
|
|
@@ -69,7 +67,6 @@ export function effectiveConfigData(config, domain) {
|
|
|
69
67
|
reconciliationIntervalSeconds: config.reconciliationIntervalSeconds
|
|
70
68
|
?? DEFAULT_RECONCILIATION_INTERVAL_SECONDS,
|
|
71
69
|
leaderNextActionMode: resolveLeaderNextActionMode(config.leaderNextActionMode),
|
|
72
|
-
contextBudget: { softTokens: budget.softTokens, hardTokens: budget.hardTokens },
|
|
73
70
|
resourcesGcMode: resolveResourcesGcMode(config.resourcesGcMode),
|
|
74
71
|
resourcesGcAutoQuarantine: resolveResourcesGcAutoQuarantine(config.resourcesGcAutoQuarantine),
|
|
75
72
|
resourcesQuarantineTtlHours: resolveResourcesQuarantineTtlHours(config.resourcesQuarantineTtlHours),
|
|
@@ -86,7 +83,7 @@ export function effectiveConfigData(config, domain) {
|
|
|
86
83
|
tmuxHistoryLimit: resolveTmuxHistoryLimit(config.tmuxHistoryLimit),
|
|
87
84
|
telemetryEnabled: resolveTelemetryEnabled(config.telemetryEnabled),
|
|
88
85
|
telemetryTerminalKeep: resolveTelemetryTerminalKeep(config.telemetryTerminalKeep),
|
|
89
|
-
|
|
86
|
+
telemetryTurnCap: resolveTelemetryTurnCap(config.telemetryTurnCap),
|
|
90
87
|
review: config.review === undefined
|
|
91
88
|
? null
|
|
92
89
|
: {
|
|
@@ -151,12 +148,6 @@ function validatedConfigValue(validate, usage) {
|
|
|
151
148
|
throw error;
|
|
152
149
|
}
|
|
153
150
|
}
|
|
154
|
-
function parseBudgetToken(value, label) {
|
|
155
|
-
if (!/^\d+$/.test(value)) {
|
|
156
|
-
throw usageError(`${label} must be a positive integer.`);
|
|
157
|
-
}
|
|
158
|
-
return Number(value);
|
|
159
|
-
}
|
|
160
151
|
function parseReconciliationIntervalSeconds(value) {
|
|
161
152
|
if (!/^\d+$/.test(value))
|
|
162
153
|
return Number.NaN;
|
|
@@ -293,48 +284,6 @@ const CONFIG_KEY_HANDLERS = [
|
|
|
293
284
|
return `Leader semantic budget reset to ${DEFAULT_LEADER_SEMANTIC_BUDGET_TURNS} turns\n`;
|
|
294
285
|
}
|
|
295
286
|
},
|
|
296
|
-
{
|
|
297
|
-
key: "context-budget",
|
|
298
|
-
showLabel: "Legacy context budget (inactive)",
|
|
299
|
-
showValue: (config) => {
|
|
300
|
-
const budget = resolveContextBudget(config.contextBudget);
|
|
301
|
-
return `inactive; legacy soft ${budget.softTokens} / hard ${budget.hardTokens} tokens`;
|
|
302
|
-
},
|
|
303
|
-
set(args, store) {
|
|
304
|
-
if (args.length !== 2 && args.length !== 4)
|
|
305
|
-
throw usageError(CONTEXT_BUDGET_SET_USAGE);
|
|
306
|
-
const options = new Map();
|
|
307
|
-
for (let index = 0; index < args.length; index += 2) {
|
|
308
|
-
const name = args[index];
|
|
309
|
-
const value = args[index + 1];
|
|
310
|
-
if (!["--soft-tokens", "--hard-tokens"].includes(name)
|
|
311
|
-
|| value === undefined
|
|
312
|
-
|| options.has(name)) {
|
|
313
|
-
throw usageError(CONTEXT_BUDGET_SET_USAGE);
|
|
314
|
-
}
|
|
315
|
-
options.set(name, value);
|
|
316
|
-
}
|
|
317
|
-
const current = resolveContextBudget(store.getConfig().contextBudget);
|
|
318
|
-
const next = {
|
|
319
|
-
...(options.get("--soft-tokens") === undefined
|
|
320
|
-
? {}
|
|
321
|
-
: { softTokens: parseBudgetToken(options.get("--soft-tokens"), "--soft-tokens") }),
|
|
322
|
-
...(options.get("--hard-tokens") === undefined
|
|
323
|
-
? {}
|
|
324
|
-
: { hardTokens: parseBudgetToken(options.get("--hard-tokens"), "--hard-tokens") })
|
|
325
|
-
};
|
|
326
|
-
const resolved = resolveContextBudget({ ...current, ...next });
|
|
327
|
-
saveConfigKey(store, (config) => ({ ...config, contextBudget: resolved }));
|
|
328
|
-
return `Legacy context budget stored as soft ${resolved.softTokens} / hard ${resolved.hardTokens} tokens (inactive)\n`;
|
|
329
|
-
},
|
|
330
|
-
clear(store) {
|
|
331
|
-
saveConfigKey(store, (config) => {
|
|
332
|
-
const { contextBudget: _removed, ...rest } = config;
|
|
333
|
-
return rest;
|
|
334
|
-
});
|
|
335
|
-
return "Legacy context budget cleared; Session Token metrics remain read-only\n";
|
|
336
|
-
}
|
|
337
|
-
},
|
|
338
287
|
{
|
|
339
288
|
key: "resources-gc-mode",
|
|
340
289
|
showLabel: "Resources GC mode",
|
|
@@ -573,22 +522,22 @@ const CONFIG_KEY_HANDLERS = [
|
|
|
573
522
|
}
|
|
574
523
|
},
|
|
575
524
|
{
|
|
576
|
-
key: "telemetry-
|
|
577
|
-
showLabel: "Telemetry
|
|
578
|
-
showValue: (config) => String(
|
|
525
|
+
key: "telemetry-turn-cap",
|
|
526
|
+
showLabel: "Telemetry Turn cap",
|
|
527
|
+
showValue: (config) => String(resolveTelemetryTurnCap(config.telemetryTurnCap)),
|
|
579
528
|
set(args, store) {
|
|
580
529
|
if (args.length !== 1)
|
|
581
|
-
throw usageError("Tools config set usage: yui config tools set telemetry-
|
|
582
|
-
const
|
|
583
|
-
saveConfigKey(store, (config) => ({ ...config,
|
|
584
|
-
return `Telemetry
|
|
530
|
+
throw usageError("Tools config set usage: yui config tools set telemetry-turn-cap <n>.");
|
|
531
|
+
const telemetryTurnCap = validatedConfigValue(() => resolveTelemetryTurnCap(Number(args[0])), "Tools config set usage: yui config tools set telemetry-turn-cap <n>.");
|
|
532
|
+
saveConfigKey(store, (config) => ({ ...config, telemetryTurnCap }));
|
|
533
|
+
return `Telemetry Turn cap set to ${telemetryTurnCap}\n`;
|
|
585
534
|
},
|
|
586
535
|
clear(store) {
|
|
587
536
|
saveConfigKey(store, (config) => {
|
|
588
|
-
const {
|
|
537
|
+
const { telemetryTurnCap: _removed, ...rest } = config;
|
|
589
538
|
return rest;
|
|
590
539
|
});
|
|
591
|
-
return "Telemetry
|
|
540
|
+
return "Telemetry Turn cap reset to default\n";
|
|
592
541
|
}
|
|
593
542
|
},
|
|
594
543
|
{
|
|
@@ -92,36 +92,36 @@ export function renderExecutionAudit(report, width = defaultTableWidth()) {
|
|
|
92
92
|
else {
|
|
93
93
|
lines.push("", ...sectionError("tasks", report));
|
|
94
94
|
}
|
|
95
|
-
if (report.
|
|
96
|
-
const
|
|
97
|
-
lines.push("", `
|
|
98
|
-
const faultRows = Object.entries(
|
|
95
|
+
if (report.turns.status === "ok" && report.turns.data !== undefined) {
|
|
96
|
+
const turns = report.turns.data;
|
|
97
|
+
lines.push("", `Turns: ${turns.total} total · ${turns.failed} failed (${(turns.failureRate * 100).toFixed(1)}%) · ${turns.completed} completed · ${turns.active} active`, `Duration: ${formatDuration(turns.cumulativeDurationMs)} total · ${formatDuration(turns.failedDurationMs)} in failed Turns`, `By role: ${turns.byRole.leader} leader · ${turns.byRole.reviewer} reviewer · ${turns.byRole.implementer} implementer/worker · ${turns.byRole.other} other`, `By purpose: ${turns.byPurpose.execution} execution · ${turns.byPurpose.review} review`);
|
|
98
|
+
const faultRows = Object.entries(turns.faultClasses)
|
|
99
99
|
.filter(([, count]) => count > 0)
|
|
100
100
|
.sort((left, right) => right[1] - left[1]);
|
|
101
101
|
if (faultRows.length > 0) {
|
|
102
|
-
lines.push(renderTable("
|
|
102
|
+
lines.push(renderTable("Turn failure classes", [
|
|
103
103
|
{ header: "Class", minWidth: 24, maxWidth: 40 },
|
|
104
104
|
{ header: "Count", minWidth: 5, maxWidth: 8 }
|
|
105
105
|
], faultRows.map(([name, count]) => [name, String(count)]), width));
|
|
106
106
|
}
|
|
107
|
-
if (
|
|
108
|
-
const phaseRows = Object.entries(
|
|
107
|
+
if (turns.launchFailures.total > 0) {
|
|
108
|
+
const phaseRows = Object.entries(turns.launchFailures.byPhase)
|
|
109
109
|
.filter(([, count]) => count > 0)
|
|
110
110
|
.sort((left, right) => right[1] - left[1]);
|
|
111
|
-
const kindRows = Object.entries(
|
|
111
|
+
const kindRows = Object.entries(turns.launchFailures.byKind)
|
|
112
112
|
.filter(([, count]) => count > 0)
|
|
113
113
|
.sort((left, right) => right[1] - left[1]);
|
|
114
|
-
lines.push("", `Launch failures: ${
|
|
114
|
+
lines.push("", `Launch failures: ${turns.launchFailures.total}`, `By phase: ${phaseRows.map(([name, count]) => `${name}=${count}`).join(" · ")}`, `By kind: ${kindRows.map(([name, count]) => `${name}=${count}`).join(" · ")}`);
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
117
|
else {
|
|
118
|
-
lines.push("", ...sectionError("
|
|
118
|
+
lines.push("", ...sectionError("turns", report));
|
|
119
119
|
}
|
|
120
120
|
if (report.wakes.status === "ok" && report.wakes.data !== undefined) {
|
|
121
121
|
const wakes = report.wakes.data;
|
|
122
|
-
lines.push("", `Leader wakes: ${wakes.
|
|
122
|
+
lines.push("", `Leader wakes: ${wakes.leaderTurns} Turns · ${wakes.withWakeReasons} with reasons`);
|
|
123
123
|
if (wakes.suppressedWakes.status === "ok") {
|
|
124
|
-
lines.push(`Suppressed wakes: ${wakes.suppressedWakes.data ?? 0} (scheduler single-flight, not failed
|
|
124
|
+
lines.push(`Suppressed wakes: ${wakes.suppressedWakes.data ?? 0} (scheduler single-flight, not failed Turns)`);
|
|
125
125
|
}
|
|
126
126
|
else if (wakes.suppressedWakes.status === "unsupported") {
|
|
127
127
|
lines.push("Suppressed wakes: unsupported (no quiescence producer in this build)");
|
|
@@ -140,10 +140,10 @@ export function renderExecutionAudit(report, width = defaultTableWidth()) {
|
|
|
140
140
|
if (report.sessions.status === "ok" && report.sessions.data !== undefined) {
|
|
141
141
|
const sessions = report.sessions.data;
|
|
142
142
|
lines.push("", `Sessions: ${sessions.generations} generations · ${sessions.broken} broken · ${sessions.stopped} stopped · ${sessions.other} other`, `Resets: ${sessions.resets} · Historical conversation switches ${sessions.conversationSwitches}`
|
|
143
|
-
+ ` · lifecycle events ${sessions.lifecycleEvents} · stop failures ${sessions.stopFailures}`, `Terminal by
|
|
144
|
-
+ ` · ${sessions.
|
|
145
|
-
+ ` · ${sessions.
|
|
146
|
-
+ ` · ${sessions.
|
|
143
|
+
+ ` · lifecycle events ${sessions.lifecycleEvents} · stop failures ${sessions.stopFailures}`, `Terminal by Turn relation: ${sessions.terminalByTurnRelation.postTurnCompleted} post-turn-completed`
|
|
144
|
+
+ ` · ${sessions.terminalByTurnRelation.turnFailed} turn-failed`
|
|
145
|
+
+ ` · ${sessions.terminalByTurnRelation.activeTurn} active-turn`
|
|
146
|
+
+ ` · ${sessions.terminalByTurnRelation.noTurn} no-turn`);
|
|
147
147
|
}
|
|
148
148
|
else {
|
|
149
149
|
lines.push("", ...sectionError("sessions", report));
|
|
@@ -190,14 +190,14 @@ export function renderExecutionAudit(report, width = defaultTableWidth()) {
|
|
|
190
190
|
.map(([category, count]) => `${category}:${count}`).join(", ")}`);
|
|
191
191
|
lines.push(renderTable("Agent errors", [
|
|
192
192
|
{ header: "Task", minWidth: 8, maxWidth: 14 },
|
|
193
|
-
{ header: "
|
|
193
|
+
{ header: "Turn", minWidth: 14, maxWidth: 24 },
|
|
194
194
|
{ header: "Role", minWidth: 8, maxWidth: 12 },
|
|
195
195
|
{ header: "Category", minWidth: 12, maxWidth: 20 },
|
|
196
196
|
{ header: "Code", minWidth: 16, maxWidth: 32 },
|
|
197
197
|
{ header: "Session", minWidth: 12, maxWidth: 16 }
|
|
198
198
|
], errors.entries.map((entry) => [
|
|
199
199
|
entry.taskId,
|
|
200
|
-
entry.
|
|
200
|
+
entry.turnId,
|
|
201
201
|
entry.roleName,
|
|
202
202
|
entry.category,
|
|
203
203
|
entry.code,
|
|
@@ -222,7 +222,7 @@ export function renderExecutionAudit(report, width = defaultTableWidth()) {
|
|
|
222
222
|
lines.push(renderTable("Task orchestration metrics", [
|
|
223
223
|
{ header: "Task", minWidth: 7, maxWidth: 14 },
|
|
224
224
|
{ header: "Type", minWidth: 8, maxWidth: 12 },
|
|
225
|
-
{ header: "
|
|
225
|
+
{ header: "Turns", minWidth: 4, maxWidth: 6 },
|
|
226
226
|
{ header: "WIs", minWidth: 3, maxWidth: 5 },
|
|
227
227
|
{ header: "Review F/D/N", minWidth: 12, maxWidth: 16 },
|
|
228
228
|
{ header: "Integration A/F/R", minWidth: 17, maxWidth: 20 },
|
|
@@ -232,7 +232,7 @@ export function renderExecutionAudit(report, width = defaultTableWidth()) {
|
|
|
232
232
|
], orchestration.tasks.map((task) => [
|
|
233
233
|
task.taskId,
|
|
234
234
|
task.taskType ?? "unspecified",
|
|
235
|
-
String(task.
|
|
235
|
+
String(task.turns.total),
|
|
236
236
|
String(task.workItems),
|
|
237
237
|
`${task.reviews.full}/${task.reviews.delta}/${task.reviews.nonSemantic}`,
|
|
238
238
|
`${task.integrations.attempts}/${task.integrations.failed}/${task.integrations.repeatedIdentities}`,
|
|
@@ -275,15 +275,15 @@ export function renderExecutionAudit(report, width = defaultTableWidth()) {
|
|
|
275
275
|
if (report.topLongRunning.status === "ok" && report.topLongRunning.data !== undefined) {
|
|
276
276
|
const entries = report.topLongRunning.data;
|
|
277
277
|
if (entries.length > 0) {
|
|
278
|
-
lines.push("", renderTable("Top long-running
|
|
278
|
+
lines.push("", renderTable("Top long-running Turns", [
|
|
279
279
|
{ header: "Task", minWidth: 8, maxWidth: 14 },
|
|
280
|
-
{ header: "
|
|
280
|
+
{ header: "Turn", minWidth: 14, maxWidth: 24 },
|
|
281
281
|
{ header: "Role", minWidth: 10, maxWidth: 20 },
|
|
282
282
|
{ header: "Status", minWidth: 8, maxWidth: 10 },
|
|
283
283
|
{ header: "Duration", minWidth: 8, maxWidth: 10 }
|
|
284
284
|
], entries.map((entry) => [
|
|
285
285
|
entry.taskId,
|
|
286
|
-
entry.
|
|
286
|
+
entry.turnId,
|
|
287
287
|
entry.roleName,
|
|
288
288
|
entry.status,
|
|
289
289
|
formatDuration(entry.durationMs)
|
|
@@ -80,12 +80,7 @@ function roleContext(args, store, options) {
|
|
|
80
80
|
: ["perform-global-role-request"]
|
|
81
81
|
},
|
|
82
82
|
sessionManifestPath: environment.YUI_SESSION_MANIFEST,
|
|
83
|
-
cliCommand: "yui"
|
|
84
|
-
// Compatibility hint for already-running Sessions. New instructions use
|
|
85
|
-
// the stable command name and do not bind behavior to this wrapper path.
|
|
86
|
-
...(environment.YUI_SESSION_CLI === undefined
|
|
87
|
-
? {}
|
|
88
|
-
: { legacySessionCliPath: environment.YUI_SESSION_CLI })
|
|
83
|
+
cliCommand: "yui"
|
|
89
84
|
});
|
|
90
85
|
if (options.jsonOutput === true)
|
|
91
86
|
return `${JSON.stringify(context)}\n`;
|
|
@@ -245,7 +240,7 @@ function bindRole(args, store) {
|
|
|
245
240
|
const activeSession = existingSet?.sessions[existingSet.activeAgentId];
|
|
246
241
|
try {
|
|
247
242
|
const switched = switchActiveRoleAgent(withBinding, existingSet ?? createRoleSessionSet({ scope: "global", roleName: name }, role.activeAgentId, now), agentId, {
|
|
248
|
-
|
|
243
|
+
activeTurn: false,
|
|
249
244
|
nativeProcessRunning: activeSession !== undefined
|
|
250
245
|
&& activeSession.status === "active"
|
|
251
246
|
}, now);
|
|
@@ -4,10 +4,7 @@ import { formatTimestamp } from "../output/timePresentation.js";
|
|
|
4
4
|
import { enqueueWork } from "../coordination/workMailboxQueue.js";
|
|
5
5
|
const WAKEUP_PREFIX = "leader-wakeup:";
|
|
6
6
|
const RECOVERY_PREFIX = "leader-recovery:";
|
|
7
|
-
/**
|
|
8
|
-
* A compatibility view over the two durable scheduler records. This does not
|
|
9
|
-
* reintroduce the deleted generic Job queue.
|
|
10
|
-
*/
|
|
7
|
+
/** Operational view over the two durable scheduler recovery records. */
|
|
11
8
|
export function runJobCommand(args, store, options = {}) {
|
|
12
9
|
const [command, ...rest] = args;
|
|
13
10
|
if (command === "list")
|
|
@@ -555,7 +555,7 @@ function assertNoActiveTaskBinding(store, project, action) {
|
|
|
555
555
|
if (references.activeTaskIds.length > 0) {
|
|
556
556
|
const delivery = [
|
|
557
557
|
...references.unresolvedWorkItemRefs,
|
|
558
|
-
...references.
|
|
558
|
+
...references.activeTurnRefs,
|
|
559
559
|
...references.unresolvedIntegrationRefs
|
|
560
560
|
];
|
|
561
561
|
throw usageError(`Project cannot be ${action} while an active Task binds it: ${project.id}. `
|
|
@@ -846,7 +846,7 @@ async function replaceProject(args, store, options) {
|
|
|
846
846
|
}
|
|
847
847
|
/**
|
|
848
848
|
* Auditable soft deprecation. The catalog record, checkout, and every
|
|
849
|
-
* historical Task/
|
|
849
|
+
* historical Task/Turn/Review/Integration/Publication reference are retained;
|
|
850
850
|
* the Project can no longer be bound to new work or maintained. Hard removal
|
|
851
851
|
* is a separate `project delete` decision.
|
|
852
852
|
*/
|
|
@@ -871,7 +871,7 @@ function retireProjectCommand(args, store, options) {
|
|
|
871
871
|
`Retired project ${retired.project.id} (${retired.project.name})`,
|
|
872
872
|
`Reason: ${parsed.reason}`,
|
|
873
873
|
`Retired by: ${retiredBy} at ${retired.project.retirement?.retiredAt ?? "?"}`,
|
|
874
|
-
"The catalog record, checkout, and historical Task/
|
|
874
|
+
"The catalog record, checkout, and historical Task/Turn/Review/Integration/Publication evidence are retained.",
|
|
875
875
|
...(retired.references.boundTaskIds.length === 0
|
|
876
876
|
? []
|
|
877
877
|
: [`Historical Task bindings retained: ${retired.references.boundTaskIds.join(", ")}.`]),
|
|
@@ -923,7 +923,7 @@ async function deleteProjectCommand(args, store, options) {
|
|
|
923
923
|
const tombstone = join(store.rootDirectory(), "projects", `.delete-${project.id}`);
|
|
924
924
|
const releaseMaintenance = acquireProjectMaintenanceLock(store.rootDirectory(), project.id);
|
|
925
925
|
try {
|
|
926
|
-
// Heal a crashed earlier attempt before the prechecks
|
|
926
|
+
// Heal a crashed earlier attempt before the prechecks turn.
|
|
927
927
|
await healCheckoutSwap({ currentPath: project.path, backupPath: tombstone });
|
|
928
928
|
if (existsSync(project.path)) {
|
|
929
929
|
const git = options.git ?? new NodeGitWorkspace();
|
|
@@ -998,7 +998,7 @@ function removeRetiredProjectRecord(store, projectId) {
|
|
|
998
998
|
if (references.boundTaskIds.length > 0) {
|
|
999
999
|
throw usageError(`Project cannot be deleted while Task records reference it: ${latest.id}. `
|
|
1000
1000
|
+ `Bound Tasks: ${references.boundTaskIds.join(", ")}. `
|
|
1001
|
-
+ "Historical Task/
|
|
1001
|
+
+ "Historical Task/Turn/Review/Integration/Publication evidence must stay resolvable; keep the Project retired instead.");
|
|
1002
1002
|
}
|
|
1003
1003
|
if (!tx.removeProject(latest.id)) {
|
|
1004
1004
|
throw new Error(`Project was already removed: ${latest.id}.`);
|
|
@@ -355,16 +355,9 @@ export function createReleaseActivatePorts(overrides = {}) {
|
|
|
355
355
|
throw new Error(`Release preflight produced no JSON (exit ${result.status}): `
|
|
356
356
|
+ `${messageOf(error)} ${result.stderr.trim()}`);
|
|
357
357
|
}
|
|
358
|
-
// The handover preflight
|
|
359
|
-
//
|
|
360
|
-
//
|
|
361
|
-
// current, compatible-old, and migration-required (MIGRATABLE) Homes,
|
|
362
|
-
// and non-ok for needs-new-version or corrupted Homes. The strict
|
|
363
|
-
// `storage schema` check reads `unsupported` for a MIGRATABLE Home even
|
|
364
|
-
// though the Controller opens it through the compatible migration path,
|
|
365
|
-
// so gating on it would reject every older-but-upgradable Home. A
|
|
366
|
-
// missing `storage state` (a Home that never ran `yui setup`) is not a
|
|
367
|
-
// compatibility blocker — the new Controller initializes it.
|
|
358
|
+
// The handover preflight must prove the exact current Home contract.
|
|
359
|
+
// Older, newer, malformed, or incomplete Homes all fail closed and are
|
|
360
|
+
// never normalized by release activation.
|
|
368
361
|
const checks = report?.checks;
|
|
369
362
|
if (!Array.isArray(checks)) {
|
|
370
363
|
throw new Error("Release preflight report has no storage checks.");
|
|
@@ -123,11 +123,11 @@ function collectTaskStatuses(store) {
|
|
|
123
123
|
}
|
|
124
124
|
return statuses;
|
|
125
125
|
}
|
|
126
|
-
/** Workspace paths claimed by active durable Jobs (
|
|
126
|
+
/** Workspace paths claimed by active durable Jobs (Turns). */
|
|
127
127
|
function collectActiveWorkspaceOwnerPaths(store) {
|
|
128
128
|
const paths = [];
|
|
129
129
|
for (const task of store.listTasks()) {
|
|
130
|
-
for (const run of store.
|
|
130
|
+
for (const run of store.listTurns(task.id)) {
|
|
131
131
|
if (run.status !== "active")
|
|
132
132
|
continue;
|
|
133
133
|
const workspace = run.workspace;
|
|
@@ -28,7 +28,7 @@ export async function runSessionStopCommand(input) {
|
|
|
28
28
|
// lifecycle work that may exist without a current Session candidate.
|
|
29
29
|
await input.runtime.drainController();
|
|
30
30
|
await input.runtime.stopController();
|
|
31
|
-
// Re-read the authoritative facts after the drain because a
|
|
31
|
+
// Re-read the authoritative facts after the drain because a Turn that was
|
|
32
32
|
// already inside a pass may have changed state meanwhile.
|
|
33
33
|
const settled = input.runtime.snapshot();
|
|
34
34
|
const blockedAfterDrain = blockedSessions(settled);
|
|
@@ -80,7 +80,7 @@ function blockedSessions(input) {
|
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
82
|
function blockedStopResult(blocked) {
|
|
83
|
-
const details = blocked.map(({ session }) => (`- ${renderSessionOwner(session)} (an active
|
|
83
|
+
const details = blocked.map(({ session }) => (`- ${renderSessionOwner(session)} (an active Turn or lifecycle operation is still pending)`));
|
|
84
84
|
return {
|
|
85
85
|
output: [
|
|
86
86
|
`Cannot stop managed Sessions: ${blocked.length} Session(s) are still busy.`,
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { usageError } from "../errors/cliError.js";
|
|
2
2
|
import { activeRoleAgentBinding } from "../role/role.js";
|
|
3
|
-
import {
|
|
4
|
-
import { agentRunDeliveryReceiptId } from "../run/agentRun.js";
|
|
3
|
+
import { managedProviderTurnId } from "../runtime/providerRuntimeIdentity.js";
|
|
5
4
|
const LEADER_ROLE = "leader";
|
|
6
|
-
const LEADER_ACTION_RUN_ENV = "
|
|
5
|
+
const LEADER_ACTION_RUN_ENV = "YUI_LEADER_ACTION_TURN_ID";
|
|
7
6
|
const LEADER_ACTION_RECEIPT_ENV = "YUI_LEADER_ACTION_RECEIPT_ID";
|
|
8
7
|
/** rr13: Per-Session DurableJob caller key injected at native Session launch. */
|
|
9
8
|
const JOB_CALLER_KEY_ENV = "YUI_JOB_CALLER_KEY";
|
|
@@ -24,7 +23,7 @@ export function taskActor(environment, taskId) {
|
|
|
24
23
|
}
|
|
25
24
|
if (env.YUI_ROLE !== undefined
|
|
26
25
|
|| env.YUI_AGENT_ID !== undefined
|
|
27
|
-
|| env.
|
|
26
|
+
|| env.YUI_TURN_ID !== undefined
|
|
28
27
|
|| env.YUI_NATIVE_SESSION_ID !== undefined) {
|
|
29
28
|
throw usageError("Managed Agent identity is incomplete; refusing to infer user authority.");
|
|
30
29
|
}
|
|
@@ -34,17 +33,15 @@ export function taskActor(environment, taskId) {
|
|
|
34
33
|
* Resolve authority for a recoverable Task-local mutation. A managed Leader
|
|
35
34
|
* does not gain that authority from long-lived process environment alone: the
|
|
36
35
|
* command must carry the exact current Turn assertion and it must still match
|
|
37
|
-
* the durable active
|
|
36
|
+
* the durable active Turn, receipt, Role binding, native Session, and Home.
|
|
38
37
|
* Plain-user and global-Operator behavior remains unchanged.
|
|
39
38
|
*/
|
|
40
39
|
export function taskLocalActor(store, environment, taskId, yuiHome) {
|
|
41
40
|
const actor = taskActor(environment, taskId);
|
|
42
41
|
if (actor !== "leader")
|
|
43
42
|
return actor;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|| taskLeaderActionRunId(store, taskId, environment, yuiHome) === undefined) {
|
|
47
|
-
throw usageError(`Task-local Leader authority requires the exact current-Turn assertion: ${taskId}.`);
|
|
43
|
+
if (taskLeaderActionTurnId(store, taskId, environment, yuiHome) === undefined) {
|
|
44
|
+
throw usageError(`Task-local Leader authority requires the current Provider Turn: ${taskId}.`);
|
|
48
45
|
}
|
|
49
46
|
return actor;
|
|
50
47
|
}
|
|
@@ -59,7 +56,7 @@ export function projectActor(environment) {
|
|
|
59
56
|
}
|
|
60
57
|
if (env.YUI_ROLE !== undefined
|
|
61
58
|
|| env.YUI_AGENT_ID !== undefined
|
|
62
|
-
|| env.
|
|
59
|
+
|| env.YUI_TURN_ID !== undefined
|
|
63
60
|
|| env.YUI_NATIVE_SESSION_ID !== undefined) {
|
|
64
61
|
throw usageError("Managed Agent identity is incomplete; refusing to infer user authority.");
|
|
65
62
|
}
|
|
@@ -72,8 +69,8 @@ export function projectActor(environment) {
|
|
|
72
69
|
*
|
|
73
70
|
* rr12: The identity is now Controller-verified rather than self-reported:
|
|
74
71
|
* - A managed Task Session (`YUI_SESSION_SCOPE=task`) returns `scope: "task"`
|
|
75
|
-
* with its Role and
|
|
76
|
-
* preferred over a possibly stale `
|
|
72
|
+
* with its Role and Turn. For a Leader, the explicit current Turn id is
|
|
73
|
+
* preferred over a possibly stale `YUI_TURN_ID`.
|
|
77
74
|
*
|
|
78
75
|
* rr13: A managed Task Session also carries `callerKey` — the
|
|
79
76
|
* `YUI_JOB_CALLER_KEY` injected at its native Session launch. The Controller
|
|
@@ -83,7 +80,7 @@ export function projectActor(environment) {
|
|
|
83
80
|
* managed global Agent carries its own durable Session identity.
|
|
84
81
|
*
|
|
85
82
|
* A managed Task Session may only start jobs for its own Task. An incomplete
|
|
86
|
-
* managed identity (role/agent/
|
|
83
|
+
* managed identity (role/agent/Turn/Session vars without a scope) is rejected
|
|
87
84
|
* rather than silently downgraded to user authority.
|
|
88
85
|
*/
|
|
89
86
|
export function resolveJobCaller(environment, taskId) {
|
|
@@ -98,14 +95,14 @@ export function resolveJobCaller(environment, taskId) {
|
|
|
98
95
|
// Controller boundary.
|
|
99
96
|
const callerKey = env[JOB_CALLER_KEY_ENV];
|
|
100
97
|
if (role === LEADER_ROLE) {
|
|
101
|
-
// Prefer the explicit current
|
|
98
|
+
// Prefer the explicit current Turn over a possibly stale YUI_TURN_ID.
|
|
102
99
|
const assertion = leaderActionAssertion(env);
|
|
103
100
|
if (assertion !== undefined && assertion !== "invalid") {
|
|
104
101
|
return {
|
|
105
102
|
scope: "task",
|
|
106
103
|
taskId,
|
|
107
104
|
role,
|
|
108
|
-
|
|
105
|
+
turnId: assertion.turnId,
|
|
109
106
|
...(callerKey === undefined ? {} : { callerKey })
|
|
110
107
|
};
|
|
111
108
|
}
|
|
@@ -114,7 +111,7 @@ export function resolveJobCaller(environment, taskId) {
|
|
|
114
111
|
scope: "task",
|
|
115
112
|
taskId,
|
|
116
113
|
role,
|
|
117
|
-
...(env.
|
|
114
|
+
...(env.YUI_TURN_ID === undefined ? {} : { turnId: env.YUI_TURN_ID }),
|
|
118
115
|
...(callerKey === undefined ? {} : { callerKey })
|
|
119
116
|
};
|
|
120
117
|
}
|
|
@@ -130,25 +127,25 @@ export function resolveJobCaller(environment, taskId) {
|
|
|
130
127
|
}
|
|
131
128
|
if (env.YUI_ROLE !== undefined
|
|
132
129
|
|| env.YUI_AGENT_ID !== undefined
|
|
133
|
-
|| env.
|
|
130
|
+
|| env.YUI_TURN_ID !== undefined
|
|
134
131
|
|| env.YUI_NATIVE_SESSION_ID !== undefined) {
|
|
135
132
|
throw usageError("Managed Agent identity is incomplete; refusing to infer user authority.");
|
|
136
133
|
}
|
|
137
134
|
return { scope: "user" };
|
|
138
135
|
}
|
|
139
136
|
/**
|
|
140
|
-
* Resolve an exact current Task Leader
|
|
137
|
+
* Resolve an exact current Task Leader Turn for event attribution.
|
|
141
138
|
*
|
|
142
139
|
* Task commands may be invoked by a managed process whose environment is
|
|
143
|
-
* stale, incomplete, or copied from another
|
|
144
|
-
* enough: the active durable
|
|
140
|
+
* stale, incomplete, or copied from another Turn. A bare YUI_TURN_ID is never
|
|
141
|
+
* enough: the active durable Turn, Role, in-flight receipt, native Session,
|
|
145
142
|
* launch generation, and (when supplied) Home must all agree before an
|
|
146
143
|
* allowlisted lifecycle event can buy a Leader action window. A fixed native
|
|
147
|
-
* Session may keep an earlier
|
|
144
|
+
* Session may keep an earlier Turn/launch in its process environment; in that
|
|
148
145
|
* case the current Leader turn must explicitly carry the exact durable
|
|
149
|
-
*
|
|
146
|
+
* Turn/receipt pair through the two command-only assertion variables below.
|
|
150
147
|
*/
|
|
151
|
-
export function
|
|
148
|
+
export function taskLeaderActionTurnId(store, taskId, environment, yuiHome) {
|
|
152
149
|
const env = environment ?? {};
|
|
153
150
|
if (env.YUI_SESSION_SCOPE !== "task" || env.YUI_ROLE !== LEADER_ROLE)
|
|
154
151
|
return undefined;
|
|
@@ -158,12 +155,13 @@ export function taskLeaderActionRunId(store, taskId, environment, yuiHome) {
|
|
|
158
155
|
if (environmentAssertion === "invalid")
|
|
159
156
|
return undefined;
|
|
160
157
|
const explicitAssertion = environmentAssertion === undefined ? undefined : environmentAssertion;
|
|
161
|
-
const
|
|
158
|
+
const observedTurnTurnId = managedProviderTurnId(store.getTaskRoleSessionSet(taskId, LEADER_ROLE)?.providerBinding?.turn) ?? undefined;
|
|
159
|
+
const turnId = explicitAssertion?.turnId ?? observedTurnTurnId ?? identity(env.YUI_TURN_ID);
|
|
162
160
|
const agentId = identity(env.YUI_AGENT_ID);
|
|
163
161
|
const adapterId = identity(env.YUI_ADAPTER_ID);
|
|
164
162
|
const launchId = identity(env.YUI_LAUNCH_ID);
|
|
165
163
|
const home = identity(env.YUI_HOME);
|
|
166
|
-
if (
|
|
164
|
+
if (turnId === undefined
|
|
167
165
|
|| agentId === undefined
|
|
168
166
|
|| adapterId === undefined
|
|
169
167
|
|| launchId === undefined
|
|
@@ -178,12 +176,12 @@ export function taskLeaderActionRunId(store, taskId, environment, yuiHome) {
|
|
|
178
176
|
if (yuiHome === undefined && storeHome !== undefined && home !== storeHome)
|
|
179
177
|
return undefined;
|
|
180
178
|
const role = store.getRole(taskId, LEADER_ROLE);
|
|
181
|
-
const run = store.
|
|
179
|
+
const run = store.getActiveTurn(taskId, LEADER_ROLE);
|
|
182
180
|
const sessions = store.getTaskRoleSessionSet(taskId, LEADER_ROLE);
|
|
183
181
|
if (role === null
|
|
184
182
|
|| run === null
|
|
185
183
|
|| run.status !== "active"
|
|
186
|
-
|| run.id !==
|
|
184
|
+
|| run.id !== turnId
|
|
187
185
|
|| run.taskId !== taskId
|
|
188
186
|
|| run.roleName !== LEADER_ROLE
|
|
189
187
|
|| run.effective.agentId !== agentId
|
|
@@ -195,13 +193,7 @@ export function taskLeaderActionRunId(store, taskId, environment, yuiHome) {
|
|
|
195
193
|
|| sessions.owner.taskId !== taskId
|
|
196
194
|
|| sessions.owner.roleName !== LEADER_ROLE
|
|
197
195
|
|| sessions.activeAgentId !== agentId
|
|
198
|
-
|| sessions.
|
|
199
|
-
|| sessions.inFlight.runId !== runId
|
|
200
|
-
|| sessions.inFlight.agentId !== agentId
|
|
201
|
-
|| sessions.inFlight.receiptId !== agentRunDeliveryReceiptId(run))
|
|
202
|
-
return undefined;
|
|
203
|
-
if (explicitAssertion !== undefined
|
|
204
|
-
&& explicitAssertion.receiptId !== formatAgentRunReceiptId(taskId, runId))
|
|
196
|
+
|| managedProviderTurnId(sessions.providerBinding?.turn) !== turnId)
|
|
205
197
|
return undefined;
|
|
206
198
|
const session = sessions.sessions[agentId];
|
|
207
199
|
if (session === undefined
|
|
@@ -217,15 +209,15 @@ export function taskLeaderActionRunId(store, taskId, environment, yuiHome) {
|
|
|
217
209
|
return run.id;
|
|
218
210
|
}
|
|
219
211
|
function leaderActionAssertion(environment) {
|
|
220
|
-
const
|
|
212
|
+
const turnId = environment[LEADER_ACTION_RUN_ENV];
|
|
221
213
|
const receiptId = environment[LEADER_ACTION_RECEIPT_ENV];
|
|
222
|
-
if (
|
|
214
|
+
if (turnId === undefined && receiptId === undefined)
|
|
223
215
|
return undefined;
|
|
224
|
-
const
|
|
216
|
+
const normalizedTurnId = identity(turnId);
|
|
225
217
|
const normalizedReceiptId = identity(receiptId);
|
|
226
|
-
return
|
|
218
|
+
return normalizedTurnId === undefined || normalizedReceiptId === undefined
|
|
227
219
|
? "invalid"
|
|
228
|
-
: {
|
|
220
|
+
: { turnId: normalizedTurnId, receiptId: normalizedReceiptId };
|
|
229
221
|
}
|
|
230
222
|
function identity(value) {
|
|
231
223
|
if (typeof value !== "string" || value.includes("\0"))
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { usageError } from "../errors/cliError.js";
|
|
2
2
|
import { resolveTaskRecordReference } from "../task/taskRecordReference.js";
|
|
3
|
-
/**
|
|
4
|
-
* Read-only ChangeSet inspection, including its optional integration manifest.
|
|
5
|
-
*/
|
|
3
|
+
/** Read-only ChangeSet inspection, including its integration manifest. */
|
|
6
4
|
export async function runTaskChangeSetCommand(args, store) {
|
|
7
5
|
const [command, ...rest] = args;
|
|
8
6
|
if (command === "show")
|
|
@@ -47,14 +45,9 @@ function renderChangeSet(changeSet) {
|
|
|
47
45
|
...changeSet.changedPaths.map((path) => ` ${path}`),
|
|
48
46
|
`Created: ${changeSet.createdAt}`
|
|
49
47
|
];
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const manifest = changeSet.manifest;
|
|
55
|
-
lines.push("Manifest:", ` Tags: ${manifest.tags.join(", ")}`, ` Deleted paths: ${manifest.deletedPaths.length}`, ...manifest.deletedPaths.map((path) => ` ${path}`), ` Target: ${manifest.targetRef ?? "-"}`, ` Evidence: ${manifest.evidenceRefs.length === 0
|
|
56
|
-
? "-"
|
|
57
|
-
: manifest.evidenceRefs.join(", ")}`);
|
|
58
|
-
}
|
|
48
|
+
const manifest = changeSet.manifest;
|
|
49
|
+
lines.push("Manifest:", ` Tags: ${manifest.tags.join(", ")}`, ` Deleted paths: ${manifest.deletedPaths.length}`, ...manifest.deletedPaths.map((path) => ` ${path}`), ` Target: ${manifest.targetRef ?? "-"}`, ` Evidence: ${manifest.evidenceRefs.length === 0
|
|
50
|
+
? "-"
|
|
51
|
+
: manifest.evidenceRefs.join(", ")}`);
|
|
59
52
|
return `${lines.join("\n")}\n`;
|
|
60
53
|
}
|