@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
package/ARCHITECTURE.md
CHANGED
|
@@ -93,8 +93,9 @@ meaning of the report. See [result consumption](docs/agent-result-consumption.md
|
|
|
93
93
|
## Planning, workspaces and resources
|
|
94
94
|
|
|
95
95
|
Draft contains planning facts and Project bindings, not an adopted delivery
|
|
96
|
-
workspace. Its private planning directory is
|
|
97
|
-
|
|
96
|
+
workspace. Its private planning directory is under
|
|
97
|
+
`<YUI_HOME>/runtime/task-runtimes/planning`, separate from durable control data
|
|
98
|
+
and delivery trees. Planning Sessions capture `planning` authority. The Leader can
|
|
98
99
|
persist an activation request during a Run or ordinary discussion and return;
|
|
99
100
|
native quiescence releases the intent for current-authority and resource checks.
|
|
100
101
|
|
package/ARCHITECTURE.zh-CN.md
CHANGED
|
@@ -72,8 +72,9 @@ Reviewer 输出留在那个 Run 上。审查策略和显式的 Task-final 合同
|
|
|
72
72
|
|
|
73
73
|
## 规划、工作区与资源
|
|
74
74
|
|
|
75
|
-
Draft 包含规划事实和 Project
|
|
76
|
-
|
|
75
|
+
Draft 包含规划事实和 Project 绑定,而不是一个已采用的交付工作区。它私有的规划目录位于
|
|
76
|
+
`<YUI_HOME>/runtime/task-runtimes/planning`,与持久控制数据和交付树分开。
|
|
77
|
+
规划 Session 捕获 `planning` 权限。Leader 可以在一个 Run 或
|
|
77
78
|
普通讨论中持久化一个激活请求并返回;原生静止会把该意图释放出来,进行当前权限和资源
|
|
78
79
|
检查。
|
|
79
80
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
+
import { currentFileLockOwner, fileLockOwnerIsLive } from "../core/fileLockOwner.js";
|
|
3
4
|
/**
|
|
4
5
|
* Short per-Task commit fence for artifact repositories.
|
|
5
6
|
*
|
|
@@ -9,9 +10,9 @@ import { join } from "node:path";
|
|
|
9
10
|
* into the wrong commit, or race the expected-HEAD check. This fence serializes
|
|
10
11
|
* the commit critical section for one Task.
|
|
11
12
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* contended fence
|
|
13
|
+
* The Project maintenance fence waits asynchronously for longer operations.
|
|
14
|
+
* An artifact save is short, so this synchronous critical section briefly
|
|
15
|
+
* retries a contended fence before giving up. It otherwise shares the same
|
|
15
16
|
* crash-safe design: an exclusive directory under the Home's `locks/` area
|
|
16
17
|
* (O_EXCL via mkdir), an owner file recording PID + process start time so a
|
|
17
18
|
* recycled PID can never pass for the original holder, and reclaim of a stale
|
|
@@ -47,12 +48,13 @@ export function artifactCommitLockPath(home, taskId) {
|
|
|
47
48
|
*/
|
|
48
49
|
export function acquireArtifactCommitLock(home, taskId) {
|
|
49
50
|
const lock = artifactCommitLockPath(home, taskId);
|
|
51
|
+
const ownerIdentity = currentFileLockOwner();
|
|
50
52
|
mkdirSync(join(home, "locks", "task-artifacts"), { recursive: true, mode: 0o700 });
|
|
51
53
|
const deadline = Date.now() + ARTIFACT_COMMIT_LOCK_TIMEOUT_MS;
|
|
52
54
|
while (true) {
|
|
53
55
|
try {
|
|
54
56
|
mkdirSync(lock, { mode: 0o700 });
|
|
55
|
-
|
|
57
|
+
writeOwnerIdentity(lock, ownerIdentity);
|
|
56
58
|
let released = false;
|
|
57
59
|
return () => {
|
|
58
60
|
if (released)
|
|
@@ -72,8 +74,7 @@ export function acquireArtifactCommitLock(home, taskId) {
|
|
|
72
74
|
}
|
|
73
75
|
}
|
|
74
76
|
/** Write this process's owner identity and return the exact bytes recorded. */
|
|
75
|
-
function writeOwnerIdentity(lock) {
|
|
76
|
-
const identity = `${process.pid}:${processStartIdentity() ?? ""}`;
|
|
77
|
+
function writeOwnerIdentity(lock, identity = currentFileLockOwner()) {
|
|
77
78
|
writeFileSync(join(lock, "owner"), `${identity}\n`, { mode: 0o600 });
|
|
78
79
|
return identity;
|
|
79
80
|
}
|
|
@@ -109,8 +110,8 @@ function reclaimStaleArtifactCommitLock(lock) {
|
|
|
109
110
|
catch (error) {
|
|
110
111
|
if (!isEnoent(error))
|
|
111
112
|
throw error;
|
|
112
|
-
//
|
|
113
|
-
//
|
|
113
|
+
// Allow publication its initial grace period; an older missing owner is
|
|
114
|
+
// diagnosed as unverified below, never treated as a dead creator.
|
|
114
115
|
try {
|
|
115
116
|
if (Date.now() - statSync(lock).mtimeMs < STALE_ARTIFACT_COMMIT_LOCK_AGE_MS)
|
|
116
117
|
return;
|
|
@@ -131,7 +132,7 @@ function reclaimStaleArtifactCommitLock(lock) {
|
|
|
131
132
|
return;
|
|
132
133
|
throw error;
|
|
133
134
|
}
|
|
134
|
-
if (
|
|
135
|
+
if (fileLockOwnerIsLive(lock))
|
|
135
136
|
return;
|
|
136
137
|
const reclaimLock = `${lock}.reclaim`;
|
|
137
138
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
@@ -171,7 +172,7 @@ function reclaimStaleArtifactCommitLock(lock) {
|
|
|
171
172
|
}
|
|
172
173
|
if (currentOwner !== expectedOwner)
|
|
173
174
|
return;
|
|
174
|
-
if (
|
|
175
|
+
if (fileLockOwnerIsLive(lock))
|
|
175
176
|
return;
|
|
176
177
|
rmSync(lock, { recursive: true, force: true });
|
|
177
178
|
}
|
|
@@ -182,63 +183,23 @@ function reclaimStaleArtifactCommitLock(lock) {
|
|
|
182
183
|
}
|
|
183
184
|
}
|
|
184
185
|
/**
|
|
185
|
-
* Reclaim a reclaim-lock directory only
|
|
186
|
-
*
|
|
186
|
+
* Reclaim a reclaim-lock directory only with a proven dead generation and
|
|
187
|
+
* after the age bound. Returns true when it removed
|
|
187
188
|
* the lock (caller retries), false otherwise.
|
|
188
189
|
*/
|
|
189
190
|
function reclaimOrphanedReclaimLock(reclaimLock) {
|
|
190
191
|
try {
|
|
191
192
|
if (Date.now() - statSync(reclaimLock).mtimeMs < STALE_ARTIFACT_COMMIT_LOCK_AGE_MS)
|
|
192
193
|
return false;
|
|
193
|
-
if (
|
|
194
|
+
if (fileLockOwnerIsLive(reclaimLock))
|
|
194
195
|
return false;
|
|
195
196
|
rmSync(reclaimLock, { recursive: true, force: true });
|
|
196
197
|
return true;
|
|
197
198
|
}
|
|
198
|
-
catch (error) {
|
|
199
|
-
return isEnoent(error);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
function lockOwnerIsAlive(lock) {
|
|
203
|
-
let owner;
|
|
204
|
-
try {
|
|
205
|
-
owner = readFileSync(join(lock, "owner"), "utf8").trim();
|
|
206
|
-
}
|
|
207
199
|
catch (error) {
|
|
208
200
|
if (isEnoent(error))
|
|
209
|
-
return
|
|
210
|
-
|
|
211
|
-
}
|
|
212
|
-
const separator = owner.indexOf(":");
|
|
213
|
-
const pid = Number.parseInt(separator < 0 ? owner : owner.slice(0, separator), 10);
|
|
214
|
-
if (!Number.isInteger(pid) || pid <= 0)
|
|
215
|
-
return false;
|
|
216
|
-
const recordedIdentity = separator < 0 ? "" : owner.slice(separator + 1);
|
|
217
|
-
const currentIdentity = processStartIdentity(pid);
|
|
218
|
-
if (currentIdentity !== undefined) {
|
|
219
|
-
return recordedIdentity !== "" && currentIdentity === recordedIdentity;
|
|
220
|
-
}
|
|
221
|
-
return processIsAlive(pid);
|
|
222
|
-
}
|
|
223
|
-
/** Linux process start time (clock ticks since boot) for a PID; undefined off /proc. */
|
|
224
|
-
function processStartIdentity(pid = process.pid) {
|
|
225
|
-
try {
|
|
226
|
-
const stat = readFileSync(`/proc/${pid}/stat`, "utf8");
|
|
227
|
-
const close = stat.lastIndexOf(")");
|
|
228
|
-
const fields = stat.slice(close + 2).split(" ");
|
|
229
|
-
return fields[19] ?? "0"; // field 22: starttime
|
|
230
|
-
}
|
|
231
|
-
catch {
|
|
232
|
-
return undefined;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
function processIsAlive(pid) {
|
|
236
|
-
try {
|
|
237
|
-
process.kill(pid, 0);
|
|
238
|
-
return true;
|
|
239
|
-
}
|
|
240
|
-
catch (error) {
|
|
241
|
-
return error instanceof Error && "code" in error && error.code === "EPERM";
|
|
201
|
+
return true;
|
|
202
|
+
throw error;
|
|
242
203
|
}
|
|
243
204
|
}
|
|
244
205
|
function isEnoent(error) {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
1
|
import { createHash } from "node:crypto";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
4
4
|
import { dirname, join } from "node:path";
|
|
5
|
-
import { ManagedGitError, externalProgramConfigViolations, managedGit, managedGitBuffer, managedGitSucceeds, requireCommitId } from "./managedGit.js";
|
|
6
5
|
import { acquireArtifactCommitLock } from "./artifactCommitLock.js";
|
|
7
6
|
import { resolveContainedArtifactPath, safeRelativeArtifactPath, taskArtifactRepoPath } from "./artifactPaths.js";
|
|
7
|
+
import { ManagedGitError, externalProgramConfigViolations, managedGit, managedGitBuffer, managedGitSucceeds, requireCommitId } from "./managedGit.js";
|
|
8
8
|
/**
|
|
9
9
|
* Per-Task local-only Git artifact repository.
|
|
10
10
|
*
|
|
@@ -106,7 +106,7 @@ export async function selectAgentPermission(resolved, io, current) {
|
|
|
106
106
|
export function renderAgentConfigurationResolutionNotice(resolved) {
|
|
107
107
|
const lines = [];
|
|
108
108
|
if (resolved.source === "cache") {
|
|
109
|
-
lines.push(`! Runtime capability request failed (${resolved.failure
|
|
109
|
+
lines.push((resolved.failure === undefined ? "" : `! Runtime capability request failed (${resolved.failure.message}). `)
|
|
110
110
|
+ `Showing cached options from ${resolved.fetchedAt ?? "an earlier request"}; they may be stale.`);
|
|
111
111
|
}
|
|
112
112
|
else if (resolved.source === "fallback") {
|
|
@@ -116,7 +116,8 @@ const agentChildren = [
|
|
|
116
116
|
{
|
|
117
117
|
name: "capabilities",
|
|
118
118
|
summary: "Probe one Agent CLI for runtime configuration options.",
|
|
119
|
-
usage: "yui config agent capabilities <id>"
|
|
119
|
+
usage: "yui config agent capabilities <id> [--refresh]",
|
|
120
|
+
options: ["--refresh"]
|
|
120
121
|
},
|
|
121
122
|
{
|
|
122
123
|
name: "update",
|
|
@@ -293,7 +294,7 @@ const taskChildren = [
|
|
|
293
294
|
"--type": ["feature", "bugfix"]
|
|
294
295
|
}
|
|
295
296
|
},
|
|
296
|
-
{ name: "activate", summary: "
|
|
297
|
+
{ name: "activate", summary: "Adopt an existing Activation request for a Draft Task.", usage: "yui task activate <id>" },
|
|
297
298
|
{
|
|
298
299
|
name: "activation",
|
|
299
300
|
summary: "Request, cancel or inspect explicit Task Activation.",
|
|
@@ -378,9 +379,9 @@ const taskChildren = [
|
|
|
378
379
|
},
|
|
379
380
|
{
|
|
380
381
|
name: "list",
|
|
381
|
-
summary: "
|
|
382
|
-
usage: "yui task list [--all] [--
|
|
383
|
-
options: ["--all", "--
|
|
382
|
+
summary: "Discover Tasks through a bounded, filterable catalog.",
|
|
383
|
+
usage: "yui task list [--all] [--status <status>] [--project <id>] [--search <text>] [--attention <category>] [--limit <1..100>] [--cursor <cursor>]",
|
|
384
|
+
options: ["--all", "--status", "--project", "--search", "--attention", "--limit", "--cursor"]
|
|
384
385
|
},
|
|
385
386
|
{ name: "show", summary: "Show a Task.", usage: "yui task show <id>" },
|
|
386
387
|
{
|
|
@@ -432,8 +433,8 @@ const taskChildren = [
|
|
|
432
433
|
{
|
|
433
434
|
name: "integrate",
|
|
434
435
|
summary: "Rebase Task changes onto the remote development head through Integration.",
|
|
435
|
-
usage: "yui task upstream integrate <task> (--latest|--project <project>) [--check <command> ...]",
|
|
436
|
-
options: ["--latest", "--project", "--check"]
|
|
436
|
+
usage: "yui task upstream integrate <task> (--latest|--project <project>) [--check <command> ...] [--rerun-checks]",
|
|
437
|
+
options: ["--latest", "--project", "--check", "--rerun-checks"]
|
|
437
438
|
}
|
|
438
439
|
]
|
|
439
440
|
},
|
|
@@ -457,18 +458,17 @@ const taskChildren = [
|
|
|
457
458
|
{
|
|
458
459
|
name: "send",
|
|
459
460
|
summary: "Send a Task message. An unaddressed user/operator message carries a submission intent (record|discuss|develop) and an optional idempotency key.",
|
|
460
|
-
usage: "yui task message send <id> (<body>|--body-file <path|->) [--intent record|discuss|develop] [--request-id <key>] [--
|
|
461
|
-
options: ["--body-file", "--intent", "--request-id", "--
|
|
461
|
+
usage: "yui task message send <id> (<body>|--body-file <path|->) [--intent record|discuss|develop] [--request-id <key>] [--to <role> --work-item <id>|--review-round <id>]",
|
|
462
|
+
options: ["--body-file", "--intent", "--request-id", "--to", "--work-item", "--review-round"],
|
|
462
463
|
optionValues: {
|
|
463
|
-
"--intent": ["record", "discuss", "develop"]
|
|
464
|
-
"--wake-policy": ["leader", "none"]
|
|
464
|
+
"--intent": ["record", "discuss", "develop"]
|
|
465
465
|
},
|
|
466
466
|
fileOptions: ["--body-file"]
|
|
467
467
|
},
|
|
468
468
|
{
|
|
469
469
|
name: "queue",
|
|
470
|
-
summary: "Queue
|
|
471
|
-
usage: "yui task message queue <id> (<body>|--body-file <path|->) --request-id <id> [--to <role> --work-item <id>|--review-round <id>]",
|
|
470
|
+
summary: "Queue ordinary Leader input without --to; an explicit Role requires an existing WorkItem/ReviewRound Assignment. Idempotent by request id.",
|
|
471
|
+
usage: "yui task message queue <id> (<body>|--body-file <path|->) --request-id <id> [--to <role> (--work-item <id>|--review-round <id>)]",
|
|
472
472
|
options: ["--body-file", "--request-id", "--to", "--work-item", "--review-round"],
|
|
473
473
|
fileOptions: ["--body-file"]
|
|
474
474
|
},
|
|
@@ -492,12 +492,9 @@ const taskChildren = [
|
|
|
492
492
|
},
|
|
493
493
|
{
|
|
494
494
|
name: "update",
|
|
495
|
-
summary: "
|
|
496
|
-
usage: "yui task message update <task>/<message> (<body>|--body-file <path|->)
|
|
497
|
-
options: ["--body-file"
|
|
498
|
-
optionValues: {
|
|
499
|
-
"--wake-policy": ["leader", "none"]
|
|
500
|
-
},
|
|
495
|
+
summary: "Edit unkeyed Draft context without changing intent; inputs with request identities require a new Message.",
|
|
496
|
+
usage: "yui task message update <task>/<message> (<body>|--body-file <path|->)",
|
|
497
|
+
options: ["--body-file"],
|
|
501
498
|
fileOptions: ["--body-file"]
|
|
502
499
|
},
|
|
503
500
|
{
|
|
@@ -659,7 +656,7 @@ const taskChildren = [
|
|
|
659
656
|
summary: "Manage Roles within a Task.",
|
|
660
657
|
sections: [{ id: "manage", title: "Commands", entries: [
|
|
661
658
|
"add", "list", "status", "show", "update", "remove", "bind", "unbind",
|
|
662
|
-
"session", "interrupt", "view", "takeover", "release"
|
|
659
|
+
"capabilities", "session", "interrupt", "view", "takeover", "release"
|
|
663
660
|
] }],
|
|
664
661
|
children: [
|
|
665
662
|
{
|
|
@@ -676,6 +673,9 @@ const taskChildren = [
|
|
|
676
673
|
usage: "yui task role status <task> <role>"
|
|
677
674
|
},
|
|
678
675
|
{ name: "show", summary: "Show one Task Role.", usage: "yui task role show <task> <role>" },
|
|
676
|
+
{ name: "capabilities", summary: "Read native options using this Role's desired or exact failed launch configuration.",
|
|
677
|
+
usage: "yui task role capabilities <task> <role> [--error <event-id>] [--refresh]",
|
|
678
|
+
options: ["--error", "--refresh"] },
|
|
679
679
|
{
|
|
680
680
|
name: "update",
|
|
681
681
|
summary: "Update a Task Role; Agent settings target the named or active binding without switching it.",
|
|
@@ -947,13 +947,13 @@ const taskChildren = [
|
|
|
947
947
|
{
|
|
948
948
|
name: "integration",
|
|
949
949
|
summary: "Integrate WorkItem results and upstream commits with Leader-owned decisions.",
|
|
950
|
-
sections: [{ id: "manage", title: "Commands", entries: ["start", "continue", "resolve", "abort", "supersede", "list", "show", "cleanup"
|
|
950
|
+
sections: [{ id: "manage", title: "Commands", entries: ["start", "continue", "resolve", "abort", "supersede", "list", "show", "cleanup"] }],
|
|
951
951
|
children: [
|
|
952
952
|
{
|
|
953
953
|
name: "start",
|
|
954
954
|
summary: "Build, validate, and CAS-commit an integration candidate.",
|
|
955
|
-
usage: "yui task integration start <task> --work-item <id> --strategy <ff|cherry-pick|merge|manual> [--project <project>] [--target <ref>] [--check <command> ...]",
|
|
956
|
-
options: ["--work-item", "--strategy", "--project", "--target", "--check"],
|
|
955
|
+
usage: "yui task integration start <task> --work-item <id> --strategy <ff|cherry-pick|merge|manual> [--project <project>] [--target <ref>] [--check <command> ...] [--rerun-checks]",
|
|
956
|
+
options: ["--work-item", "--strategy", "--project", "--target", "--check", "--rerun-checks"],
|
|
957
957
|
optionValues: { "--strategy": ["ff", "cherry-pick", "merge", "manual"] }
|
|
958
958
|
},
|
|
959
959
|
{
|
|
@@ -982,21 +982,7 @@ const taskChildren = [
|
|
|
982
982
|
},
|
|
983
983
|
{ name: "list", summary: "List Integration Attempts.", usage: "yui task integration list <task>" },
|
|
984
984
|
{ name: "show", summary: "Show one Integration Attempt.", usage: "yui task integration show <task>/<integration>" },
|
|
985
|
-
{ name: "cleanup", summary: "Remove a terminal Integration worktree and branch.", usage: "yui task integration cleanup <task>/<integration>" }
|
|
986
|
-
{
|
|
987
|
-
name: "queue",
|
|
988
|
-
summary: "Manage the serialized integration queue.",
|
|
989
|
-
sections: [{ id: "queue", title: "Commands", entries: ["enqueue", "list", "show", "process", "supersede", "requeue", "reconcile"] }],
|
|
990
|
-
children: [
|
|
991
|
-
{ name: "enqueue", summary: "Enqueue a ChangeSet for serialized integration.", usage: "yui task integration queue enqueue <task> --project <project> --change-set <id> [--target <ref>] [--check <command> ...]", options: ["--project", "--change-set", "--target", "--check"] },
|
|
992
|
-
{ name: "list", summary: "List integration queue entries.", usage: "yui task integration queue list <task> [--project <project>]", options: ["--project"] },
|
|
993
|
-
{ name: "show", summary: "Show one integration queue entry.", usage: "yui task integration queue show <task>/<entry>" },
|
|
994
|
-
{ name: "process", summary: "Process queued integration entries.", usage: "yui task integration queue process <task> [--project <project>] [--limit <n>]", options: ["--project", "--limit"] },
|
|
995
|
-
{ name: "supersede", summary: "Supersede a queued entry.", usage: "yui task integration queue supersede <task>/<entry> --reason <text>", options: ["--reason"] },
|
|
996
|
-
{ name: "requeue", summary: "Requeue a conflicted entry.", usage: "yui task integration queue requeue <task>/<entry>" },
|
|
997
|
-
{ name: "reconcile", summary: "Reconcile a blocked entry.", usage: "yui task integration queue reconcile <task>/<entry>" }
|
|
998
|
-
]
|
|
999
|
-
}
|
|
985
|
+
{ name: "cleanup", summary: "Remove a terminal Integration worktree and branch.", usage: "yui task integration cleanup <task>/<integration>" }
|
|
1000
986
|
]
|
|
1001
987
|
},
|
|
1002
988
|
{
|
|
@@ -1085,10 +1071,12 @@ const taskChildren = [
|
|
|
1085
1071
|
{
|
|
1086
1072
|
name: "wake",
|
|
1087
1073
|
summary: "Inspect the durable Leader wake ledger and its delta content.",
|
|
1088
|
-
sections: [{ id: "manage", title: "Commands", entries: ["list", "show", "resolve"] }],
|
|
1074
|
+
sections: [{ id: "manage", title: "Commands", entries: ["list", "show", "retry", "resolve"] }],
|
|
1089
1075
|
children: [
|
|
1090
1076
|
{ name: "list", summary: "List recorded Leader wakes.", usage: "yui task wake list <task>" },
|
|
1091
1077
|
{ name: "show", summary: "Show one wake and its delta content.", usage: "yui task wake show <task> <wake>" },
|
|
1078
|
+
{ name: "retry", summary: "Retry a rejected notification after correcting its cause; preserve original input.",
|
|
1079
|
+
usage: "yui task wake retry <task> <wake> --reason <correction>", options: ["--reason"] },
|
|
1092
1080
|
{ name: "resolve", summary: "Release an unknown notification claim after explicit quiescence evidence, without replay.",
|
|
1093
1081
|
usage: "yui task wake resolve <task> <wake> --reason <quiescence-evidence>", options: ["--reason"] }
|
|
1094
1082
|
]
|
|
@@ -1117,13 +1105,41 @@ export const ROOT_COMMAND = buildNode({
|
|
|
1117
1105
|
{ id: "general", title: "General", entries: [
|
|
1118
1106
|
"help", "version", "update", "upgrade", "setup", "doctor"
|
|
1119
1107
|
] },
|
|
1120
|
-
{ id: "workflow", title: "Workflow", entries: ["operator", "project", "task"] },
|
|
1108
|
+
{ id: "workflow", title: "Workflow", entries: ["operator", "role", "project", "task"] },
|
|
1121
1109
|
{ id: "configuration", title: "Configuration", entries: ["config"] },
|
|
1122
1110
|
{ id: "operations", title: "Operations", entries: ["web", "controller", "session", "execution", "capability", "job", "jobs", "telemetry", "release"] },
|
|
1123
1111
|
{ id: "resources", title: "Resources", entries: ["resources"] },
|
|
1124
1112
|
{ id: "internal", title: "Internal", entries: ["internal"] }
|
|
1125
1113
|
],
|
|
1126
1114
|
children: [
|
|
1115
|
+
{
|
|
1116
|
+
name: "role",
|
|
1117
|
+
summary: "Queue input or control an exact current Global Role Turn.",
|
|
1118
|
+
sections: [{ id: "input", title: "Input control", entries: ["message", "interrupt"] }],
|
|
1119
|
+
children: [
|
|
1120
|
+
{
|
|
1121
|
+
name: "message", summary: "Send durable input to a Global Role.",
|
|
1122
|
+
sections: [{ id: "input", title: "Input control", entries: ["queue", "steer"] }],
|
|
1123
|
+
children: [
|
|
1124
|
+
{
|
|
1125
|
+
name: "queue", summary: "Queue input for the next legal delivery opportunity.",
|
|
1126
|
+
usage: "yui role message queue <role> (<text>|--body-file <path|->) --request-id <id>",
|
|
1127
|
+
options: ["--request-id", "--body-file"], fileOptions: ["--body-file"]
|
|
1128
|
+
},
|
|
1129
|
+
{
|
|
1130
|
+
name: "steer", summary: "Steer the exact current native Turn.",
|
|
1131
|
+
usage: "yui role message steer <role> (<text>|--body-file <path|->) --request-id <id> --expected-target <turn>",
|
|
1132
|
+
options: ["--request-id", "--expected-target", "--body-file"], fileOptions: ["--body-file"]
|
|
1133
|
+
}
|
|
1134
|
+
]
|
|
1135
|
+
},
|
|
1136
|
+
{
|
|
1137
|
+
name: "interrupt", summary: "Request cancellation of the exact current native Turn.",
|
|
1138
|
+
usage: "yui role interrupt <role> --expected-target <turn> [--request-id <id>] [--then-message <message>]",
|
|
1139
|
+
options: ["--request-id", "--expected-target", "--then-message"]
|
|
1140
|
+
}
|
|
1141
|
+
]
|
|
1142
|
+
},
|
|
1127
1143
|
{ name: "help", summary: "Show root or scoped command help.", usage: "yui help [command ...]", commandPathArguments: true },
|
|
1128
1144
|
{ name: "version", summary: "Print the installed Yui version." },
|
|
1129
1145
|
{ name: "update", summary: "Install the latest published Yui package globally." },
|
|
@@ -1540,7 +1556,7 @@ export const ROOT_COMMAND = buildNode({
|
|
|
1540
1556
|
summary: "Start, inspect, cancel, or acknowledge a Controller-managed DurableJob.",
|
|
1541
1557
|
sections: [{ id: "manage", title: "Commands", entries: ["start", "get", "cancel", "acknowledge"] }],
|
|
1542
1558
|
children: [
|
|
1543
|
-
{ name: "start", summary: "Start a DurableJob
|
|
1559
|
+
{ name: "start", summary: "Start a DurableJob under an explicit request identity.", usage: "yui job start --request-id <id> --task <id> --project <project> --head <sha> --workspace <dir> --step <name>=<command> [--step ...] [--owner task|work-item:<id>|integration-attempt:<id>] [--env <k=v>...]" },
|
|
1544
1560
|
{ name: "get", summary: "Show a DurableJob record and its terminal result.", usage: "yui job get --task <id> --job <job-id>" },
|
|
1545
1561
|
{ name: "cancel", summary: "Request cancellation of a running or queued DurableJob.", usage: "yui job cancel --task <id> --job <job-id>" },
|
|
1546
1562
|
{ name: "acknowledge", summary: "Acknowledge an unknown-needs-attention DurableJob so Task lifecycle gates can proceed.", usage: "yui job acknowledge --task <id> --job <job-id>" }
|
package/dist/cli/completion.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { ROOT_COMMAND, listPublicCommandPaths, orderedImmediateTokens, visibleChildren } from "./commandCatalog.js";
|
|
2
2
|
import { findInteractionPolicy } from "./interactionPolicy.js";
|
|
3
|
-
export function renderCompletion(shell
|
|
3
|
+
export function renderCompletion(shell) {
|
|
4
4
|
const entries = collectEntries(ROOT_COMMAND);
|
|
5
5
|
switch (shell) {
|
|
6
|
-
case "bash": return renderBash(entries
|
|
7
|
-
case "zsh": return renderZsh(entries
|
|
8
|
-
case "fish": return renderFish(entries
|
|
6
|
+
case "bash": return renderBash(entries);
|
|
7
|
+
case "zsh": return renderZsh(entries);
|
|
8
|
+
case "fish": return renderFish(entries);
|
|
9
9
|
default: throw new Error("Completion shell must be one of bash, zsh, fish.");
|
|
10
10
|
}
|
|
11
11
|
}
|
|
@@ -30,8 +30,8 @@ function collectEntries(root) {
|
|
|
30
30
|
function manifest(prefix) {
|
|
31
31
|
return listPublicCommandPaths().map((path) => `${prefix} ${path}`).join("\n");
|
|
32
32
|
}
|
|
33
|
-
function renderBash(entries
|
|
34
|
-
const functionName =
|
|
33
|
+
function renderBash(entries) {
|
|
34
|
+
const functionName = "_yui";
|
|
35
35
|
return `${manifest("# yui command:")}
|
|
36
36
|
${functionName}() {
|
|
37
37
|
local current path previous dynamic_candidate dynamic=false
|
|
@@ -55,7 +55,7 @@ ${bashDynamicOptionCases(entries)}
|
|
|
55
55
|
if [[ "$dynamic" == true ]]; then
|
|
56
56
|
while IFS= read -r dynamic_candidate; do
|
|
57
57
|
[[ -n "$dynamic_candidate" ]] && dynamic_candidates+=("$dynamic_candidate")
|
|
58
|
-
done < <(command
|
|
58
|
+
done < <(command yui config completion candidates "$current" -- "\${COMP_WORDS[@]:1:COMP_CWORD-1}" 2>/dev/null)
|
|
59
59
|
candidates=("\${dynamic_candidates[@]}")
|
|
60
60
|
elif [[ "$current" == -* ]]; then
|
|
61
61
|
case "$path" in
|
|
@@ -70,11 +70,11 @@ ${entries.map((entry) => ` ${bashPattern(entry.path)}) candidates=(${[...en
|
|
|
70
70
|
fi
|
|
71
71
|
COMPREPLY=( $(compgen -W "\${candidates[*]}" -- "$current") )
|
|
72
72
|
}
|
|
73
|
-
complete -F ${functionName}
|
|
73
|
+
complete -F ${functionName} yui
|
|
74
74
|
`;
|
|
75
75
|
}
|
|
76
|
-
function renderZsh(entries
|
|
77
|
-
return `#compdef
|
|
76
|
+
function renderZsh(entries) {
|
|
77
|
+
return `#compdef yui
|
|
78
78
|
${manifest("# yui command:")}
|
|
79
79
|
local current command_path previous dynamic_output dynamic=false
|
|
80
80
|
local -a candidates
|
|
@@ -95,7 +95,7 @@ ${zshDynamicOptionCases(entries)}
|
|
|
95
95
|
esac
|
|
96
96
|
fi
|
|
97
97
|
if [[ "$dynamic" == true ]]; then
|
|
98
|
-
dynamic_output="$(command
|
|
98
|
+
dynamic_output="$(command yui config completion candidates "$current" -- "\${(@)words[2,CURRENT-1]}" 2>/dev/null)"
|
|
99
99
|
candidates=("\${(@f)dynamic_output}")
|
|
100
100
|
elif [[ "$current" == -* ]]; then
|
|
101
101
|
case "$command_path" in
|
|
@@ -111,8 +111,8 @@ fi
|
|
|
111
111
|
(( \${#candidates[@]} > 0 )) && compadd -- "$candidates[@]"
|
|
112
112
|
`;
|
|
113
113
|
}
|
|
114
|
-
function renderFish(entries
|
|
115
|
-
const prefix =
|
|
114
|
+
function renderFish(entries) {
|
|
115
|
+
const prefix = "__yui";
|
|
116
116
|
const lines = [
|
|
117
117
|
manifest("# yui command:"),
|
|
118
118
|
`function ${prefix}_at_path`,
|
|
@@ -151,17 +151,17 @@ function renderFish(entries, identity) {
|
|
|
151
151
|
"end",
|
|
152
152
|
`function ${prefix}_dynamic`,
|
|
153
153
|
" set -l words (commandline -opc)",
|
|
154
|
-
|
|
154
|
+
" yui config completion candidates (commandline -ct) -- $words[2..-1] 2>/dev/null",
|
|
155
155
|
"end"
|
|
156
156
|
];
|
|
157
157
|
for (const entry of entries) {
|
|
158
158
|
for (const argument of entry.dynamicArguments) {
|
|
159
159
|
const condition = `${prefix}_needs_dynamic argument ${argument} ${fishPath(entry.path)}`;
|
|
160
|
-
lines.push(`complete -c
|
|
160
|
+
lines.push(`complete -c yui -f -n ${fishQuote(condition)} -a '(${prefix}_dynamic)'`);
|
|
161
161
|
}
|
|
162
162
|
for (const option of entry.dynamicOptions) {
|
|
163
163
|
const condition = `${prefix}_needs_dynamic option ${option} ${fishPath(entry.path)}`;
|
|
164
|
-
lines.push(`complete -c
|
|
164
|
+
lines.push(`complete -c yui -f -n ${fishQuote(condition)} -a '(${prefix}_dynamic)'`);
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
167
|
for (const entry of entries) {
|
|
@@ -169,13 +169,13 @@ function renderFish(entries, identity) {
|
|
|
169
169
|
const condition = entry.path.length === 0
|
|
170
170
|
? "__fish_use_subcommand"
|
|
171
171
|
: `${prefix}_at_path ${fishPath(entry.path)}${fishInitialDynamicExclusion(entry, prefix)}`;
|
|
172
|
-
lines.push(`complete -c
|
|
172
|
+
lines.push(`complete -c yui -f -n ${fishQuote(condition)} -a '${escapeSingle(entry.immediate.join(" "))}'`);
|
|
173
173
|
}
|
|
174
174
|
if (entry.options.length > 0) {
|
|
175
175
|
const path = fishPath(entry.path);
|
|
176
176
|
const exact = `${prefix}_at_path ${path}${fishInitialDynamicExclusion(entry, prefix)}`;
|
|
177
177
|
const condition = `begin; ${exact}; end; or ${prefix}_at_command_options ${path}`;
|
|
178
|
-
lines.push(`complete -c
|
|
178
|
+
lines.push(`complete -c yui -f -n ${fishQuote(condition)} -a '${escapeSingle(entry.options.join(" "))}'`);
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
return `${lines.join("\n")}\n`;
|
|
@@ -41,7 +41,7 @@ export async function runCompletionWizard(port, io, options = {}) {
|
|
|
41
41
|
let activate = false;
|
|
42
42
|
let activationReady = automatic;
|
|
43
43
|
if (!automatic) {
|
|
44
|
-
const activationAnswer = normalize(await io.question(`${activationBlock(state.shell, installation
|
|
44
|
+
const activationAnswer = normalize(await io.question(`${activationBlock(state.shell, installation)}\n`
|
|
45
45
|
+ `Update ${installation.activationPath} with this managed Yui block? [Y/n]: `));
|
|
46
46
|
if (activationAnswer !== ""
|
|
47
47
|
&& activationAnswer !== "y"
|
|
@@ -2,7 +2,7 @@ import { findChild, ROOT_COMMAND, visibleChildren } from "./commandCatalog.js";
|
|
|
2
2
|
import { getSelectionCandidates } from "./interactionCandidates.js";
|
|
3
3
|
import { findInteractionPolicy } from "./interactionPolicy.js";
|
|
4
4
|
export async function resolveCompletionCandidates(input) {
|
|
5
|
-
const words = input.words[0] === "yui"
|
|
5
|
+
const words = input.words[0] === "yui"
|
|
6
6
|
? input.words.slice(1)
|
|
7
7
|
: [...input.words];
|
|
8
8
|
const { node, consumed } = resolveCommand(words);
|
|
@@ -223,7 +223,10 @@ export const INTERACTION_POLICIES = Object.freeze([
|
|
|
223
223
|
{
|
|
224
224
|
commandPath: ["task", "list"],
|
|
225
225
|
selectors: [],
|
|
226
|
-
trailingOptions: {
|
|
226
|
+
trailingOptions: {
|
|
227
|
+
"--all": "flag", "--status": "value", "--project": "value",
|
|
228
|
+
"--search": "value", "--attention": "value", "--limit": "value", "--cursor": "value"
|
|
229
|
+
}
|
|
227
230
|
},
|
|
228
231
|
{
|
|
229
232
|
...taskTarget("remote-delivery"),
|
|
@@ -276,7 +279,7 @@ export const INTERACTION_POLICIES = Object.freeze([
|
|
|
276
279
|
provider: "messages",
|
|
277
280
|
actionTarget: true
|
|
278
281
|
}],
|
|
279
|
-
trailingOptions: { "--body-file": "value"
|
|
282
|
+
trailingOptions: { "--body-file": "value" }
|
|
280
283
|
},
|
|
281
284
|
{
|
|
282
285
|
commandPath: ["task", "message", "retire"],
|
|
@@ -554,7 +557,8 @@ export const INTERACTION_POLICIES = Object.freeze([
|
|
|
554
557
|
"--strategy": "value",
|
|
555
558
|
"--project": "value",
|
|
556
559
|
"--target": "value",
|
|
557
|
-
"--check": "value"
|
|
560
|
+
"--check": "value",
|
|
561
|
+
"--rerun-checks": "flag"
|
|
558
562
|
}
|
|
559
563
|
},
|
|
560
564
|
{
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { usageError } from "../errors/cliError.js";
|
|
2
|
+
import { requireManagedGlobalCaller } from "../runtime/managedCaller.js";
|
|
3
|
+
import { routeInvocation } from "./invocationRouter.js";
|
|
4
|
+
import { findInteractionPolicy } from "./interactionPolicy.js";
|
|
5
|
+
import { TASK_RECORD_ID_PREFIXES } from "../task/taskRecordReference.js";
|
|
6
|
+
import { taskDiagnosticTarget } from "./managedDiagnostics.js";
|
|
7
|
+
/** Configuration reads remain available; every Home configuration mutation
|
|
8
|
+
* has one owner, irrespective of which config subcommand parses its flags. */
|
|
9
|
+
export function assertConfigurationAuthority(args, store, env) {
|
|
10
|
+
const configurationWrite = args[0] === "config"
|
|
11
|
+
&& !["show", "describe"].includes(args[1] ?? "")
|
|
12
|
+
&& !["show", "list", "capabilities", "status", "candidates"].includes(args[2] ?? "");
|
|
13
|
+
const resourceWrite = args[0] === "resources" && args.some(arg => ["--apply", "--purge", "--restore"].includes(arg));
|
|
14
|
+
if (!configurationWrite && !resourceWrite)
|
|
15
|
+
return;
|
|
16
|
+
if (env.YUI_SESSION_SCOPE === "global" && env.YUI_ROLE === "operator") {
|
|
17
|
+
requireManagedGlobalCaller(store, env);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (env.YUI_SESSION_SCOPE !== undefined || env.YUI_ROLE !== undefined
|
|
21
|
+
|| env.YUI_AGENT_ID !== undefined || env.YUI_NATIVE_SESSION_ID !== undefined) {
|
|
22
|
+
throw usageError("Home configuration and resource mutations require the user or current Operator, not a Task Assignment.");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/** The parsed command path identifies the first target argument, never a
|
|
26
|
+
* string found in a body/flag value. Record-local references retain their
|
|
27
|
+
* normal command-specific parser; an explicit foreign Task cannot pass it. */
|
|
28
|
+
export function assertTaskInvocationScope(args, env) {
|
|
29
|
+
if (env.YUI_SESSION_SCOPE !== "task")
|
|
30
|
+
return;
|
|
31
|
+
if (args[0] === "jobs" || (args[0] === "task" && ["create", "overlap"].includes(args[1] ?? ""))) {
|
|
32
|
+
throw usageError("This global operation is outside the caller's Task; use its scoped Context.");
|
|
33
|
+
}
|
|
34
|
+
if (args[0] !== "task" || args[1] === "list")
|
|
35
|
+
return;
|
|
36
|
+
const diagnostic = taskDiagnosticTarget(args);
|
|
37
|
+
if (diagnostic !== undefined) {
|
|
38
|
+
if (diagnostic !== env.YUI_TASK_ID)
|
|
39
|
+
throw usageError("Command target is outside the caller's Task.");
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const invocation = routeInvocation([...args]);
|
|
43
|
+
if (invocation.kind !== "execute")
|
|
44
|
+
return;
|
|
45
|
+
let targetIndex = invocation.node.path.length - 1;
|
|
46
|
+
const optionSyntax = findInteractionPolicy(invocation.node)?.trailingOptions;
|
|
47
|
+
while (args[targetIndex]?.startsWith("--")) {
|
|
48
|
+
// Reuse known option arity, not any picker/confirmation authority. An
|
|
49
|
+
// unclassified prefix cannot turn a missing target into permission.
|
|
50
|
+
const kind = optionSyntax?.[args[targetIndex]];
|
|
51
|
+
if (kind === undefined)
|
|
52
|
+
throw usageError("Place this command's Task target before its options so its scope is explicit.");
|
|
53
|
+
targetIndex += kind === "flag" ? 1 : 2;
|
|
54
|
+
}
|
|
55
|
+
const target = args[targetIndex];
|
|
56
|
+
if (target === undefined)
|
|
57
|
+
return; // The domain parser still requires its target.
|
|
58
|
+
const taskId = target.split("/")[0];
|
|
59
|
+
const local = !target.includes("/") && Object.values(TASK_RECORD_ID_PREFIXES)
|
|
60
|
+
.some(prefix => target.startsWith(`${prefix}-`));
|
|
61
|
+
if (!local && taskId !== env.YUI_TASK_ID) {
|
|
62
|
+
throw usageError("Command target is outside the caller's Task.");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -4,7 +4,7 @@ export function taskDiagnosticTarget(args) {
|
|
|
4
4
|
if (args[0] !== "task")
|
|
5
5
|
return undefined;
|
|
6
6
|
if (["show", "context", "next-action", "archive-preflight"].includes(args[1] ?? "")) {
|
|
7
|
-
return args[1] === "context" && ["inspect", "delta"].includes(args[2] ?? "")
|
|
7
|
+
return args[1] === "context" && ["read", "inspect", "delta"].includes(args[2] ?? "")
|
|
8
8
|
? args[3] : args[2];
|
|
9
9
|
}
|
|
10
10
|
if (args[1] === "role" && ["list", "status", "show"].includes(args[2] ?? ""))
|