@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,11 +1,11 @@
|
|
|
1
1
|
import { isDeepStrictEqual } from "node:util";
|
|
2
|
-
import { agentNotFound, usageError } from "../errors/cliError.js";
|
|
3
|
-
import { defaultTableWidth, renderTable } from "../output/table.js";
|
|
4
2
|
import { isAgentAdapterId, supportedAgentAdapterIds } from "../agent/adapterCatalog.js";
|
|
5
|
-
import { adapterIdForExecutionComponent, agentExecutionComponentLabel, defaultExecutionComponentForAdapter, isAgentExecutionComponentId, supportedAgentExecutionComponentIds } from "../agent/executionComponents.js";
|
|
6
3
|
import { createConfiguredAgent, validateConfiguredAgent } from "../agent/agent.js";
|
|
7
|
-
import {
|
|
4
|
+
import { adapterIdForExecutionComponent, agentExecutionComponentLabel, defaultExecutionComponentForAdapter, isAgentExecutionComponentId, supportedAgentExecutionComponentIds } from "../agent/executionComponents.js";
|
|
5
|
+
import { agentNotFound, usageError } from "../errors/cliError.js";
|
|
6
|
+
import { defaultTableWidth, renderTable } from "../output/table.js";
|
|
8
7
|
import { hasRuntimeLifecycleWork, runtimeLifecycleTarget } from "../runtime/lifecycleReservation.js";
|
|
8
|
+
import { LIVE_SESSION_ACKNOWLEDGEMENT_OPTION } from "./roleRuntimeGuard.js";
|
|
9
9
|
export function runAgentCommand(args, store) {
|
|
10
10
|
const [command, ...rest] = args;
|
|
11
11
|
switch (command) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { usageError } from "../errors/cliError.js";
|
|
2
|
-
import { resolveJobCaller } from "
|
|
2
|
+
import { resolveJobCaller } from "../task/taskAuthority.js";
|
|
3
3
|
import { callFileTaskController } from "../controller/clientRuntime.js";
|
|
4
4
|
export async function runCapabilityCommand(args, home, environment) {
|
|
5
5
|
const [action, ...rest] = args;
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { mkdirSync, realpathSync } from "node:fs";
|
|
2
2
|
import { isAbsolute, relative, resolve } from "node:path";
|
|
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_RUNS, 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, resolveLeaderSemanticBudgetRuns, resolveResourcesGcAutoQuarantine, resolveResourcesGcMode, resolveResourcesQuarantineTtlHours, resolveRuntimeHealth, resolveTelemetryEnabled, resolveTelemetryRunCap, resolveTelemetryTerminalKeep, resolveTmuxBin, resolveTmuxHistoryLimit } from "../config/yuiConfig.js";
|
|
5
3
|
import { CONFIG_DEFINITIONS, CONFIG_KEYS, configDefinition, configDefinitionsForDomain } from "../config/configCatalog.js";
|
|
6
|
-
import { resolveTimeZone } from "../
|
|
4
|
+
import { resolveTimeZone } from "../config/timeZone.js";
|
|
5
|
+
import { DEFAULT_AGENT_LAUNCH_INACTIVITY_TIMEOUT_SECONDS, DEFAULT_CONTROLLER_TASK_CONCURRENCY, DEFAULT_DELIVERY_TIMEOUT_SECONDS, DEFAULT_RECONCILIATION_INTERVAL_SECONDS, DEFAULT_RESOURCES_GC_MODE, DEFAULT_RESOURCES_QUARANTINE_TTL_HOURS, DEFAULT_TMUX_HISTORY_LIMIT, reconciliationIntervalMilliseconds, resolveAgentLaunchInactivityTimeoutSeconds, resolveControllerTaskConcurrency, resolveDeliveryTimeoutSeconds, resolveResourcesGcAutoQuarantine, resolveResourcesGcMode, resolveResourcesQuarantineTtlHours, resolveRuntimeHealth, resolveTelemetryEnabled, resolveTelemetryRunCap, resolveTelemetryTerminalKeep, resolveTmuxBin, resolveTmuxHistoryLimit } from "../config/yuiConfig.js";
|
|
6
|
+
import { usageError } from "../errors/cliError.js";
|
|
7
7
|
import { defaultTableWidth, renderTable } from "../output/table.js";
|
|
8
8
|
import { REVIEW_TRIGGERS } from "../review/reviewConfig.js";
|
|
9
9
|
/**
|
|
10
10
|
* One uniform key model for every durable setting. Each catalog domain uses
|
|
11
|
-
* the same show/set/clear contract
|
|
12
|
-
* `leader-next-action` are keys like any other.
|
|
11
|
+
* the same show/set/clear contract, including the explicit review policy.
|
|
13
12
|
*/
|
|
14
13
|
export { CONFIG_KEYS } from "../config/configCatalog.js";
|
|
15
14
|
const CONFIG_PROPERTIES = Object.fromEntries(CONFIG_DEFINITIONS.map(({ key, property }) => [
|
|
@@ -20,7 +19,6 @@ const TIME_ZONE_SET_USAGE = "System config set usage: yui config system set time
|
|
|
20
19
|
const RECONCILIATION_SET_USAGE = "Runtime config set usage: yui config runtime set reconciliation-interval-seconds <5-300>.";
|
|
21
20
|
const RESOURCES_GC_MODE_SET_USAGE = "Resources config set usage: yui config resources set resources-gc-mode <report|quarantine>.";
|
|
22
21
|
const RESOURCES_GC_AUTO_QUARANTINE_SET_USAGE = "Resources config set usage: yui config resources set resources-gc-auto-quarantine <true|false>.";
|
|
23
|
-
const LEADER_NEXT_ACTION_SET_USAGE = `Workflow config set usage: yui config workflow set leader-next-action <${LEADER_NEXT_ACTION_MODES.join("|")}>.`;
|
|
24
22
|
const REVIEW_SET_USAGE = "Workflow config set usage: yui config workflow set review --role <global-role> --trigger <always|leader|final>.";
|
|
25
23
|
export function runConfigCommand(domain, args, store) {
|
|
26
24
|
const keys = configDefinitionsForDomain(domain).map(({ key }) => key);
|
|
@@ -65,7 +63,6 @@ export function effectiveConfigData(config, domain) {
|
|
|
65
63
|
lastTaskId: config.lastTaskId ?? null,
|
|
66
64
|
reconciliationIntervalSeconds: config.reconciliationIntervalSeconds
|
|
67
65
|
?? DEFAULT_RECONCILIATION_INTERVAL_SECONDS,
|
|
68
|
-
leaderNextActionMode: resolveLeaderNextActionMode(config.leaderNextActionMode),
|
|
69
66
|
resourcesGcMode: resolveResourcesGcMode(config.resourcesGcMode),
|
|
70
67
|
resourcesGcAutoQuarantine: resolveResourcesGcAutoQuarantine(config.resourcesGcAutoQuarantine),
|
|
71
68
|
resourcesQuarantineTtlHours: resolveResourcesQuarantineTtlHours(config.resourcesQuarantineTtlHours),
|
|
@@ -77,7 +74,6 @@ export function effectiveConfigData(config, domain) {
|
|
|
77
74
|
controllerTaskConcurrency: resolveControllerTaskConcurrency(config.controllerTaskConcurrency),
|
|
78
75
|
agentLaunchInactivityTimeoutSeconds: resolveAgentLaunchInactivityTimeoutSeconds(config.agentLaunchInactivityTimeoutSeconds),
|
|
79
76
|
deliveryTimeoutSeconds: resolveDeliveryTimeoutSeconds(config.deliveryTimeoutSeconds),
|
|
80
|
-
leaderSemanticBudgetRuns: resolveLeaderSemanticBudgetRuns(config.leaderSemanticBudgetRuns),
|
|
81
77
|
tmuxBin: resolveTmuxBin(config.tmuxBin),
|
|
82
78
|
tmuxHistoryLimit: resolveTmuxHistoryLimit(config.tmuxHistoryLimit),
|
|
83
79
|
telemetryEnabled: resolveTelemetryEnabled(config.telemetryEnabled),
|
|
@@ -164,7 +160,7 @@ const CONFIG_KEY_HANDLERS = [
|
|
|
164
160
|
throw usageError("System config set usage: yui config system set default-agent <agent-id>.");
|
|
165
161
|
}
|
|
166
162
|
const defaultAgent = args[0].trim();
|
|
167
|
-
if (store.getConfiguredAgent
|
|
163
|
+
if (store.getConfiguredAgent(defaultAgent) === null) {
|
|
168
164
|
throw usageError(`Configured Agent not found: ${defaultAgent}.`);
|
|
169
165
|
}
|
|
170
166
|
saveConfigKey(store, (config) => ({ ...config, defaultAgent }));
|
|
@@ -237,51 +233,6 @@ const CONFIG_KEY_HANDLERS = [
|
|
|
237
233
|
return `Reconciliation interval reset to ${DEFAULT_RECONCILIATION_INTERVAL_SECONDS} seconds\n`;
|
|
238
234
|
}
|
|
239
235
|
},
|
|
240
|
-
{
|
|
241
|
-
key: "leader-next-action",
|
|
242
|
-
showLabel: "Leader next-action mode",
|
|
243
|
-
showValue: (config) => resolveLeaderNextActionMode(config.leaderNextActionMode),
|
|
244
|
-
set(args, store) {
|
|
245
|
-
if (args.length !== 1)
|
|
246
|
-
throw usageError(LEADER_NEXT_ACTION_SET_USAGE);
|
|
247
|
-
let mode;
|
|
248
|
-
try {
|
|
249
|
-
mode = resolveLeaderNextActionMode(args[0]);
|
|
250
|
-
}
|
|
251
|
-
catch (error) {
|
|
252
|
-
throw usageError(error instanceof Error ? error.message : String(error), LEADER_NEXT_ACTION_SET_USAGE);
|
|
253
|
-
}
|
|
254
|
-
saveConfigKey(store, (config) => ({ ...config, leaderNextActionMode: mode }));
|
|
255
|
-
return `Leader next-action mode set to ${mode}\n`;
|
|
256
|
-
},
|
|
257
|
-
clear(store) {
|
|
258
|
-
saveConfigKey(store, (config) => {
|
|
259
|
-
const { leaderNextActionMode: _removed, ...rest } = config;
|
|
260
|
-
return rest;
|
|
261
|
-
});
|
|
262
|
-
return `Leader next-action mode reset to ${DEFAULT_LEADER_NEXT_ACTION_MODE}\n`;
|
|
263
|
-
}
|
|
264
|
-
},
|
|
265
|
-
{
|
|
266
|
-
key: "leader-semantic-budget-runs",
|
|
267
|
-
showLabel: "Leader semantic budget",
|
|
268
|
-
showValue: (config) => `${resolveLeaderSemanticBudgetRuns(config.leaderSemanticBudgetRuns)} runs`,
|
|
269
|
-
set(args, store) {
|
|
270
|
-
const usage = "Workflow config set usage: yui config workflow set leader-semantic-budget-runs <1-20>.";
|
|
271
|
-
if (args.length !== 1)
|
|
272
|
-
throw usageError(usage);
|
|
273
|
-
const leaderSemanticBudgetRuns = validatedConfigValue(() => resolveLeaderSemanticBudgetRuns(Number(args[0])), usage);
|
|
274
|
-
saveConfigKey(store, (config) => ({ ...config, leaderSemanticBudgetRuns }));
|
|
275
|
-
return `Leader semantic budget set to ${leaderSemanticBudgetRuns} runs\n`;
|
|
276
|
-
},
|
|
277
|
-
clear(store) {
|
|
278
|
-
saveConfigKey(store, (config) => {
|
|
279
|
-
const { leaderSemanticBudgetRuns: _removed, ...rest } = config;
|
|
280
|
-
return rest;
|
|
281
|
-
});
|
|
282
|
-
return `Leader semantic budget reset to ${DEFAULT_LEADER_SEMANTIC_BUDGET_RUNS} runs\n`;
|
|
283
|
-
}
|
|
284
|
-
},
|
|
285
236
|
{
|
|
286
237
|
key: "resources-gc-mode",
|
|
287
238
|
showLabel: "Resources GC mode",
|
|
@@ -565,7 +516,7 @@ const CONFIG_KEY_HANDLERS = [
|
|
|
565
516
|
|| !REVIEW_TRIGGERS.includes(rawTrigger)) {
|
|
566
517
|
throw usageError(REVIEW_SET_USAGE);
|
|
567
518
|
}
|
|
568
|
-
if (store.getGlobalRole
|
|
519
|
+
if (store.getGlobalRole(roleName) === null) {
|
|
569
520
|
throw usageError(`Global Role not found: ${roleName}.`);
|
|
570
521
|
}
|
|
571
522
|
const trigger = rawTrigger;
|
|
@@ -598,8 +549,6 @@ if (missingConfigHandlers.length > 0 || duplicateConfigHandlers.length > 0) {
|
|
|
598
549
|
}
|
|
599
550
|
function resolveDefaultWorkspace(value, store) {
|
|
600
551
|
const requested = resolve(value);
|
|
601
|
-
if (store.rootDirectory === undefined)
|
|
602
|
-
return requested;
|
|
603
552
|
const requestedHome = resolve(store.rootDirectory());
|
|
604
553
|
assertWorkspaceOutsideHome(requested, requestedHome);
|
|
605
554
|
mkdirSync(requested, { recursive: true, mode: 0o700 });
|
|
@@ -12,7 +12,7 @@ import { CONFIG_DOMAINS } from "../config/configCatalog.js";
|
|
|
12
12
|
* therefore explain what the user sees without reconstructing configuration
|
|
13
13
|
* from help text or implementation defaults.
|
|
14
14
|
*/
|
|
15
|
-
export function runConfigOverview(args, store, environment,
|
|
15
|
+
export function runConfigOverview(args, store, environment, roleOptions) {
|
|
16
16
|
if (args.length !== 0)
|
|
17
17
|
throw usageError("Config show usage: yui config show.");
|
|
18
18
|
const domains = Object.fromEntries(CONFIG_DOMAINS.map((domain) => [
|
|
@@ -27,7 +27,7 @@ export function runConfigOverview(args, store, environment, identity, roleOption
|
|
|
27
27
|
]));
|
|
28
28
|
const profileResult = runProfileCommand(["list"], store);
|
|
29
29
|
const profiles = profileResult.data.profiles;
|
|
30
|
-
const completion = inspectCompletionStates(store.getConfig(), environment
|
|
30
|
+
const completion = inspectCompletionStates(store.getConfig(), environment);
|
|
31
31
|
const roleOutput = runGlobalRoleCommand(["list"], store, roleOptions);
|
|
32
32
|
if (typeof roleOutput !== "string") {
|
|
33
33
|
throw new Error("Config overview received an invalid Role control result.");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { usageError } from "../errors/cliError.js";
|
|
2
2
|
import { ensureFileTaskController } from "../controller/clientRuntime.js";
|
|
3
3
|
import { acknowledgeDurableJob, cancelDurableJob, getDurableJob, startDurableJob } from "../controller/jobClient.js";
|
|
4
|
-
import { resolveJobCaller, taskLocalActor } from "
|
|
4
|
+
import { resolveJobCaller, taskLocalActor } from "../task/taskAuthority.js";
|
|
5
5
|
/**
|
|
6
6
|
* The textual `--owner` forms accepted by `job start`. The public help text in
|
|
7
7
|
* the command catalog must document exactly these forms.
|
|
@@ -25,7 +25,7 @@ export async function runDurableJobCommand(args, options) {
|
|
|
25
25
|
throw usageError(command === undefined
|
|
26
26
|
? "Job command is required: start, get, cancel, or acknowledge."
|
|
27
27
|
: `Unknown command: job ${command}`, "yui job start --task <id> --project <project> --head <sha> --workspace <dir> "
|
|
28
|
-
+ "--step <name>=<command> [--step ...] [--env K=V ...] "
|
|
28
|
+
+ "--request-id <id> --step <name>=<command> [--step ...] [--env K=V ...] "
|
|
29
29
|
+ `[--owner ${JOB_OWNER_USAGE}] [--retry-of <job-id>]\n`
|
|
30
30
|
+ "yui job get --task <id> --job <job-id>\n"
|
|
31
31
|
+ "yui job cancel --task <id> --job <job-id>\n"
|
|
@@ -36,6 +36,7 @@ async function startJob(args, options) {
|
|
|
36
36
|
await ensureFileTaskController(options.home, { environment: options.environment });
|
|
37
37
|
const caller = resolveJobCaller(options.environment, parsed.taskId);
|
|
38
38
|
const params = {
|
|
39
|
+
requestId: parsed.requestId,
|
|
39
40
|
taskId: parsed.taskId,
|
|
40
41
|
owner: parsed.owner,
|
|
41
42
|
projectId: parsed.projectId,
|
|
@@ -54,8 +55,9 @@ async function startJob(args, options) {
|
|
|
54
55
|
}
|
|
55
56
|
async function getJob(args, options) {
|
|
56
57
|
const ref = parseRefArgs(args, "get");
|
|
58
|
+
const caller = resolveJobCaller(options.environment, ref.taskId);
|
|
57
59
|
await ensureFileTaskController(options.home, { environment: options.environment });
|
|
58
|
-
const job = await getDurableJob(options.home, ref.taskId, ref.jobId);
|
|
60
|
+
const job = await getDurableJob(options.home, ref.taskId, ref.jobId, caller);
|
|
59
61
|
if (options.json === true)
|
|
60
62
|
return `${JSON.stringify(job, null, 2)}\n`;
|
|
61
63
|
const lines = [
|
|
@@ -111,6 +113,7 @@ async function acknowledgeJob(args, options) {
|
|
|
111
113
|
}
|
|
112
114
|
function parseStartArgs(args) {
|
|
113
115
|
let taskId;
|
|
116
|
+
let requestId;
|
|
114
117
|
let projectId;
|
|
115
118
|
let head;
|
|
116
119
|
let workspace;
|
|
@@ -129,6 +132,9 @@ function parseStartArgs(args) {
|
|
|
129
132
|
case "--task":
|
|
130
133
|
taskId = value;
|
|
131
134
|
break;
|
|
135
|
+
case "--request-id":
|
|
136
|
+
requestId = value;
|
|
137
|
+
break;
|
|
132
138
|
case "--project":
|
|
133
139
|
projectId = value;
|
|
134
140
|
break;
|
|
@@ -165,10 +171,10 @@ function parseStartArgs(args) {
|
|
|
165
171
|
}
|
|
166
172
|
}
|
|
167
173
|
if (taskId === undefined || projectId === undefined || head === undefined
|
|
168
|
-
|| workspace === undefined || steps.length === 0) {
|
|
169
|
-
throw usageError("job start requires --task, --project, --head, --workspace, and at least one --step.", "yui job start ...");
|
|
174
|
+
|| workspace === undefined || requestId === undefined || requestId.trim().length === 0 || steps.length === 0) {
|
|
175
|
+
throw usageError("job start requires --request-id, --task, --project, --head, --workspace, and at least one --step.", "yui job start ...");
|
|
170
176
|
}
|
|
171
|
-
return { taskId, owner, projectId, head, workspace, env, steps, retryOf };
|
|
177
|
+
return { taskId, requestId, owner, projectId, head, workspace, env, steps, retryOf };
|
|
172
178
|
}
|
|
173
179
|
export function parseJobOwner(value) {
|
|
174
180
|
if (value === "task")
|
|
@@ -14,30 +14,41 @@ import { isSystemRoleName, SYSTEM_ROLE_NAMES, systemRoleDescription } from "../r
|
|
|
14
14
|
import { hasAgentConfigOptions, hasNoRoleMutation, parseRoleOptions, patchRoleAgentBinding, roleOptionSpecs, roleProfileFrom, roleProfilePatch } from "./roleConfiguration.js";
|
|
15
15
|
import { hasRoleLaunchContextOptions, validateConfiguredRoleSkills } from "./roleSkillValidation.js";
|
|
16
16
|
import { assertLiveRoleSessionAcknowledged, assertRoleRuntimeMutationAllowed, LIVE_SESSION_ACKNOWLEDGEMENT_OPTION } from "./roleRuntimeGuard.js";
|
|
17
|
-
export function
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
17
|
+
export function applyGlobalInputControl(name, input, store, options = {}) {
|
|
18
|
+
assertGlobalInputAuthority(store, options, name);
|
|
19
|
+
return input.action === "interrupt"
|
|
20
|
+
? interruptGlobalInput(name, input, store)
|
|
21
|
+
: messageGlobalInput(name, input, store, options);
|
|
22
|
+
}
|
|
23
|
+
function inputOutput(output, data) {
|
|
24
|
+
return { kind: "output", output, data };
|
|
25
|
+
}
|
|
26
|
+
function renderGlobalInput(result, options) {
|
|
27
|
+
return result.kind === "output" ? jsonOrText(options, result.output, result.data) : result;
|
|
28
|
+
}
|
|
29
|
+
function assertGlobalInputAuthority(store, options, target) {
|
|
30
|
+
const env = options.env ?? process.env;
|
|
31
|
+
if (env.YUI_SESSION_SCOPE !== undefined && env.YUI_SESSION_SCOPE !== "global"
|
|
32
|
+
|| env.YUI_SESSION_SCOPE === "global" && env.YUI_ROLE !== "operator" && env.YUI_ROLE !== target) {
|
|
33
|
+
throw usageError("Global input mutation is outside the exact Session authority.");
|
|
34
|
+
}
|
|
35
|
+
if (env.YUI_SESSION_SCOPE === "global") {
|
|
36
|
+
const caller = store.getGlobalRoleSessionSet(env.YUI_ROLE ?? "");
|
|
37
|
+
const session = caller?.sessions[caller.activeAgentId];
|
|
38
|
+
if (session === undefined || session.status !== "active" || env.YUI_AGENT_ID !== session.agentId
|
|
39
|
+
|| env.YUI_ADAPTER_ID !== session.adapterId
|
|
40
|
+
|| (env.CODEX_THREAD_ID ?? env.YUI_NATIVE_SESSION_ID) !== session.nativeSessionId) {
|
|
41
|
+
throw usageError("Global input mutation requires the current native caller Session.");
|
|
39
42
|
}
|
|
40
43
|
}
|
|
44
|
+
else if (env.YUI_ROLE !== undefined || env.YUI_AGENT_ID !== undefined || env.YUI_NATIVE_SESSION_ID !== undefined) {
|
|
45
|
+
throw usageError("Incomplete managed identity cannot acquire user authority.");
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export function runGlobalRoleCommand(args, store, options = {}) {
|
|
49
|
+
const [command, ...rest] = args;
|
|
50
|
+
if (command === "session" && rest[0] === "retry")
|
|
51
|
+
assertGlobalInputAuthority(store, options, rest[1]);
|
|
41
52
|
switch (command) {
|
|
42
53
|
case "add": return addRole(rest, store, options);
|
|
43
54
|
case "list": return listRoles(rest, store);
|
|
@@ -551,6 +562,13 @@ function globalRoleMessage(args, store, options) {
|
|
|
551
562
|
const expectedTarget = action === "steer"
|
|
552
563
|
? required(parsed.one("--expected-target"), "--expected-target")
|
|
553
564
|
: undefined;
|
|
565
|
+
return renderGlobalInput(applyGlobalInputControl(name, action === "steer"
|
|
566
|
+
? { action, body, requestId, expectedTarget: expectedTarget, to: name }
|
|
567
|
+
: { action, body, requestId }, store, options), options);
|
|
568
|
+
}
|
|
569
|
+
function messageGlobalInput(name, input, store, options) {
|
|
570
|
+
const { action, body, requestId } = input;
|
|
571
|
+
const expectedTarget = input.action === "steer" ? input.expectedTarget : undefined;
|
|
554
572
|
const now = new Date();
|
|
555
573
|
// The durable Global input is authored as an operator input: a Global Role has
|
|
556
574
|
// no Task Leader, and the operator is the human authority over Global Roles.
|
|
@@ -563,14 +581,14 @@ function globalRoleMessage(args, store, options) {
|
|
|
563
581
|
});
|
|
564
582
|
if (action === "queue") {
|
|
565
583
|
const state = persisted.idempotentReplay ? "idempotent-replay" : "queued";
|
|
566
|
-
return
|
|
584
|
+
return inputOutput(`Queued Global message ${persisted.message.id} to ${name} (${state}).\n`, { roleName: name, message: persisted.message, delivery: { state } });
|
|
567
585
|
}
|
|
568
586
|
if (persisted.idempotentReplay) {
|
|
569
|
-
return
|
|
587
|
+
return inputOutput(`Steer Global message ${persisted.message.id} already recorded (idempotent-replay).\n`, { roleName: name, message: persisted.message, steer: { state: "idempotent-replay" } });
|
|
570
588
|
}
|
|
571
589
|
const resolution = resolveGlobalInputControl(store, name, "steer", expectedTarget);
|
|
572
590
|
if (resolution.outcome !== "ready") {
|
|
573
|
-
return
|
|
591
|
+
return inputOutput(`Steer Global message ${persisted.message.id} saved but not delivered (${resolution.code}: ${resolution.detail}).\n`, { roleName: name, message: persisted.message,
|
|
574
592
|
steer: { state: "not-steered", code: resolution.code, detail: resolution.detail } });
|
|
575
593
|
}
|
|
576
594
|
store.updateGlobalRoleMessage({ ...persisted.message, control: {
|
|
@@ -596,7 +614,6 @@ function globalRoleMessage(args, store, options) {
|
|
|
596
614
|
* fourth action and not an auto-fallback (decision-3 §4).
|
|
597
615
|
*/
|
|
598
616
|
function globalRoleInterrupt(args, store, options) {
|
|
599
|
-
const usage = "Role interrupt usage: yui role interrupt <role> --expected-target <turn> [--then-message <global-message-id>] [--request-id <id>].";
|
|
600
617
|
const [rawName, ...tail] = args;
|
|
601
618
|
const name = roleName(rawName);
|
|
602
619
|
const parsed = parseOptions(tail, new Map([
|
|
@@ -607,12 +624,19 @@ function globalRoleInterrupt(args, store, options) {
|
|
|
607
624
|
const expectedTarget = required(parsed.one("--expected-target"), "--expected-target");
|
|
608
625
|
const thenMessageId = trimmed(parsed.one("--then-message"));
|
|
609
626
|
const requestId = trimmed(parsed.one("--request-id")) ?? `cancel:${encodeURIComponent(expectedTarget)}`;
|
|
627
|
+
return renderGlobalInput(applyGlobalInputControl(name, {
|
|
628
|
+
action: "interrupt", role: name, expectedTarget, thenMessage: thenMessageId, requestId
|
|
629
|
+
}, store, options), options);
|
|
630
|
+
}
|
|
631
|
+
function interruptGlobalInput(name, input, store) {
|
|
632
|
+
const { expectedTarget, thenMessage: thenMessageId } = input;
|
|
633
|
+
const requestId = input.requestId ?? `cancel:${encodeURIComponent(expectedTarget)}`;
|
|
610
634
|
const fingerprint = JSON.stringify({ expectedTarget, thenMessageId });
|
|
611
635
|
const prior = store.getGlobalRoleSessionSet(name)?.interrupts?.[requestId];
|
|
612
636
|
if (prior !== undefined) {
|
|
613
637
|
if (prior.fingerprint !== fingerprint)
|
|
614
638
|
throw usageError("Interrupt requestId already names another control.");
|
|
615
|
-
return
|
|
639
|
+
return inputOutput(`Interrupt ${requestId} already recorded; no native control repeated.\n`, { roleName: name, interrupt: prior.receipt ?? { state: "interrupt-unknown" }, idempotentReplay: true });
|
|
616
640
|
}
|
|
617
641
|
const resolved = store.transaction((tx) => {
|
|
618
642
|
requireRole(name, tx);
|
|
@@ -645,10 +669,10 @@ function globalRoleInterrupt(args, store, options) {
|
|
|
645
669
|
return resolution;
|
|
646
670
|
});
|
|
647
671
|
if (resolved.outcome === "then-conflict") {
|
|
648
|
-
return
|
|
672
|
+
return inputOutput(`Interrupt not delivered (${resolved.code}: ${resolved.detail}).\n`, { roleName: name, interrupt: { state: "not-interrupted", code: resolved.code, detail: resolved.detail } });
|
|
649
673
|
}
|
|
650
674
|
if (resolved.outcome !== "ready") {
|
|
651
|
-
return
|
|
675
|
+
return inputOutput(`Interrupt not delivered (${resolved.code}: ${resolved.detail}).\n`, { roleName: name, interrupt: { state: "not-interrupted", code: resolved.code, detail: resolved.detail } });
|
|
652
676
|
}
|
|
653
677
|
return {
|
|
654
678
|
kind: "input-interrupt",
|
|
@@ -286,9 +286,6 @@ function requireTask(store, taskId) {
|
|
|
286
286
|
function recordTaskEvent(store, taskId, type, payload, now) {
|
|
287
287
|
store.saveEvent(taskId, createTaskEvent(store.nextEventId(taskId), taskId, type, payload, now));
|
|
288
288
|
}
|
|
289
|
-
function requiredOption(options, name) {
|
|
290
|
-
return requiredText(options.get(name), name);
|
|
291
|
-
}
|
|
292
289
|
function optionalOption(options, name) {
|
|
293
290
|
if (!options.has(name))
|
|
294
291
|
return undefined;
|
|
@@ -93,9 +93,6 @@ function retryJob(args, store, options) {
|
|
|
93
93
|
enqueueWork(tx, { kind: "role", taskId: task.id, roleName: "leader" }, "recovery-retry", now, [{ type: "task", id: task.id }]);
|
|
94
94
|
});
|
|
95
95
|
const target = { kind: "role", taskId, roleName: "leader" };
|
|
96
|
-
|
|
97
|
-
runtime.notifyMailboxChanged(target);
|
|
98
|
-
else
|
|
99
|
-
runtime.notifyStateChanged(taskId);
|
|
96
|
+
runtime.notifyMailboxChanged(target);
|
|
100
97
|
return `Retry requested for ${id}\n`;
|
|
101
98
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { usageError } from "../errors/cliError.js";
|
|
2
1
|
import { agentAdapterLabel as adapterLabel } from "../agent/adapterCatalog.js";
|
|
2
|
+
import { usageError } from "../errors/cliError.js";
|
|
3
3
|
import { createRoleSessionSet } from "../executor/agentExecutor.js";
|
|
4
|
-
import {
|
|
4
|
+
import { TASK_SUBMISSION_INTENTS } from "../message/message.js";
|
|
5
|
+
import { listOperatorSessions, prepareOperatorNewSession, prepareOperatorResumeSession, projectOperatorStatus } from "../operator/operatorSessionHistory.js";
|
|
5
6
|
import { defaultTableWidth, renderTable } from "../output/table.js";
|
|
6
7
|
import { formatRelativeTimestamp } from "../output/timePresentation.js";
|
|
7
8
|
import { updateGlobalRole } from "../role/role.js";
|
|
8
|
-
import { TASK_SUBMISSION_INTENTS } from "../message/message.js";
|
|
9
9
|
import { submitOperatorMessage } from "./taskCommands.js";
|
|
10
10
|
import { readCommandText } from "./textInput.js";
|
|
11
11
|
/** Operator command parsing never launches or attaches a native process. */
|
|
@@ -8,7 +8,7 @@ import { GitWorkspaceRefreshError, NodeGitWorkspace } from "../repository/gitWor
|
|
|
8
8
|
import { acquireProjectMaintenanceLock } from "../repository/projectMaintenanceLock.js";
|
|
9
9
|
import { addProjectKnowledge, addKnowledgeProposal, assertProjectActive, decideKnowledgeProposal, createProject, findKnowledgeProposal, findKnowledgeProposalByFingerprint, knowledgeEvidenceDigest, knowledgeProposalFingerprint, managedProjectPath, planKnowledgeAcceptance, retireProject, retireProjectKnowledge, resolveProject, updateProjectKnowledge, updateProjectMetadata, validateProject, validateProjectName } from "../repository/project.js";
|
|
10
10
|
import { managedWorkspacesRoot } from "../storage/homeLayout.js";
|
|
11
|
-
import { projectActor } from "
|
|
11
|
+
import { projectActor } from "../task/taskAuthority.js";
|
|
12
12
|
export async function runProjectCommand(args, store, options = {}) {
|
|
13
13
|
const [command, ...rest] = args;
|
|
14
14
|
if (command === "add" || command === "clone") {
|
|
@@ -1497,9 +1497,6 @@ function proposeKnowledge(args, store, options) {
|
|
|
1497
1497
|
* digest at proposal time, so a later Agent can verify the source record.
|
|
1498
1498
|
*/
|
|
1499
1499
|
function requireProposalEvidence(store, parsed) {
|
|
1500
|
-
if (store.getTask === undefined) {
|
|
1501
|
-
throw usageError("Knowledge promotion requires Task evidence, which this store does not provide.");
|
|
1502
|
-
}
|
|
1503
1500
|
const task = store.getTask(parsed.task);
|
|
1504
1501
|
if (task === null)
|
|
1505
1502
|
throw usageError(`Task not found: ${parsed.task}.`);
|
|
@@ -1511,9 +1508,6 @@ function requireProposalEvidence(store, parsed) {
|
|
|
1511
1508
|
};
|
|
1512
1509
|
let evidence;
|
|
1513
1510
|
if (parsed.decision !== undefined) {
|
|
1514
|
-
if (store.getDecision === undefined) {
|
|
1515
|
-
throw usageError("Knowledge promotion requires Decision evidence, which this store does not provide.");
|
|
1516
|
-
}
|
|
1517
1511
|
const decision = store.getDecision(task.id, parsed.decision);
|
|
1518
1512
|
if (decision === null) {
|
|
1519
1513
|
throw usageError(`Decision not found: ${parsed.decision} in Task ${task.id}.`);
|
|
@@ -1521,9 +1515,6 @@ function requireProposalEvidence(store, parsed) {
|
|
|
1521
1515
|
evidence = `${decision.title}\n${decision.rationale}`;
|
|
1522
1516
|
}
|
|
1523
1517
|
else if (parsed.milestone !== undefined) {
|
|
1524
|
-
if (store.getMilestone === undefined) {
|
|
1525
|
-
throw usageError("Knowledge promotion requires Milestone evidence, which this store does not provide.");
|
|
1526
|
-
}
|
|
1527
1518
|
const milestone = store.getMilestone(task.id, parsed.milestone);
|
|
1528
1519
|
if (milestone === null) {
|
|
1529
1520
|
throw usageError(`Milestone not found: ${parsed.milestone} in Task ${task.id}.`);
|
|
@@ -7,12 +7,11 @@
|
|
|
7
7
|
* every quarantined resource to its original path.
|
|
8
8
|
*/
|
|
9
9
|
import { resolve } from "node:path";
|
|
10
|
+
import { resolveResourcesGcMode, resolveResourcesQuarantineTtlHours } from "../config/yuiConfig.js";
|
|
10
11
|
import { usageError } from "../errors/cliError.js";
|
|
11
12
|
import { defaultTableWidth, renderTable } from "../output/table.js";
|
|
12
|
-
import { applyResourceGc, planResourceGc, purgeResourceQuarantine, restoreAllResourceGc } from "../resources/resourceGc.js";
|
|
13
|
-
import { createResourceRegistryStore } from "../resources/resourceRegistryStore.js";
|
|
14
13
|
import { resourceKindLabel, resourceOwnerLabel } from "../resources/resourceDiscovery.js";
|
|
15
|
-
import {
|
|
14
|
+
import { applyResourceGc, planResourceGc, readResourceGcState, purgeResourceQuarantine, restoreAllResourceGc } from "../resources/resourceGc.js";
|
|
16
15
|
export async function runResourcesCommand(args, store, options = {}) {
|
|
17
16
|
const [command, ...rest] = args;
|
|
18
17
|
if (command !== "gc") {
|
|
@@ -27,10 +26,7 @@ async function runGcCommand(args, store, options) {
|
|
|
27
26
|
const now = options.now?.() ?? new Date();
|
|
28
27
|
const home = resolve(store.rootDirectory());
|
|
29
28
|
const mode = resolveGcMode(store);
|
|
30
|
-
const projects = store
|
|
31
|
-
const managedWorkspaces = collectManagedWorkspaces(store);
|
|
32
|
-
const taskStatusById = collectTaskStatuses(store);
|
|
33
|
-
const activeWorkspaceOwnerPaths = collectActiveWorkspaceOwnerPaths(store);
|
|
29
|
+
const { projects, managedWorkspaces, taskStatusById, activeWorkspaceOwnerPaths, sessionOwners } = readResourceGcState(store);
|
|
34
30
|
if (action === "restore") {
|
|
35
31
|
const result = await restoreAllResourceGc(home, { now });
|
|
36
32
|
return {
|
|
@@ -46,7 +42,7 @@ async function runGcCommand(args, store, options) {
|
|
|
46
42
|
data: { mode, action: "purge", skipped: true }
|
|
47
43
|
};
|
|
48
44
|
}
|
|
49
|
-
const result = await purgeResourceQuarantine(home, { now, ttlHours, managedWorkspaces });
|
|
45
|
+
const result = await purgeResourceQuarantine(home, { now, ttlHours, managedWorkspaces }, store);
|
|
50
46
|
return {
|
|
51
47
|
output: renderPurgeResult(result),
|
|
52
48
|
data: result
|
|
@@ -54,7 +50,7 @@ async function runGcCommand(args, store, options) {
|
|
|
54
50
|
}
|
|
55
51
|
const plan = await planResourceGc({
|
|
56
52
|
home,
|
|
57
|
-
|
|
53
|
+
sessionOwners,
|
|
58
54
|
projects,
|
|
59
55
|
managedWorkspaces,
|
|
60
56
|
taskStatusById,
|
|
@@ -66,7 +62,7 @@ async function runGcCommand(args, store, options) {
|
|
|
66
62
|
if (action === "apply" && mode === "quarantine") {
|
|
67
63
|
const result = await applyResourceGc({
|
|
68
64
|
home,
|
|
69
|
-
|
|
65
|
+
sessionOwners,
|
|
70
66
|
projects,
|
|
71
67
|
managedWorkspaces,
|
|
72
68
|
taskStatusById,
|
|
@@ -74,7 +70,7 @@ async function runGcCommand(args, store, options) {
|
|
|
74
70
|
now,
|
|
75
71
|
quarantineTtlHours: ttlHours,
|
|
76
72
|
activeWorkspaceOwnerPaths
|
|
77
|
-
}, plan);
|
|
73
|
+
}, plan, store);
|
|
78
74
|
return {
|
|
79
75
|
output: renderApplyResult(result),
|
|
80
76
|
data: result
|
|
@@ -109,35 +105,6 @@ function parseTtlHours(args, store) {
|
|
|
109
105
|
function resolveGcMode(store) {
|
|
110
106
|
return resolveResourcesGcMode(store.getConfig().resourcesGcMode);
|
|
111
107
|
}
|
|
112
|
-
function collectManagedWorkspaces(store) {
|
|
113
|
-
const workspaces = [];
|
|
114
|
-
for (const task of store.listTasks()) {
|
|
115
|
-
workspaces.push(...store.listManagedWorkspaces(task.id));
|
|
116
|
-
}
|
|
117
|
-
return workspaces;
|
|
118
|
-
}
|
|
119
|
-
function collectTaskStatuses(store) {
|
|
120
|
-
const statuses = new Map();
|
|
121
|
-
for (const task of store.listTasks()) {
|
|
122
|
-
statuses.set(task.id, task.status);
|
|
123
|
-
}
|
|
124
|
-
return statuses;
|
|
125
|
-
}
|
|
126
|
-
/** Workspace paths claimed by active durable Jobs (AgentRuns). */
|
|
127
|
-
function collectActiveWorkspaceOwnerPaths(store) {
|
|
128
|
-
const paths = [];
|
|
129
|
-
for (const task of store.listTasks()) {
|
|
130
|
-
for (const run of store.listRuns(task.id)) {
|
|
131
|
-
if (run.status !== "active")
|
|
132
|
-
continue;
|
|
133
|
-
const workspace = run.workspace;
|
|
134
|
-
if (workspace === undefined)
|
|
135
|
-
continue;
|
|
136
|
-
paths.push(workspace.root, ...workspace.entries.map((entry) => entry.path));
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
return paths;
|
|
140
|
-
}
|
|
141
108
|
function renderPlan(plan, action) {
|
|
142
109
|
const lines = [];
|
|
143
110
|
const modeNotice = plan.mode === "report" && action === "apply"
|
|
@@ -207,6 +174,9 @@ function renderApplyResult(result) {
|
|
|
207
174
|
if (result.restored.length > 0) {
|
|
208
175
|
lines.push(`Restored ${result.restored.length} resource(s) from quarantine.`);
|
|
209
176
|
}
|
|
177
|
+
for (const record of result.planned.retained) {
|
|
178
|
+
lines.push(`Retained ${record.id} ${record.path}: ${record.blocker ?? "current ownership or live reference"}`);
|
|
179
|
+
}
|
|
210
180
|
if (result.applied.length === 0 && result.failed.length === 0 && result.restored.length === 0) {
|
|
211
181
|
lines.push("No releasable resources.");
|
|
212
182
|
}
|
|
@@ -187,12 +187,8 @@ function permissionPatch(binding, parsed) {
|
|
|
187
187
|
}
|
|
188
188
|
const current = binding.config.permission;
|
|
189
189
|
if (selected !== "configured" && !nativeOptions) {
|
|
190
|
-
//
|
|
191
|
-
|
|
192
|
-
// permission at all, and it must be the adapter's own default rather than a
|
|
193
|
-
// fixed `bypass`: ACP defaults to `default`, and defaulting it to bypass
|
|
194
|
-
// here would widen authority the user never granted.
|
|
195
|
-
return structuredClone(current ?? defaultRoleAgentConfig(binding.adapterId).permission);
|
|
190
|
+
// The validated binding always has its explicit permission strategy.
|
|
191
|
+
return structuredClone(current);
|
|
196
192
|
}
|
|
197
193
|
const permission = current?.strategy === "configured"
|
|
198
194
|
? structuredClone(current)
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import { usageError } from "../errors/cliError.js";
|
|
3
|
-
import { currentManagedRuntime } from "../runtime/managedCaller.js";
|
|
4
2
|
import { enqueueWork } from "../coordination/workMailboxQueue.js";
|
|
3
|
+
import { usageError } from "../errors/cliError.js";
|
|
5
4
|
import { SYSTEM_LEADER_ROLE } from "../role/systemRoles.js";
|
|
5
|
+
import { currentManagedRuntime } from "../runtime/managedCaller.js";
|
|
6
6
|
import { describeEnvironmentPlan } from "../task/taskActivation.js";
|
|
7
7
|
import { cancelTaskActivation, requestTaskActivation, taskActivationOperationRef } from "../task/taskActivationService.js";
|
|
8
|
-
import { taskLocalActor } from "
|
|
8
|
+
import { taskLocalActor } from "../task/taskAuthority.js";
|
|
9
9
|
/**
|
|
10
10
|
* Explicit Activation requests.
|
|
11
11
|
*
|
|
@@ -52,10 +52,6 @@ function requestActivation(args, store, options) {
|
|
|
52
52
|
actorId: caller.actorId,
|
|
53
53
|
authorityRef: caller.authorityRef,
|
|
54
54
|
environmentPlan,
|
|
55
|
-
// The activation-request command is the explicit activation boundary, so
|
|
56
|
-
// every request it records carries an explicit provable origin (task-32
|
|
57
|
-
// §2.4). A develop submission records its own request with `submit-develop`.
|
|
58
|
-
origin: "explicit",
|
|
59
55
|
...(caller.planningRunId === undefined ? {} : { callerRunId: caller.planningRunId })
|
|
60
56
|
}, now));
|
|
61
57
|
// An immediate request has nothing left to wait for, so ask the Controller to
|
|
@@ -65,7 +61,7 @@ function requestActivation(args, store, options) {
|
|
|
65
61
|
store.transaction((tx) => {
|
|
66
62
|
enqueueWork(tx, { kind: "task", taskId }, "activation-requested", now, [{ type: "task", id: taskId }]);
|
|
67
63
|
});
|
|
68
|
-
void options.runtime?.notifyMailboxChanged
|
|
64
|
+
void options.runtime?.notifyMailboxChanged({ kind: "task", taskId });
|
|
69
65
|
}
|
|
70
66
|
const request = result.request;
|
|
71
67
|
const lines = [
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { exactPositionals, parseTail } from "./taskCommandSupport.js";
|
|
2
|
+
export function parseTaskAgentCapabilityQuery(args) {
|
|
3
|
+
const usage = "Usage: yui task role capabilities <task> <role> [--error <event-id>] [--refresh]";
|
|
4
|
+
const parsed = parseTail(args, new Set(["--error"]), usage, new Set(["--refresh"]));
|
|
5
|
+
exactPositionals(parsed.positionals, 2, usage);
|
|
6
|
+
const errorId = parsed.options.get("--error");
|
|
7
|
+
return { taskId: parsed.positionals[0], roleName: parsed.positionals[1],
|
|
8
|
+
...(errorId === undefined ? {} : { errorId }), refresh: parsed.options.has("--refresh") };
|
|
9
|
+
}
|