@zq-silk/yui 0.15.11 → 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 +11 -6
- package/ARCHITECTURE.zh-CN.md +8 -4
- package/README.md +13 -5
- package/dist/agentRun/agentRun.js +3 -0
- 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 +92 -48
- 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 +11 -3
- package/dist/cli/invocationAuthority.js +64 -0
- package/dist/cli/managedDiagnostics.js +2 -2
- package/dist/cli/parseRepeatable.js +35 -0
- package/dist/cli/updatePorts.js +26 -5
- package/dist/cli.js +1303 -1235
- 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/executionAuditCommands.js +10 -0
- package/dist/commands/globalRoleCommands.js +78 -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 +45 -25
- 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 +355 -732
- 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 +20 -58
- package/dist/commands/taskNextActionCommand.js +7 -6
- package/dist/commands/taskPublicationAdoptCommand.js +127 -0
- package/dist/commands/taskPublicationCommands.js +12 -3
- package/dist/commands/taskPublicationVerifyCommand.js +24 -40
- package/dist/commands/taskRemoteDeliveryCommand.js +5 -86
- 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 +5 -3
- package/dist/context/taskCatalog.js +185 -0
- package/dist/context/taskContext.js +152 -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 +20 -24
- package/dist/controller/fileSchedulerStoreAdapter.js +191 -225
- package/dist/controller/globalInputDelivery.js +13 -0
- package/dist/controller/jobClient.js +4 -4
- package/dist/controller/jobControl.js +60 -25
- package/dist/controller/jobSupervisor.js +4 -4
- package/dist/controller/providerRetryAdmission.js +100 -0
- package/dist/controller/providerRetryDelivery.js +218 -0
- package/dist/controller/runtime.js +85 -43
- 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 +79 -90
- 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 +5 -10
- package/dist/message/globalProviderRetry.js +15 -0
- 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/executionAudit.js +19 -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/gitWorkspace.js +371 -105
- package/dist/repository/projectMaintenanceLock.js +98 -82
- package/dist/repository/taskBaseFreshness.js +1 -1
- package/dist/repository/taskWorkspaceCoordinator.js +82 -144
- package/dist/repository/taskWorkspacePreparer.js +113 -47
- package/dist/repository/workspaceCleanupInspection.js +187 -0
- 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/agentError.js +5 -3
- package/dist/runtime/agentFailureContext.js +43 -0
- package/dist/runtime/agentHost.js +42 -25
- package/dist/runtime/builtinAgentErrorMappers.js +91 -0
- package/dist/runtime/codexAppServerRuntime.js +34 -3
- package/dist/runtime/codexInteractiveHost.js +2 -2
- package/dist/runtime/index.js +0 -1
- package/dist/runtime/managedCaller.js +21 -1
- package/dist/runtime/providerControl.js +5 -1
- package/dist/runtime/providerErrors.js +38 -0
- package/dist/runtime/providerRetry.js +198 -0
- package/dist/runtime/providerRuntimeIdentity.js +28 -2
- package/dist/runtime/runtimeObservation.js +0 -5
- package/dist/runtime/runtimeSessionCandidate.js +2 -3
- package/dist/runtime/sessionOwnerIdentity.js +1 -1
- package/dist/runtime/sessionTokenMetrics.js +15 -5
- package/dist/runtime/structuredProviderHost.js +10 -43
- package/dist/runtime/taskUsageMetrics.js +275 -0
- package/dist/runtime/tmuxAdapters.js +6 -8
- package/dist/scheduler/activeRoleRunDelivery.js +19 -7
- package/dist/scheduler/leaderWakeupProcessor.js +24 -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 +49 -36
- package/dist/scheduler/taskObservabilityProjection.js +6 -45
- 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 +173 -1
- package/dist/storage/sqliteStore.js +172 -161
- package/dist/storage/storageSchema.js +2 -14
- package/dist/storage/storageVersions.js +1 -1
- package/dist/storage/storeRpc.js +16 -7
- package/dist/storage/taskCatalog.js +123 -0
- package/dist/storage/taskStore.js +5 -7
- package/dist/storage/upgrade/upgradeOrchestrator.js +25 -37
- package/dist/task/archiveDiagnostics.js +1 -0
- package/dist/task/archivePreflight.js +124 -0
- package/dist/task/completionReadiness.js +5 -24
- package/dist/task/draftPlan.js +0 -53
- package/dist/task/nextAction.js +7 -13
- package/dist/task/publicationAdoption.js +56 -0
- package/dist/task/publicationReference.js +10 -0
- package/dist/task/remoteDelivery.js +31 -16
- 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 +92 -17
- package/dist/web/assets/client/components.js +55 -13
- package/dist/web/assets/client/i18n.js +72 -4
- package/dist/web/assets/client/taskSurface.js +6 -5
- package/dist/web/assets/client/view.js +35 -7
- package/dist/web/assets/shell.js +6 -0
- package/dist/web/assets/styles/layout.js +7 -0
- package/dist/web/webServer.js +12 -3
- package/dist/web/webSnapshot.js +14 -85
- package/dist/web/webTaskSurface.js +17 -46
- package/dist/workItem/workItem.js +1 -12
- package/dist/workspace/cleanupInspection.js +63 -0
- package/dist/workspace/workItemChangeSetManager.js +110 -50
- package/docs/agent-result-consumption.md +4 -0
- package/docs/agent-result-consumption.zh-CN.md +3 -0
- package/docs/agent-runtime-drivers.md +7 -0
- package/docs/agent-runtime-drivers.zh-CN.md +5 -0
- package/docs/architecture/README.md +2 -0
- package/docs/architecture/README.zh-CN.md +3 -1
- package/docs/architecture/capabilities-and-resources.md +42 -5
- package/docs/architecture/capabilities-and-resources.zh-CN.md +33 -3
- package/docs/managed-turn-and-session-runtime.md +121 -1
- package/docs/managed-turn-and-session-runtime.zh-CN.md +96 -2
- package/docs/observability/README.md +62 -0
- package/docs/observability/README.zh-CN.md +47 -0
- package/docs/plugin-sdk.md +4 -2
- package/docs/project-refresh.md +77 -0
- package/docs/project-refresh.zh-CN.md +59 -0
- package/docs/provider-retry.md +70 -0
- 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 +223 -17
- package/docs/task-delivery.zh-CN.md +171 -14
- package/docs/task-discovery.md +101 -0
- package/docs/task-discovery.zh-CN.md +85 -0
- package/docs/testing/verification-levels.md +161 -9
- package/docs/testing/verification-levels.zh-CN.md +116 -9
- package/i18n/README.zh-CN.md +13 -7
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +5 -0
- package/skills/yui-leader/references/execution.md +3 -2
- package/skills/yui-leader/references/integration.md +9 -5
- package/skills/yui-leader/references/planning.md +9 -3
- package/skills/yui-operator/SKILL.md +24 -8
- package/skills/yui-reviewer/SKILL.md +4 -0
- package/skills/yui-runtime/SKILL.md +17 -2
- package/skills/yui-runtime/references/publication.md +26 -4
- package/skills/yui-runtime/references/recovery.md +71 -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 -376
- 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
|
@@ -3,9 +3,9 @@ import { chmodSync, existsSync, lstatSync, mkdirSync, readFileSync, renameSync,
|
|
|
3
3
|
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
4
4
|
import { dataError } from "../errors/cliError.js";
|
|
5
5
|
import { activationBlock, activationEnd, activationIsAutomatic, activationStart, completionMarker, managedCompletionScript } from "./completionState.js";
|
|
6
|
-
export function installCompletion(store, shell, installation, env,
|
|
6
|
+
export function installCompletion(store, shell, installation, env, activate) {
|
|
7
7
|
validateInstallation(installation);
|
|
8
|
-
writeManagedScript(shell, installation.scriptPath
|
|
8
|
+
writeManagedScript(shell, installation.scriptPath);
|
|
9
9
|
store.transaction((tx) => {
|
|
10
10
|
const config = tx.getConfig();
|
|
11
11
|
tx.saveConfig({
|
|
@@ -16,20 +16,20 @@ export function installCompletion(store, shell, installation, env, identity, act
|
|
|
16
16
|
}
|
|
17
17
|
});
|
|
18
18
|
});
|
|
19
|
-
if (!activationIsAutomatic(shell, installation, env
|
|
20
|
-
writeActivationBlock(shell, installation
|
|
19
|
+
if (!activationIsAutomatic(shell, installation, env) && activate) {
|
|
20
|
+
writeActivationBlock(shell, installation);
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
-
export function uninstallCompletion(store, shell
|
|
23
|
+
export function uninstallCompletion(store, shell) {
|
|
24
24
|
store.transaction((tx) => {
|
|
25
25
|
const config = tx.getConfig();
|
|
26
26
|
const installation = config.completionInstallations?.[shell];
|
|
27
27
|
if (installation === undefined)
|
|
28
28
|
return;
|
|
29
|
-
assertManagedScriptRemovable(shell, installation.scriptPath
|
|
30
|
-
assertActivationRemovable(shell, installation
|
|
31
|
-
removeManagedScript(shell, installation.scriptPath
|
|
32
|
-
removeActivationBlock(shell, installation
|
|
29
|
+
assertManagedScriptRemovable(shell, installation.scriptPath);
|
|
30
|
+
assertActivationRemovable(shell, installation);
|
|
31
|
+
removeManagedScript(shell, installation.scriptPath);
|
|
32
|
+
removeActivationBlock(shell, installation);
|
|
33
33
|
const installations = { ...config.completionInstallations };
|
|
34
34
|
delete installations[shell];
|
|
35
35
|
if (Object.keys(installations).length > 0) {
|
|
@@ -40,17 +40,17 @@ export function uninstallCompletion(store, shell, identity) {
|
|
|
40
40
|
tx.saveConfig(withoutInstallations);
|
|
41
41
|
});
|
|
42
42
|
}
|
|
43
|
-
function assertManagedScriptRemovable(shell, path
|
|
43
|
+
function assertManagedScriptRemovable(shell, path) {
|
|
44
44
|
if (!existsSync(path))
|
|
45
45
|
return;
|
|
46
46
|
const stat = lstatSync(path);
|
|
47
47
|
if (!stat.isFile()
|
|
48
48
|
|| stat.isSymbolicLink()
|
|
49
|
-
|| !readFileSync(path, "utf8").startsWith(completionMarker(shell
|
|
49
|
+
|| !readFileSync(path, "utf8").startsWith(completionMarker(shell))) {
|
|
50
50
|
throw dataError(`Refusing to remove unmanaged completion script: ${path}`);
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
-
function assertActivationRemovable(shell, installation
|
|
53
|
+
function assertActivationRemovable(shell, installation) {
|
|
54
54
|
const path = installation.activationPath;
|
|
55
55
|
if (!existsSync(path))
|
|
56
56
|
return;
|
|
@@ -59,25 +59,25 @@ function assertActivationRemovable(shell, installation, identity) {
|
|
|
59
59
|
throw dataError(`Refusing to modify unsafe activation file: ${path}`);
|
|
60
60
|
}
|
|
61
61
|
const contents = readFileSync(path, "utf8");
|
|
62
|
-
const starts = occurrences(contents, activationStart(shell
|
|
63
|
-
const ends = occurrences(contents, activationEnd(shell
|
|
62
|
+
const starts = occurrences(contents, activationStart(shell));
|
|
63
|
+
const ends = occurrences(contents, activationEnd(shell));
|
|
64
64
|
if (starts !== ends || starts > 1) {
|
|
65
65
|
throw dataError(`Refusing to remove ambiguous Yui activation block: ${path}`);
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
-
function writeManagedScript(shell, path
|
|
68
|
+
function writeManagedScript(shell, path) {
|
|
69
69
|
if (existsSync(path)) {
|
|
70
70
|
const stat = lstatSync(path);
|
|
71
71
|
if (!stat.isFile() || stat.isSymbolicLink()) {
|
|
72
72
|
throw dataError(`Refusing to overwrite unsafe completion script: ${path}`);
|
|
73
73
|
}
|
|
74
|
-
if (!readFileSync(path, "utf8").startsWith(completionMarker(shell
|
|
74
|
+
if (!readFileSync(path, "utf8").startsWith(completionMarker(shell))) {
|
|
75
75
|
throw dataError(`Refusing to overwrite unmanaged completion script: ${path}`);
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
|
-
writeAtomic(path, managedCompletionScript(shell
|
|
78
|
+
writeAtomic(path, managedCompletionScript(shell), 0o644);
|
|
79
79
|
}
|
|
80
|
-
function writeActivationBlock(shell, installation
|
|
80
|
+
function writeActivationBlock(shell, installation) {
|
|
81
81
|
const path = installation.activationPath;
|
|
82
82
|
let contents = "";
|
|
83
83
|
let mode = 0o644;
|
|
@@ -89,31 +89,31 @@ function writeActivationBlock(shell, installation, identity) {
|
|
|
89
89
|
contents = readFileSync(path, "utf8");
|
|
90
90
|
mode = stat.mode & 0o777;
|
|
91
91
|
}
|
|
92
|
-
const start = activationStart(shell
|
|
93
|
-
const end = activationEnd(shell
|
|
92
|
+
const start = activationStart(shell);
|
|
93
|
+
const end = activationEnd(shell);
|
|
94
94
|
const starts = occurrences(contents, start);
|
|
95
95
|
const ends = occurrences(contents, end);
|
|
96
96
|
if (starts > 1 || ends > 1 || starts !== ends) {
|
|
97
97
|
throw dataError(`Refusing to modify ambiguous Yui activation block: ${path}`);
|
|
98
98
|
}
|
|
99
|
-
const block = activationBlock(shell, installation
|
|
99
|
+
const block = activationBlock(shell, installation);
|
|
100
100
|
const next = starts === 1
|
|
101
101
|
? replaceManagedBlock(contents, start, end, block)
|
|
102
102
|
: `${contents}${contents.length === 0 || contents.endsWith("\n") ? "" : "\n"}${block}\n`;
|
|
103
103
|
writeAtomic(path, next, mode);
|
|
104
104
|
}
|
|
105
|
-
function removeManagedScript(shell, path
|
|
105
|
+
function removeManagedScript(shell, path) {
|
|
106
106
|
if (!existsSync(path))
|
|
107
107
|
return;
|
|
108
108
|
const stat = lstatSync(path);
|
|
109
109
|
if (!stat.isFile()
|
|
110
110
|
|| stat.isSymbolicLink()
|
|
111
|
-
|| !readFileSync(path, "utf8").startsWith(completionMarker(shell
|
|
111
|
+
|| !readFileSync(path, "utf8").startsWith(completionMarker(shell))) {
|
|
112
112
|
throw dataError(`Refusing to remove unmanaged completion script: ${path}`);
|
|
113
113
|
}
|
|
114
114
|
rmSync(path);
|
|
115
115
|
}
|
|
116
|
-
function removeActivationBlock(shell, installation
|
|
116
|
+
function removeActivationBlock(shell, installation) {
|
|
117
117
|
const path = installation.activationPath;
|
|
118
118
|
if (!existsSync(path))
|
|
119
119
|
return;
|
|
@@ -122,8 +122,8 @@ function removeActivationBlock(shell, installation, identity) {
|
|
|
122
122
|
throw dataError(`Refusing to modify unsafe activation file: ${path}`);
|
|
123
123
|
}
|
|
124
124
|
const contents = readFileSync(path, "utf8");
|
|
125
|
-
const start = activationStart(shell
|
|
126
|
-
const end = activationEnd(shell
|
|
125
|
+
const start = activationStart(shell);
|
|
126
|
+
const end = activationEnd(shell);
|
|
127
127
|
const starts = occurrences(contents, start);
|
|
128
128
|
const ends = occurrences(contents, end);
|
|
129
129
|
if (starts !== ends || starts > 1) {
|
|
@@ -10,14 +10,14 @@ export function currentCompletionShell(env) {
|
|
|
10
10
|
? value
|
|
11
11
|
: undefined;
|
|
12
12
|
}
|
|
13
|
-
export function suggestedCompletionInstallation(shell, env
|
|
13
|
+
export function suggestedCompletionInstallation(shell, env) {
|
|
14
14
|
const home = absoluteEnvRoot("HOME", env.HOME);
|
|
15
15
|
if (shell === "bash") {
|
|
16
16
|
const data = env.XDG_DATA_HOME === undefined
|
|
17
17
|
? join(home, ".local", "share")
|
|
18
18
|
: absoluteEnvRoot("XDG_DATA_HOME", env.XDG_DATA_HOME);
|
|
19
19
|
return {
|
|
20
|
-
scriptPath: join(data, "bash-completion", "completions",
|
|
20
|
+
scriptPath: join(data, "bash-completion", "completions", "yui"),
|
|
21
21
|
activationPath: join(home, ".bashrc")
|
|
22
22
|
};
|
|
23
23
|
}
|
|
@@ -26,7 +26,7 @@ export function suggestedCompletionInstallation(shell, env, identity) {
|
|
|
26
26
|
? home
|
|
27
27
|
: absoluteEnvRoot("ZDOTDIR", env.ZDOTDIR);
|
|
28
28
|
return {
|
|
29
|
-
scriptPath: join(zshRoot, ".zfunc",
|
|
29
|
+
scriptPath: join(zshRoot, ".zfunc", "_yui"),
|
|
30
30
|
activationPath: join(zshRoot, ".zshrc")
|
|
31
31
|
};
|
|
32
32
|
}
|
|
@@ -34,11 +34,11 @@ export function suggestedCompletionInstallation(shell, env, identity) {
|
|
|
34
34
|
? join(home, ".config")
|
|
35
35
|
: absoluteEnvRoot("XDG_CONFIG_HOME", env.XDG_CONFIG_HOME);
|
|
36
36
|
return {
|
|
37
|
-
scriptPath: join(config, "fish", "completions",
|
|
37
|
+
scriptPath: join(config, "fish", "completions", "yui.fish"),
|
|
38
38
|
activationPath: join(config, "fish", "config.fish")
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
|
-
export function inspectCompletionStates(config, env
|
|
41
|
+
export function inspectCompletionStates(config, env) {
|
|
42
42
|
const current = currentCompletionShell(env);
|
|
43
43
|
return COMPLETION_SHELLS.map((shell) => {
|
|
44
44
|
const installation = config.completionInstallations?.[shell];
|
|
@@ -50,8 +50,8 @@ export function inspectCompletionStates(config, env, identity) {
|
|
|
50
50
|
current: shell === current
|
|
51
51
|
};
|
|
52
52
|
}
|
|
53
|
-
const installed = completionScriptIsCurrent(shell, installation
|
|
54
|
-
&& completionActivationIsCurrent(shell, installation, env
|
|
53
|
+
const installed = completionScriptIsCurrent(shell, installation)
|
|
54
|
+
&& completionActivationIsCurrent(shell, installation, env);
|
|
55
55
|
return {
|
|
56
56
|
shell,
|
|
57
57
|
status: installed ? "Installed" : "Needs repair",
|
|
@@ -78,46 +78,46 @@ export function renderCompletionStateTable(states, width = defaultTableWidth())
|
|
|
78
78
|
state.installation?.scriptPath ?? ""
|
|
79
79
|
]), width);
|
|
80
80
|
}
|
|
81
|
-
export function managedCompletionScript(shell
|
|
82
|
-
return `${completionMarker(shell
|
|
81
|
+
export function managedCompletionScript(shell) {
|
|
82
|
+
return `${completionMarker(shell)}\n${renderCompletion(shell)}`;
|
|
83
83
|
}
|
|
84
|
-
export function completionMarker(shell
|
|
85
|
-
return `# yui-completion: managed shell=${shell} identity
|
|
84
|
+
export function completionMarker(shell) {
|
|
85
|
+
return `# yui-completion: managed shell=${shell} identity=yui format=1`;
|
|
86
86
|
}
|
|
87
|
-
export function activationBlock(shell, installation
|
|
88
|
-
const start = activationStart(shell
|
|
89
|
-
const end = activationEnd(shell
|
|
87
|
+
export function activationBlock(shell, installation) {
|
|
88
|
+
const start = activationStart(shell);
|
|
89
|
+
const end = activationEnd(shell);
|
|
90
90
|
const source = `source ${shellQuote(installation.scriptPath)}`;
|
|
91
91
|
const functionName = basename(installation.scriptPath);
|
|
92
92
|
const body = shell === "zsh"
|
|
93
|
-
? `fpath=(${shellQuote(dirname(installation.scriptPath))} $fpath)\nautoload -Uz compinit\n(( $+functions[compdef] )) || compinit\nautoload -Uz -- ${shellQuote(functionName)}\ncompdef ${shellQuote(functionName)}
|
|
93
|
+
? `fpath=(${shellQuote(dirname(installation.scriptPath))} $fpath)\nautoload -Uz compinit\n(( $+functions[compdef] )) || compinit\nautoload -Uz -- ${shellQuote(functionName)}\ncompdef ${shellQuote(functionName)} 'yui'`
|
|
94
94
|
: source;
|
|
95
95
|
return `${start}\n${body}\n${end}`;
|
|
96
96
|
}
|
|
97
|
-
export function activationStart(shell
|
|
98
|
-
return `# >>> yui completion shell=${shell} identity
|
|
97
|
+
export function activationStart(shell) {
|
|
98
|
+
return `# >>> yui completion shell=${shell} identity=yui >>>`;
|
|
99
99
|
}
|
|
100
|
-
export function activationEnd(shell
|
|
101
|
-
return `# <<< yui completion shell=${shell} identity
|
|
100
|
+
export function activationEnd(shell) {
|
|
101
|
+
return `# <<< yui completion shell=${shell} identity=yui <<<`;
|
|
102
102
|
}
|
|
103
|
-
export function activationIsAutomatic(shell, installation, env
|
|
103
|
+
export function activationIsAutomatic(shell, installation, env) {
|
|
104
104
|
return shell === "fish"
|
|
105
|
-
&& installation.scriptPath === suggestedCompletionInstallation(shell, env
|
|
105
|
+
&& installation.scriptPath === suggestedCompletionInstallation(shell, env).scriptPath;
|
|
106
106
|
}
|
|
107
107
|
export function shellQuote(value) {
|
|
108
108
|
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
109
109
|
}
|
|
110
|
-
export function completionScriptIsCurrent(shell, installation
|
|
110
|
+
export function completionScriptIsCurrent(shell, installation) {
|
|
111
111
|
return safeRegularFile(installation.scriptPath)
|
|
112
|
-
&& readFileSync(installation.scriptPath, "utf8") === managedCompletionScript(shell
|
|
112
|
+
&& readFileSync(installation.scriptPath, "utf8") === managedCompletionScript(shell);
|
|
113
113
|
}
|
|
114
|
-
export function completionActivationIsCurrent(shell, installation, env
|
|
115
|
-
if (activationIsAutomatic(shell, installation, env
|
|
114
|
+
export function completionActivationIsCurrent(shell, installation, env) {
|
|
115
|
+
if (activationIsAutomatic(shell, installation, env))
|
|
116
116
|
return true;
|
|
117
117
|
if (!safeRegularFile(installation.activationPath))
|
|
118
118
|
return false;
|
|
119
119
|
const contents = readFileSync(installation.activationPath, "utf8");
|
|
120
|
-
const block = activationBlock(shell, installation
|
|
120
|
+
const block = activationBlock(shell, installation);
|
|
121
121
|
return contents.split(block).length === 2;
|
|
122
122
|
}
|
|
123
123
|
function safeRegularFile(path) {
|
|
@@ -4,21 +4,19 @@ import { COMPLETION_SHELLS, completionActivationIsCurrent, completionScriptIsCur
|
|
|
4
4
|
export class FileCompletionManager {
|
|
5
5
|
#store;
|
|
6
6
|
#env;
|
|
7
|
-
|
|
8
|
-
constructor(store, env, identity) {
|
|
7
|
+
constructor(store, env) {
|
|
9
8
|
this.#store = store;
|
|
10
9
|
this.#env = { ...env };
|
|
11
|
-
this.#identity = identity;
|
|
12
10
|
}
|
|
13
11
|
inspect() {
|
|
14
12
|
const config = this.#store.getConfig();
|
|
15
13
|
const currentShell = currentCompletionShell(this.#env);
|
|
16
14
|
const states = COMPLETION_SHELLS.map((shell) => {
|
|
17
|
-
const suggested = suggestedCompletionInstallation(shell, this.#env
|
|
15
|
+
const suggested = suggestedCompletionInstallation(shell, this.#env);
|
|
18
16
|
const stored = config.completionInstallations?.[shell];
|
|
19
17
|
const installation = stored ?? suggested;
|
|
20
|
-
const scriptCurrent = completionScriptIsCurrent(shell, installation
|
|
21
|
-
const activationCurrent = completionActivationIsCurrent(shell, installation, this.#env
|
|
18
|
+
const scriptCurrent = completionScriptIsCurrent(shell, installation);
|
|
19
|
+
const activationCurrent = completionActivationIsCurrent(shell, installation, this.#env);
|
|
22
20
|
const status = scriptCurrent && activationCurrent
|
|
23
21
|
? "Installed"
|
|
24
22
|
: stored === undefined ? "Not installed" : "Needs repair";
|
|
@@ -37,15 +35,12 @@ export class FileCompletionManager {
|
|
|
37
35
|
});
|
|
38
36
|
});
|
|
39
37
|
return Object.freeze({
|
|
40
|
-
identity:
|
|
38
|
+
identity: "yui",
|
|
41
39
|
...(currentShell === undefined ? {} : { currentShell }),
|
|
42
40
|
states: Object.freeze(states)
|
|
43
41
|
});
|
|
44
42
|
}
|
|
45
43
|
install(request) {
|
|
46
|
-
installCompletion(this.#store, request.shell, request.installation, this.#env,
|
|
44
|
+
installCompletion(this.#store, request.shell, request.installation, this.#env, request.activate);
|
|
47
45
|
}
|
|
48
46
|
}
|
|
49
|
-
export function resolveCliIdentity(env) {
|
|
50
|
-
return env.YUI_CLI_NAME === "yui-dev" ? "yui-dev" : "yui";
|
|
51
|
-
}
|
|
@@ -14,8 +14,6 @@ export const CONFIG_DEFINITIONS = Object.freeze([
|
|
|
14
14
|
{ key: "runtime-health", domain: "runtime", property: "runtimeHealth", label: "Runtime health thresholds", summary: "Quiet, checkpoint-overdue, and read-only diagnostic thresholds in seconds; values must be strictly increasing (defaults: 300/900/1800).", takesEffect: "CLI and Web projections immediately; scheduler diagnostics after the Controller restarts." },
|
|
15
15
|
{ key: "agent-launch-inactivity-timeout-seconds", domain: "runtime", property: "agentLaunchInactivityTimeoutSeconds", label: "Agent launch inactivity timeout", summary: "Maximum launch silence before startup fails, 15-3600 seconds (default: 300).", takesEffect: "After the Controller restarts." },
|
|
16
16
|
{ key: "delivery-timeout-seconds", domain: "runtime", property: "deliveryTimeoutSeconds", label: "Delivery timeout", summary: "Total control-plane delivery retry budget, 5-600 seconds (default: 120).", takesEffect: "After the Controller restarts; internal retry cadence remains automatic." },
|
|
17
|
-
{ key: "leader-next-action", domain: "workflow", property: "leaderNextActionMode", label: "Leader next-action mode", summary: "Leader next-action mode: display, warn, or enforce (default: display).", takesEffect: "The next Leader next-action projection or gate." },
|
|
18
|
-
{ key: "leader-semantic-budget-runs", domain: "workflow", property: "leaderSemanticBudgetRuns", label: "Leader semantic budget", summary: "Consecutive completed Leader AgentRuns without durable delivery progress before warning, 1-20 (default: 3).", takesEffect: "The next Leader delivery guard evaluation." },
|
|
19
17
|
{ key: "review", domain: "workflow", property: "review", label: "Review", summary: "Optional global WorkItem review rule: a configured Role plus always, leader, or final trigger. Setup leaves it disabled so the Leader may review directly or delegate selectively.", takesEffect: "The next Candidate snapshot; in-flight Candidates and ReviewRounds keep their policy." },
|
|
20
18
|
{ key: "resources-gc-mode", domain: "resources", property: "resourcesGcMode", label: "Resources GC mode", summary: "Resource GC mode: report or quarantine (default: report).", takesEffect: "The next resource GC operation." },
|
|
21
19
|
{ key: "resources-gc-auto-quarantine", domain: "resources", property: "resourcesGcAutoQuarantine", label: "Resources GC auto-quarantine", summary: "Automatically quarantine eligible terminal Task resources (default: false).", takesEffect: "The next eligible automatic resource GC operation." },
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const DEFAULT_TIME_ZONE = "Asia/Shanghai";
|
|
2
|
+
export function resolveTimeZone(value) {
|
|
3
|
+
const timeZone = value ?? DEFAULT_TIME_ZONE;
|
|
4
|
+
if (typeof timeZone !== "string" || timeZone.trim() !== timeZone || timeZone.length === 0) {
|
|
5
|
+
throw new TypeError("timeZone must be a valid IANA timezone.");
|
|
6
|
+
}
|
|
7
|
+
try {
|
|
8
|
+
new Intl.DateTimeFormat("en", { timeZone }).format(0);
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
throw new TypeError("timeZone must be a valid IANA timezone.");
|
|
12
|
+
}
|
|
13
|
+
return timeZone;
|
|
14
|
+
}
|
package/dist/config/yuiConfig.js
CHANGED
|
@@ -49,31 +49,6 @@ export function reconciliationIntervalMilliseconds(value) {
|
|
|
49
49
|
}
|
|
50
50
|
return seconds * 1_000;
|
|
51
51
|
}
|
|
52
|
-
/**
|
|
53
|
-
* Issue 07 (Leader convergence) feature mode. `display` only shows the
|
|
54
|
-
* read-only next-action decision support; `warn` additionally reports
|
|
55
|
-
* duplicate deliveries and semantic-budget warnings; `enforce` hard-blocks
|
|
56
|
-
* only exact duplicates, while semantic-budget exhaustion remains a warning
|
|
57
|
-
* because it must not override Leader judgment. The mode is additive and
|
|
58
|
-
* optional — Homes without it keep the `display` default, so no config
|
|
59
|
-
* migration is required.
|
|
60
|
-
*/
|
|
61
|
-
export const LEADER_NEXT_ACTION_MODES = ["display", "warn", "enforce"];
|
|
62
|
-
export const DEFAULT_LEADER_NEXT_ACTION_MODE = "display";
|
|
63
|
-
export function resolveLeaderNextActionMode(value) {
|
|
64
|
-
if (value === undefined || value === null)
|
|
65
|
-
return DEFAULT_LEADER_NEXT_ACTION_MODE;
|
|
66
|
-
if (typeof value !== "string") {
|
|
67
|
-
throw new TypeError("leaderNextActionMode must be display, warn, or enforce.");
|
|
68
|
-
}
|
|
69
|
-
const normalized = value.trim().toLowerCase();
|
|
70
|
-
if (normalized.length === 0)
|
|
71
|
-
return DEFAULT_LEADER_NEXT_ACTION_MODE;
|
|
72
|
-
if (!LEADER_NEXT_ACTION_MODES.includes(normalized)) {
|
|
73
|
-
throw new TypeError("leaderNextActionMode must be display, warn, or enforce.");
|
|
74
|
-
}
|
|
75
|
-
return normalized;
|
|
76
|
-
}
|
|
77
52
|
// ── Executable paths ──────────────────────────────────────────────────────
|
|
78
53
|
export function resolveTmuxBin(value) {
|
|
79
54
|
if (value === undefined || value === null)
|
|
@@ -115,7 +90,6 @@ export const DEFAULT_CONTROLLER_TASK_CONCURRENCY = 4;
|
|
|
115
90
|
export const MAX_CONTROLLER_TASK_CONCURRENCY = 32;
|
|
116
91
|
export const DEFAULT_AGENT_LAUNCH_INACTIVITY_TIMEOUT_SECONDS = 300;
|
|
117
92
|
export const DEFAULT_DELIVERY_TIMEOUT_SECONDS = 120;
|
|
118
|
-
export const DEFAULT_LEADER_SEMANTIC_BUDGET_RUNS = 3;
|
|
119
93
|
export const DEFAULT_TMUX_HISTORY_LIMIT = 100_000;
|
|
120
94
|
export function resolveRuntimeHealth(configured) {
|
|
121
95
|
if (configured === undefined || configured === null)
|
|
@@ -141,9 +115,6 @@ export function resolveAgentLaunchInactivityTimeoutSeconds(value) {
|
|
|
141
115
|
export function resolveDeliveryTimeoutSeconds(value) {
|
|
142
116
|
return resolveBoundedPositiveInteger(value, DEFAULT_DELIVERY_TIMEOUT_SECONDS, 5, 600, "deliveryTimeoutSeconds");
|
|
143
117
|
}
|
|
144
|
-
export function resolveLeaderSemanticBudgetRuns(value) {
|
|
145
|
-
return resolveBoundedPositiveInteger(value, DEFAULT_LEADER_SEMANTIC_BUDGET_RUNS, 1, 20, "leaderSemanticBudgetRuns");
|
|
146
|
-
}
|
|
147
118
|
export function resolveTmuxHistoryLimit(value) {
|
|
148
119
|
return resolveBoundedPositiveInteger(value, DEFAULT_TMUX_HISTORY_LIMIT, 1_000, 1_000_000, "tmuxHistoryLimit");
|
|
149
120
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { providerRetryProjection } from "../runtime/providerRetry.js";
|
|
1
2
|
import { operationalTaskRecords } from "../task/taskRecordRetirement.js";
|
|
2
3
|
import { TASK_COMPLETION_PUBLISHED_TREE_AUTHORIZED_EVENT } from "../task/publicationReference.js";
|
|
3
4
|
import { RUN_INPUT_MAX_DELTAS } from "./runInputContract.js";
|
|
@@ -277,8 +278,7 @@ export function buildRunContextPack(store, taskId, runId) {
|
|
|
277
278
|
}
|
|
278
279
|
/** Reads the Task's current in-flight execution, outside the frozen contract. */
|
|
279
280
|
function readLiveTaskState(store, taskId) {
|
|
280
|
-
const activeRuns = store.
|
|
281
|
-
.filter((run) => run.status === "active")
|
|
281
|
+
const activeRuns = store.listActiveRuns(taskId)
|
|
282
282
|
.map((run) => Object.freeze({
|
|
283
283
|
runId: run.id,
|
|
284
284
|
roleName: run.roleName,
|
|
@@ -287,7 +287,7 @@ function readLiveTaskState(store, taskId) {
|
|
|
287
287
|
...(run.reviewRoundId === undefined ? {} : { reviewRoundId: run.reviewRoundId })
|
|
288
288
|
}));
|
|
289
289
|
const activeTaskReviews = store.listReviewRounds(taskId)
|
|
290
|
-
.filter((round) => (
|
|
290
|
+
.filter((round) => (round.scope === "task"
|
|
291
291
|
&& (round.status === "pending" || round.status === "running")))
|
|
292
292
|
.map((round) => Object.freeze({
|
|
293
293
|
reviewRoundId: round.id,
|
|
@@ -295,6 +295,8 @@ function readLiveTaskState(store, taskId) {
|
|
|
295
295
|
status: round.status
|
|
296
296
|
}));
|
|
297
297
|
return Object.freeze({
|
|
298
|
+
providerRetries: Object.freeze(store.listRoleSessionSets(taskId).flatMap(set => set.providerBinding?.retry === undefined
|
|
299
|
+
? [] : [{ roleName: set.owner.roleName, retry: providerRetryProjection(set.providerBinding) }])),
|
|
298
300
|
activeRuns: Object.freeze(activeRuns),
|
|
299
301
|
activeTaskReviews: Object.freeze(activeTaskReviews)
|
|
300
302
|
});
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { usageError } from "../errors/cliError.js";
|
|
2
|
+
import { contextContentDigest } from "./contextSnapshot.js";
|
|
3
|
+
import { materialize, resolveContextReader } from "./taskContext.js";
|
|
4
|
+
import { CATALOG_ATTENTION } from "../storage/taskCatalog.js";
|
|
5
|
+
const TASK_STATUSES = ["draft", "active", "completed", "cancelled", "archived"];
|
|
6
|
+
const PAGE_BYTES = 32 * 1024;
|
|
7
|
+
const SUMMARY_BYTES = 512;
|
|
8
|
+
const MAX_LIMIT = 100;
|
|
9
|
+
export function parseTaskCatalogOptions(args) {
|
|
10
|
+
const values = new Map();
|
|
11
|
+
let all = false;
|
|
12
|
+
for (let i = 0; i < args.length; i++) {
|
|
13
|
+
const key = args[i];
|
|
14
|
+
if (key === "--all" && !all) {
|
|
15
|
+
all = true;
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
if (!["--limit", "--cursor", "--status", "--project", "--search", "--attention"].includes(key)
|
|
19
|
+
|| values.has(key) || args[i + 1] === undefined || args[i + 1].startsWith("--")) {
|
|
20
|
+
throw usageError("Task list expects [--all] [--status <status>] [--project <id>] [--search <text>] [--attention <category>] [--limit <1..100>] [--cursor <cursor>].");
|
|
21
|
+
}
|
|
22
|
+
values.set(key, args[++i]);
|
|
23
|
+
}
|
|
24
|
+
const status = values.get("--status");
|
|
25
|
+
if (status !== undefined && !TASK_STATUSES.includes(status)) {
|
|
26
|
+
throw usageError("Unknown Task catalog status.");
|
|
27
|
+
}
|
|
28
|
+
const attention = values.get("--attention");
|
|
29
|
+
if (attention !== undefined && !CATALOG_ATTENTION.includes(attention)) {
|
|
30
|
+
throw usageError(`Task catalog attention must be one of: ${CATALOG_ATTENTION.join(", ")}.`);
|
|
31
|
+
}
|
|
32
|
+
const limit = values.has("--limit") ? Number(values.get("--limit")) : 20;
|
|
33
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > MAX_LIMIT)
|
|
34
|
+
throw usageError("Task catalog limit must be between 1 and 100.");
|
|
35
|
+
const search = values.get("--search")?.trim();
|
|
36
|
+
const project = values.get("--project")?.trim();
|
|
37
|
+
if ((search?.length ?? 0) > 256 || (project?.length ?? 0) > 256 || project === "") {
|
|
38
|
+
throw usageError("Task catalog filters exceed their text limit.");
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
all: all || status === "archived", limit,
|
|
42
|
+
...(status === undefined ? {} : { status: status }),
|
|
43
|
+
...(attention === undefined ? {} : { attention: attention }),
|
|
44
|
+
...(search ? { search } : {}),
|
|
45
|
+
...(project === undefined ? {} : { project }),
|
|
46
|
+
...(values.has("--cursor") ? { cursor: values.get("--cursor") } : {})
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/** Task-local Leaders discover only their Task. Assignment Roles use their
|
|
50
|
+
* existing Context pack: whole-Task counts would leak unrelated assignments. */
|
|
51
|
+
export function taskCatalogScope(store, environment) {
|
|
52
|
+
const caller = resolveContextReader(store, environment);
|
|
53
|
+
if (caller !== undefined && caller.roleName !== "leader") {
|
|
54
|
+
throw usageError("Task discovery is unavailable to an Assignment-scoped Role; use its authorized Run Context.");
|
|
55
|
+
}
|
|
56
|
+
return caller?.taskId;
|
|
57
|
+
}
|
|
58
|
+
export function readTaskCatalog(store, options, environment = {}) {
|
|
59
|
+
return store.transaction(reader => {
|
|
60
|
+
const taskId = taskCatalogScope(reader, environment);
|
|
61
|
+
const { cursor: rawCursor, ...filters } = options;
|
|
62
|
+
if (!Number.isSafeInteger(filters.limit) || filters.limit < 1 || filters.limit > MAX_LIMIT) {
|
|
63
|
+
throw usageError("Task catalog limit must be between 1 and 100.");
|
|
64
|
+
}
|
|
65
|
+
const scope = contextContentDigest({ taskId: taskId ?? null, ...filters });
|
|
66
|
+
const cursor = rawCursor === undefined ? undefined : decodeCursor(rawCursor, scope);
|
|
67
|
+
const facts = reader.queryTaskCatalog({
|
|
68
|
+
...filters, ...(taskId === undefined ? {} : { taskId }),
|
|
69
|
+
...(cursor === undefined ? {} : { after: cursor.after, through: cursor.through }),
|
|
70
|
+
limit: options.limit + 1
|
|
71
|
+
});
|
|
72
|
+
const refs = new Map();
|
|
73
|
+
const getRef = (id) => {
|
|
74
|
+
let ref = refs.get(id);
|
|
75
|
+
if (ref === undefined) {
|
|
76
|
+
const task = reader.getTask(id);
|
|
77
|
+
if (task === null)
|
|
78
|
+
throw usageError("Task catalog changed during the read; retry.");
|
|
79
|
+
ref = { taskId: id, ...materialize("task", id, task).ref };
|
|
80
|
+
refs.set(id, ref);
|
|
81
|
+
}
|
|
82
|
+
return ref;
|
|
83
|
+
};
|
|
84
|
+
const attention = Object.fromEntries(CATALOG_ATTENTION.map(kind => {
|
|
85
|
+
const source = facts.attention[kind];
|
|
86
|
+
const selected = [];
|
|
87
|
+
for (const id of source.taskIds) {
|
|
88
|
+
const ref = getRef(id);
|
|
89
|
+
if (bytes([...selected, ref]) <= 2048)
|
|
90
|
+
selected.push(ref);
|
|
91
|
+
}
|
|
92
|
+
return [kind, {
|
|
93
|
+
count: source.count,
|
|
94
|
+
unit: kind === "executionSignals" ? "signals" : "records",
|
|
95
|
+
refs: selected,
|
|
96
|
+
// Samples identify affected Tasks, not individual records. Count and
|
|
97
|
+
// sample size therefore must never be subtracted from one another.
|
|
98
|
+
taskCount: source.taskCount,
|
|
99
|
+
omittedTaskRefs: source.taskCount - selected.length,
|
|
100
|
+
query: { all: options.all, attention: kind }
|
|
101
|
+
}];
|
|
102
|
+
}));
|
|
103
|
+
const response = {
|
|
104
|
+
view: "compact",
|
|
105
|
+
scope: { taskId: taskId ?? null, archived: options.all ? "included" : "excluded",
|
|
106
|
+
attention: "authorized-catalog-before-filters", executionSignals: "raw-inspection-candidates-not-execution-status" },
|
|
107
|
+
filters, total: facts.total, counts: facts.counts, attention,
|
|
108
|
+
tasks: [],
|
|
109
|
+
nextCursor: null,
|
|
110
|
+
consistency: "current-per-page; refresh for membership changes; new creation keys after the upper bound excluded",
|
|
111
|
+
limits: { pageBytes: PAGE_BYTES, summaryBytes: SUMMARY_BYTES, maxTasks: options.limit, attentionTaskRefsPerCategory: 4 }
|
|
112
|
+
};
|
|
113
|
+
const through = cursor?.through ?? facts.through;
|
|
114
|
+
const continuation = (after) => through === null ? null
|
|
115
|
+
: Buffer.from(JSON.stringify({ version: 1, scope, after, through })).toString("base64url");
|
|
116
|
+
for (const row of facts.rows.slice(0, options.limit)) {
|
|
117
|
+
const ref = getRef(row.id);
|
|
118
|
+
const summary = row.summary === null ? null : truncateUtf8(row.summary, SUMMARY_BYTES);
|
|
119
|
+
const title = truncateUtf8(row.title, 256);
|
|
120
|
+
// SQL already limits these fields. Compare against the selected original
|
|
121
|
+
// only when necessary; length-at-limit is conservatively marked omitted.
|
|
122
|
+
const item = {
|
|
123
|
+
id: row.id, title, status: row.status, createdAt: row.createdAt, updatedAt: row.updatedAt,
|
|
124
|
+
summary, summaryStatus: row.summaryPresent ? "available" : "missing",
|
|
125
|
+
omitted: { title: row.title.length >= 256 || title !== row.title,
|
|
126
|
+
summary: row.summary !== null && (row.summary.length >= 512 || summary !== row.summary) },
|
|
127
|
+
counts: { workItems: row.workItems, activeRuns: row.activeRuns },
|
|
128
|
+
attention: Object.fromEntries(CATALOG_ATTENTION.map(kind => [kind, row[kind]])),
|
|
129
|
+
ref
|
|
130
|
+
};
|
|
131
|
+
const next = continuation({ id: row.id, createdAt: row.createdAt });
|
|
132
|
+
if (bytes({ ok: true, data: { ...response, tasks: [...response.tasks, item], nextCursor: next } }) + 1 > PAGE_BYTES)
|
|
133
|
+
break;
|
|
134
|
+
response.tasks.push(item);
|
|
135
|
+
}
|
|
136
|
+
if (response.tasks.length < facts.rows.length) {
|
|
137
|
+
const last = response.tasks.at(-1);
|
|
138
|
+
if (last === undefined)
|
|
139
|
+
throw usageError("Task catalog identity/attention metadata exceeds the page byte budget.");
|
|
140
|
+
response.nextCursor = continuation({ id: last.id, createdAt: last.createdAt });
|
|
141
|
+
}
|
|
142
|
+
if (bytes({ ok: true, data: response }) + 1 > PAGE_BYTES)
|
|
143
|
+
throw usageError("Task catalog metadata exceeds the page byte budget.");
|
|
144
|
+
return response;
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
export function renderTaskCatalog(result) {
|
|
148
|
+
return [
|
|
149
|
+
`Tasks (compact): ${result.tasks.length} shown; ${result.total} matching`,
|
|
150
|
+
...result.tasks.map(task => `${task.id}\t${task.status}\t${task.title}\n ${task.summary ?? "(summary missing)"}`),
|
|
151
|
+
`Attention across catalog: ${CATALOG_ATTENTION.map(kind => `${kind}=${result.attention[kind].count}`).join(", ")}`,
|
|
152
|
+
"Expand: yui task context <task-id>; inspect the Task ref for original requirements.",
|
|
153
|
+
...(result.nextCursor === null ? [] : [`Next cursor: ${result.nextCursor}`])
|
|
154
|
+
].join("\n") + "\n";
|
|
155
|
+
}
|
|
156
|
+
function bytes(value) { return Buffer.byteLength(JSON.stringify(value)); }
|
|
157
|
+
function truncateUtf8(value, max) {
|
|
158
|
+
let result = "";
|
|
159
|
+
let size = 0;
|
|
160
|
+
for (const point of value) {
|
|
161
|
+
size += Buffer.byteLength(point);
|
|
162
|
+
if (size > max)
|
|
163
|
+
break;
|
|
164
|
+
result += point;
|
|
165
|
+
}
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
168
|
+
function decodeCursor(raw, scope) {
|
|
169
|
+
try {
|
|
170
|
+
if (raw.length > 4096 || !/^[A-Za-z0-9_-]+$/.test(raw))
|
|
171
|
+
throw new Error();
|
|
172
|
+
const parsed = JSON.parse(Buffer.from(raw, "base64url").toString("utf8"));
|
|
173
|
+
const validKey = (key) => key && typeof key.id === "string" && key.id.length > 0
|
|
174
|
+
&& typeof key.createdAt === "string" && Number.isFinite(Date.parse(key.createdAt));
|
|
175
|
+
if (parsed.version !== 1 || parsed.scope !== scope || !validKey(parsed.after) || !validKey(parsed.through)
|
|
176
|
+
|| parsed.after.createdAt > parsed.through.createdAt
|
|
177
|
+
|| (parsed.after.createdAt === parsed.through.createdAt
|
|
178
|
+
&& Buffer.compare(Buffer.from(parsed.after.id), Buffer.from(parsed.through.id)) > 0))
|
|
179
|
+
throw new Error();
|
|
180
|
+
return parsed;
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
throw usageError("Invalid Task catalog cursor or cursor belongs to another scope/filter.");
|
|
184
|
+
}
|
|
185
|
+
}
|