@zq-silk/yui 0.2.0 → 0.4.2
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 +603 -133
- package/README.md +806 -31
- package/dist/agent/agent.js +2 -1
- package/dist/agent/argumentPolicy.js +3 -1
- package/dist/agent/launchEnvironment.js +106 -0
- package/dist/agent/managedRuntimeEnvironment.js +34 -0
- package/dist/brief/taskBrief.js +11 -1
- package/dist/cli/agentConfigurationPicker.js +287 -0
- package/dist/cli/commandCatalog.js +488 -60
- package/dist/cli/completion.js +146 -22
- package/dist/cli/helpRenderer.js +3 -1
- package/dist/cli/interactionCandidates.js +53 -15
- package/dist/cli/interactionPolicy.js +267 -30
- package/dist/cli/interactiveSelection.js +6 -2
- package/dist/cli/invocationRouter.js +5 -1
- package/dist/cli/operatorWizard.js +87 -0
- package/dist/cli/roleOptionCatalog.js +1 -0
- package/dist/cli/roleWizard.js +185 -21
- package/dist/cli/updateCommand.js +62 -19
- package/dist/cli/updateOrchestrator.js +539 -0
- package/dist/cli/updatePorts.js +1119 -0
- package/dist/cli/upgradeCommand.js +112 -0
- package/dist/cli.js +1420 -86
- package/dist/commands/agentCommands.js +146 -3
- package/dist/commands/configCommands.js +126 -0
- package/dist/commands/controllerCommands.js +365 -0
- package/dist/commands/globalRoleCommands.js +168 -126
- package/dist/commands/jobCommands.js +18 -8
- package/dist/commands/operatorCommands.js +159 -9
- package/dist/commands/profileCommands.js +203 -0
- package/dist/commands/projectCommands.js +650 -0
- package/dist/commands/roleConfiguration.js +85 -24
- package/dist/commands/roleRuntimeGuard.js +12 -0
- package/dist/commands/roleSkillValidation.js +47 -0
- package/dist/commands/taskActor.js +127 -0
- package/dist/commands/taskCommands.js +4201 -313
- package/dist/commands/taskCompletionGate.js +131 -0
- package/dist/commands/taskContextCommand.js +244 -30
- package/dist/commands/taskInputCommands.js +177 -59
- package/dist/commands/taskIntegrationCommands.js +303 -0
- package/dist/commands/taskOverviewCommand.js +363 -0
- package/dist/commands/taskRoleRuntimeStatus.js +125 -19
- package/dist/commands/textInput.js +15 -0
- package/dist/completion/completionInstaller.js +26 -22
- package/dist/config/yuiConfig.js +4 -3
- package/dist/context/dispatchContext.js +90 -38
- package/dist/context/roleSessionContext.js +119 -0
- package/dist/controller/claudeLifecycleHook.js +203 -0
- package/dist/controller/clientRuntime.js +408 -56
- package/dist/controller/codexLifecycleHook.js +108 -0
- package/dist/controller/controller.js +1089 -32
- package/dist/controller/domainIdentity.js +505 -0
- package/dist/controller/ephemeralResourceReaper.js +131 -0
- package/dist/controller/fileSchedulerStoreAdapter.js +2153 -103
- package/dist/controller/providerHookRunFence.js +127 -0
- package/dist/controller/resourceCleanupLinux.js +286 -0
- package/dist/controller/resourceInventory.js +531 -0
- package/dist/controller/resourceInventoryLinux.js +610 -0
- package/dist/controller/runtime.js +629 -10
- package/dist/controller/runtimeEventInbox.js +564 -0
- package/dist/controller/runtimeEventProcessor.js +248 -0
- package/dist/controller/runtimeLaunchCoordinator.js +477 -0
- package/dist/controller/sessionNotify.js +121 -78
- package/dist/coordination/deadlineScheduler.js +15 -0
- package/dist/coordination/mailboxScheduler.js +108 -0
- package/dist/coordination/workMailbox.js +329 -0
- package/dist/coordination/workMailboxQueue.js +86 -0
- package/dist/core/controllerClient.js +19 -5
- package/dist/core/controllerEndpoint.js +37 -0
- package/dist/core/controllerServer.js +218 -10
- package/dist/core/protocol.js +6 -2
- package/dist/decision/decision.js +2 -1
- package/dist/doctor/doctor.js +681 -32
- package/dist/domain/validation.js +53 -0
- package/dist/errors/cliError.js +5 -3
- package/dist/event/taskEvent.js +7 -3
- package/dist/execution/codexThreadNaming.js +160 -0
- package/dist/execution/executionGroup.js +579 -0
- package/dist/executor/agentAdapter.js +255 -40
- package/dist/executor/agentConfigurationCatalog.js +326 -0
- package/dist/executor/agentConfigurationProbe.js +506 -0
- package/dist/executor/agentExecutor.js +625 -10
- package/dist/executor/codexConfigConflict.js +290 -0
- package/dist/executor/effectiveLaunch.js +340 -0
- package/dist/executor/executorRegistry.js +238 -36
- package/dist/executor/fileRoleLaunchPlanner.js +550 -40
- package/dist/executor/turnCompletion.js +126 -0
- package/dist/input/inputRequest.js +30 -9
- package/dist/integration/changeSet.js +36 -0
- package/dist/integration/checkResult.js +24 -0
- package/dist/integration/gitIntegrationService.js +695 -0
- package/dist/integration/integrationAttempt.js +142 -0
- package/dist/interaction/operatorPresentation.js +96 -0
- package/dist/lifecycle/canonicalLifecycleEvent.js +342 -0
- package/dist/lifecycle/exactRunTerminalization.js +572 -0
- package/dist/lifecycle/providerLifecycleMapping.js +190 -0
- package/dist/lifecycle/taskRoleSessionReset.js +124 -0
- package/dist/message/message.js +23 -7
- package/dist/milestone/milestone.js +2 -1
- package/dist/operator/operatorSessionHistory.js +124 -0
- package/dist/output/agentConfigurationPresentation.js +43 -0
- package/dist/output/rolePresentation.js +34 -10
- package/dist/output/terminal.js +8 -0
- package/dist/output/timePresentation.js +55 -0
- package/dist/profile/agentProfile.js +128 -0
- package/dist/repository/gitWorkspace.js +578 -24
- package/dist/repository/project.js +213 -0
- package/dist/repository/taskWorkspaceCoordinator.js +392 -0
- package/dist/repository/taskWorkspacePreparer.js +1688 -191
- package/dist/review/reviewConfig.js +11 -0
- package/dist/review/reviewRound.js +399 -0
- package/dist/review/taskFinalReviewContract.js +90 -0
- package/dist/role/role.js +124 -23
- package/dist/run/agentRun.js +155 -12
- package/dist/run/runIdentity.js +82 -0
- package/dist/runtime/exactControlPlane.js +472 -0
- package/dist/runtime/index.js +8 -0
- package/dist/runtime/lifecycleReservation.js +38 -0
- package/dist/runtime/ports.js +11 -0
- package/dist/runtime/preallocatedNativeSession.js +13 -0
- package/dist/runtime/promptEnvelope.js +30 -0
- package/dist/runtime/runtimeBinding.js +31 -0
- package/dist/runtime/runtimeOwner.js +14 -0
- package/dist/runtime/sessionLaunchRequest.js +62 -0
- package/dist/runtime/sessionTitle.js +54 -0
- package/dist/runtime/taskRuntimeIsolation.js +643 -0
- package/dist/runtime/tmuxAdapters.js +315 -0
- package/dist/runtime/turnCompletion.js +3 -0
- package/dist/runtime/validation.js +23 -0
- package/dist/scheduler/activeRoleRunDelivery.js +342 -32
- package/dist/scheduler/activeTaskProgress.js +63 -0
- package/dist/scheduler/leaderFailure.js +2 -1
- package/dist/scheduler/leaderWakeupProcessor.js +307 -66
- package/dist/scheduler/operatorInputNotificationProcessor.js +109 -46
- package/dist/scheduler/operatorNotification.js +44 -2
- package/dist/scheduler/ports.js +28 -1
- package/dist/scheduler/roleRunLiveness.js +131 -25
- package/dist/scheduler/roleRunStall.js +951 -0
- package/dist/scheduler/taskExecutionProjection.js +544 -0
- package/dist/scheduler/wakeupQueue.js +3 -0
- package/dist/setup/setupCommand.js +302 -52
- package/dist/storage/compatibleTaskStore.js +102 -0
- package/dist/storage/migration/baseline.js +78 -0
- package/dist/storage/migration/classifier.js +51 -0
- package/dist/storage/migration/compatibleCodec.js +53 -0
- package/dist/storage/migration/engine.js +147 -0
- package/dist/storage/migration/index.js +33 -0
- package/dist/storage/migration/planner.js +154 -0
- package/dist/storage/migration/productionRegistry.js +486 -0
- package/dist/storage/migration/registry.js +169 -0
- package/dist/storage/migration/report.js +54 -0
- package/dist/storage/migration/types.js +31 -0
- package/dist/storage/storageSchema.js +147 -123
- package/dist/storage/storageVersions.js +11 -0
- package/dist/storage/taskStore.js +1793 -197
- package/dist/storage/upgrade/homeClassification.js +156 -0
- package/dist/storage/upgrade/homeMigrationTarget.js +595 -0
- package/dist/storage/upgrade/offlineUpgradeInventory.js +315 -0
- package/dist/storage/upgrade/productionMigrationRegistry.js +6 -0
- package/dist/storage/upgrade/recordVersionScan.js +176 -0
- package/dist/storage/upgrade/recordVersions.js +159 -0
- package/dist/storage/upgrade/switchProgress.js +80 -0
- package/dist/storage/upgrade/upgradeOrchestrator.js +948 -0
- package/dist/storage/upgrade/upgradeReceipt.js +161 -0
- package/dist/storage/upgradeCoordination.js +186 -0
- package/dist/storage/upgradeFence.js +366 -0
- package/dist/task/task.js +132 -26
- package/dist/task/taskRecordReference.js +66 -0
- package/dist/tmux/commandExecutor.js +75 -2
- package/dist/tmux/tmuxManager.js +747 -49
- package/dist/version.js +23 -0
- package/dist/web/assets/assetManifest.js +62 -0
- package/dist/web/assets/client/app.js +631 -0
- package/dist/web/assets/client/components.js +605 -0
- package/dist/web/assets/client/dom.js +14 -0
- package/dist/web/assets/client/format.js +28 -0
- package/dist/web/assets/client/i18n.js +494 -0
- package/dist/web/assets/client/markdown.js +114 -0
- package/dist/web/assets/client/theme.js +32 -0
- package/dist/web/assets/client/view.js +458 -0
- package/dist/web/assets/fontData.js +12 -0
- package/dist/web/assets/fonts.js +12 -0
- package/dist/web/assets/shell.js +114 -0
- package/dist/web/assets/styles/cards.js +135 -0
- package/dist/web/assets/styles/layout.js +47 -0
- package/dist/web/assets/styles/markdown.js +29 -0
- package/dist/web/assets/styles/responsive.js +39 -0
- package/dist/web/assets/styles/tokens.js +101 -0
- package/dist/web/assets/styles/widgets.js +147 -0
- package/dist/web/tmuxWebTerminal.js +158 -0
- package/dist/web/webServer.js +463 -0
- package/dist/web/webSnapshot.js +148 -0
- package/dist/workItem/workItem.js +642 -23
- package/dist/workspace/gitChangeSetCapture.js +86 -0
- package/dist/workspace/workItemChangeSetManager.js +445 -0
- package/dist/worktree/managedWorkspace.js +202 -0
- package/docs/task-local-identity.md +62 -0
- package/i18n/README.zh-CN.md +406 -31
- package/package.json +10 -2
- package/skills/yui-leader/SKILL.md +601 -39
- package/skills/yui-operator/SKILL.md +255 -34
- package/skills/yui-reviewer/SKILL.md +57 -0
- package/skills/yui-worker/SKILL.md +214 -17
- package/dist/commands/repositoryCommands.js +0 -86
- package/dist/operator/operatorContext.js +0 -66
- package/dist/repository/repository.js +0 -55
- package/dist/scheduler/archivedTaskRuntime.js +0 -12
- package/dist/worktree/roleWorkspace.js +0 -62
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { requireSafeIdentity, requireText, requireTimestamp } from "../runtime/validation.js";
|
|
2
|
+
export const DEFAULT_RECENT_TURN_ID_LIMIT = 32;
|
|
3
|
+
const PENDING_TURN_COMPLETION_FIELDS = [
|
|
4
|
+
"schemaVersion",
|
|
5
|
+
"taskId",
|
|
6
|
+
"roleName",
|
|
7
|
+
"agentId",
|
|
8
|
+
"nativeSessionId",
|
|
9
|
+
"turnId",
|
|
10
|
+
"runId",
|
|
11
|
+
"summary",
|
|
12
|
+
"observedAt",
|
|
13
|
+
"dueAt"
|
|
14
|
+
];
|
|
15
|
+
export function createPendingTurnCompletion(input) {
|
|
16
|
+
const observedAt = requireTimestamp(input.observedAt, "Turn observedAt");
|
|
17
|
+
const dueAt = requireTimestamp(input.dueAt, "Turn dueAt");
|
|
18
|
+
requireOrderedTimestamps(observedAt, dueAt);
|
|
19
|
+
return {
|
|
20
|
+
schemaVersion: 1,
|
|
21
|
+
taskId: requireSafeIdentity(input.taskId, "Task id"),
|
|
22
|
+
roleName: requireSafeIdentity(input.roleName, "Role name"),
|
|
23
|
+
agentId: requireSafeIdentity(input.agentId, "Agent id"),
|
|
24
|
+
nativeSessionId: requireText(input.nativeSessionId, "Native session id"),
|
|
25
|
+
turnId: requireSafeIdentity(input.turnId, "Turn id"),
|
|
26
|
+
runId: requireSafeIdentity(input.runId, "Run id"),
|
|
27
|
+
summary: requireText(input.summary, "Turn summary"),
|
|
28
|
+
observedAt,
|
|
29
|
+
dueAt
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export function validatePendingTurnCompletion(value) {
|
|
33
|
+
const input = requireRecord(value, "PendingTurnCompletion");
|
|
34
|
+
requireExactFields(input, PENDING_TURN_COMPLETION_FIELDS, "PendingTurnCompletion");
|
|
35
|
+
if (input.schemaVersion !== 1) {
|
|
36
|
+
throw new Error("PendingTurnCompletion must use schemaVersion 1.");
|
|
37
|
+
}
|
|
38
|
+
const observedAt = requirePersistedTimestamp(input.observedAt, "PendingTurnCompletion observedAt");
|
|
39
|
+
const dueAt = requirePersistedTimestamp(input.dueAt, "PendingTurnCompletion dueAt");
|
|
40
|
+
requireOrderedTimestamps(observedAt, dueAt);
|
|
41
|
+
return {
|
|
42
|
+
schemaVersion: 1,
|
|
43
|
+
taskId: requireSafeIdentityValue(input.taskId, "Task id"),
|
|
44
|
+
roleName: requireSafeIdentityValue(input.roleName, "Role name"),
|
|
45
|
+
agentId: requireSafeIdentityValue(input.agentId, "Agent id"),
|
|
46
|
+
nativeSessionId: requireTextValue(input.nativeSessionId, "Native session id"),
|
|
47
|
+
turnId: requireSafeIdentityValue(input.turnId, "Turn id"),
|
|
48
|
+
runId: requireSafeIdentityValue(input.runId, "Run id"),
|
|
49
|
+
summary: requireTextValue(input.summary, "Turn summary"),
|
|
50
|
+
observedAt,
|
|
51
|
+
dueAt
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export function validateRecentTurnIds(value, limit = DEFAULT_RECENT_TURN_ID_LIMIT) {
|
|
55
|
+
const normalizedLimit = requireLimit(limit);
|
|
56
|
+
if (!Array.isArray(value))
|
|
57
|
+
throw new Error("Recent Turn ids must be an array.");
|
|
58
|
+
if (value.length > normalizedLimit) {
|
|
59
|
+
throw new Error(`Recent Turn ids must not contain more than ${normalizedLimit} entries.`);
|
|
60
|
+
}
|
|
61
|
+
const result = value.map((turnId) => requireSafeIdentityValue(turnId, "Recent Turn id"));
|
|
62
|
+
if (new Set(result).size !== result.length) {
|
|
63
|
+
throw new Error("Recent Turn ids must not contain duplicates.");
|
|
64
|
+
}
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
export function rememberRecentTurnId(recentTurnIds, turnId, limit = DEFAULT_RECENT_TURN_ID_LIMIT) {
|
|
68
|
+
const normalizedLimit = requireLimit(limit);
|
|
69
|
+
const existing = validateRecentTurnIds(recentTurnIds, normalizedLimit);
|
|
70
|
+
const normalizedTurnId = requireSafeIdentity(turnId, "Recent Turn id");
|
|
71
|
+
return [
|
|
72
|
+
...existing.filter((candidate) => candidate !== normalizedTurnId),
|
|
73
|
+
normalizedTurnId
|
|
74
|
+
].slice(-normalizedLimit);
|
|
75
|
+
}
|
|
76
|
+
export function hasRecentTurnId(recentTurnIds, turnId) {
|
|
77
|
+
const existing = validateRecentTurnIds(recentTurnIds);
|
|
78
|
+
return existing.includes(requireSafeIdentity(turnId, "Recent Turn id"));
|
|
79
|
+
}
|
|
80
|
+
function requireOrderedTimestamps(observedAt, dueAt) {
|
|
81
|
+
if (Date.parse(dueAt) < Date.parse(observedAt)) {
|
|
82
|
+
throw new Error("PendingTurnCompletion dueAt must not be earlier than observedAt.");
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function requirePersistedTimestamp(value, label) {
|
|
86
|
+
if (typeof value !== "string")
|
|
87
|
+
throw new Error(`${label} must be a valid timestamp.`);
|
|
88
|
+
const timestamp = Date.parse(value);
|
|
89
|
+
if (!Number.isFinite(timestamp))
|
|
90
|
+
throw new Error(`${label} must be a valid timestamp.`);
|
|
91
|
+
const canonical = new Date(timestamp).toISOString();
|
|
92
|
+
if (value !== canonical)
|
|
93
|
+
throw new Error(`${label} must be a canonical timestamp.`);
|
|
94
|
+
return canonical;
|
|
95
|
+
}
|
|
96
|
+
function requireRecord(value, label) {
|
|
97
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
98
|
+
throw new Error(`${label} must be an object.`);
|
|
99
|
+
}
|
|
100
|
+
return value;
|
|
101
|
+
}
|
|
102
|
+
function requireExactFields(value, fields, label) {
|
|
103
|
+
const expected = new Set(fields);
|
|
104
|
+
const unknown = Object.keys(value).find((field) => !expected.has(field));
|
|
105
|
+
if (unknown !== undefined)
|
|
106
|
+
throw new Error(`${label} has unknown field: ${unknown}.`);
|
|
107
|
+
const missing = fields.find((field) => !Object.hasOwn(value, field));
|
|
108
|
+
if (missing !== undefined)
|
|
109
|
+
throw new Error(`${label} is missing field: ${missing}.`);
|
|
110
|
+
}
|
|
111
|
+
function requireSafeIdentityValue(value, label) {
|
|
112
|
+
if (typeof value !== "string")
|
|
113
|
+
throw new Error(`${label} is invalid.`);
|
|
114
|
+
return requireSafeIdentity(value, label);
|
|
115
|
+
}
|
|
116
|
+
function requireTextValue(value, label) {
|
|
117
|
+
if (typeof value !== "string")
|
|
118
|
+
throw new Error(`${label} is invalid.`);
|
|
119
|
+
return requireText(value, label);
|
|
120
|
+
}
|
|
121
|
+
function requireLimit(value) {
|
|
122
|
+
if (!Number.isInteger(value) || value < 1) {
|
|
123
|
+
throw new Error("Recent Turn id limit must be a positive integer.");
|
|
124
|
+
}
|
|
125
|
+
return value;
|
|
126
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { validateTaskRecordReference } from "../task/taskRecordReference.js";
|
|
1
2
|
export class InputRequestStateError extends Error {
|
|
2
3
|
requestId;
|
|
3
4
|
status;
|
|
@@ -13,7 +14,7 @@ export function createInputRequest(id, taskId, requester, input, now) {
|
|
|
13
14
|
const timestamp = requireDate(now, "Input request creation time");
|
|
14
15
|
const choices = normalizeChoices(input.choices);
|
|
15
16
|
return validateInputRequest({
|
|
16
|
-
schemaVersion:
|
|
17
|
+
schemaVersion: 2,
|
|
17
18
|
id: requireIdentity(id, "Input request id"),
|
|
18
19
|
taskId: requireIdentity(taskId, "Input request Task id"),
|
|
19
20
|
requester: normalizeRequester(requester),
|
|
@@ -71,12 +72,12 @@ export function validateInputRequest(value) {
|
|
|
71
72
|
"schemaVersion", "id", "taskId", "requester", "question", "choices",
|
|
72
73
|
"blockedRefs", "policy", "status", "createdAt", "updatedAt", ...terminalField
|
|
73
74
|
], "Input request");
|
|
74
|
-
if (request.schemaVersion !==
|
|
75
|
-
throw new Error("Input request must use schemaVersion
|
|
75
|
+
if (request.schemaVersion !== 2)
|
|
76
|
+
throw new Error("Input request must use schemaVersion 2.");
|
|
76
77
|
const choices = validateChoices(request.choices);
|
|
77
78
|
const createdAt = requireTimestamp(request.createdAt, "Input request createdAt");
|
|
78
79
|
const base = {
|
|
79
|
-
schemaVersion:
|
|
80
|
+
schemaVersion: 2,
|
|
80
81
|
id: requireIdentity(request.id, "Input request id"),
|
|
81
82
|
taskId: requireIdentity(request.taskId, "Input request Task id"),
|
|
82
83
|
requester: normalizeRequester(request.requester),
|
|
@@ -87,6 +88,18 @@ export function validateInputRequest(value) {
|
|
|
87
88
|
createdAt,
|
|
88
89
|
updatedAt: requireTimestamp(request.updatedAt, "Input request updatedAt")
|
|
89
90
|
};
|
|
91
|
+
validateTaskRecordReference({ taskId: base.taskId, localId: base.id }, "inputRequest");
|
|
92
|
+
validateTaskRecordReference({
|
|
93
|
+
taskId: base.requester.taskId,
|
|
94
|
+
localId: base.requester.runId
|
|
95
|
+
}, "agentRun");
|
|
96
|
+
for (const reference of base.blockedRefs) {
|
|
97
|
+
validateTaskRecordReference({ taskId: reference.taskId, localId: reference.id }, reference.type === "run" ? "agentRun" : "workItem");
|
|
98
|
+
}
|
|
99
|
+
if (base.requester.taskId !== base.taskId
|
|
100
|
+
|| base.blockedRefs.some(({ taskId }) => taskId !== base.taskId)) {
|
|
101
|
+
throw new Error("Input request references must belong to its Task.");
|
|
102
|
+
}
|
|
90
103
|
if (Date.parse(base.updatedAt) < Date.parse(base.createdAt)) {
|
|
91
104
|
throw new Error("Input request updatedAt cannot precede createdAt.");
|
|
92
105
|
}
|
|
@@ -161,13 +174,17 @@ function normalizeBlockedRefs(value) {
|
|
|
161
174
|
throw new Error("Input blocked references must be an array.");
|
|
162
175
|
const references = value.map((reference) => {
|
|
163
176
|
const item = record(reference, "Input blocked reference");
|
|
164
|
-
exact(item, ["type", "id"], "Input blocked reference");
|
|
177
|
+
exact(item, ["type", "taskId", "id"], "Input blocked reference");
|
|
165
178
|
if (item.type !== "work-item" && item.type !== "run") {
|
|
166
179
|
throw new Error("Input blocked reference type must be work-item or run.");
|
|
167
180
|
}
|
|
168
|
-
return {
|
|
181
|
+
return {
|
|
182
|
+
type: item.type,
|
|
183
|
+
taskId: requireIdentity(item.taskId, "Input blocked reference Task id"),
|
|
184
|
+
id: requireIdentity(item.id, "Input blocked reference id")
|
|
185
|
+
};
|
|
169
186
|
});
|
|
170
|
-
const keys = references.map(({ type, id }) => `${type}:${id}`);
|
|
187
|
+
const keys = references.map(({ type, taskId, id }) => `${type}:${taskId}/${id}`);
|
|
171
188
|
if (new Set(keys).size !== keys.length)
|
|
172
189
|
throw new Error("Input blocked references must be unique.");
|
|
173
190
|
return references;
|
|
@@ -207,11 +224,12 @@ function validateBlockedRefs(value) {
|
|
|
207
224
|
function normalizeRequester(value) {
|
|
208
225
|
const requester = record(value, "Input requester");
|
|
209
226
|
exact(requester, requester.nativeSessionId === undefined
|
|
210
|
-
? ["roleName", "agentId", "runId"]
|
|
211
|
-
: ["roleName", "agentId", "runId", "nativeSessionId"], "Input requester");
|
|
227
|
+
? ["taskId", "roleName", "agentId", "runId"]
|
|
228
|
+
: ["taskId", "roleName", "agentId", "runId", "nativeSessionId"], "Input requester");
|
|
212
229
|
if (requester.roleName !== "leader")
|
|
213
230
|
throw new Error("Input requester must be the Task Leader.");
|
|
214
231
|
return {
|
|
232
|
+
taskId: requireIdentity(requester.taskId, "Input requester Task id"),
|
|
215
233
|
roleName: "leader",
|
|
216
234
|
agentId: requireIdentity(requester.agentId, "Input requester Agent id"),
|
|
217
235
|
runId: requireIdentity(requester.runId, "Input requester Run id"),
|
|
@@ -228,6 +246,9 @@ function normalizeAnswer(request, answer) {
|
|
|
228
246
|
exact(value, ["text"], "Input answer");
|
|
229
247
|
return { text: requireText(value.text, "Input answer") };
|
|
230
248
|
}
|
|
249
|
+
if (value.text !== undefined) {
|
|
250
|
+
throw new Error("Choice input request requires a choice answer.");
|
|
251
|
+
}
|
|
231
252
|
exact(value, ["choiceKey"], "Input answer");
|
|
232
253
|
const key = requireChoiceKey(value.choiceKey);
|
|
233
254
|
const choice = request.choices.find((candidate) => candidate.key === key);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { normalizedUniqueText, requireIdentity, requireText, requireTimestamp } from "../domain/validation.js";
|
|
2
|
+
import { validateTaskRecordReference } from "../task/taskRecordReference.js";
|
|
3
|
+
export function createWorkItemChangeSet(input, now) {
|
|
4
|
+
return validateChangeSet({
|
|
5
|
+
schemaVersion: 2,
|
|
6
|
+
...input,
|
|
7
|
+
changedPaths: [...input.changedPaths],
|
|
8
|
+
createdAt: now.toISOString()
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
export function validateChangeSet(changeSet) {
|
|
12
|
+
if (changeSet.schemaVersion !== 2)
|
|
13
|
+
throw new Error("ChangeSet must use schemaVersion 2.");
|
|
14
|
+
validateTaskRecordReference({ taskId: changeSet.taskId, localId: changeSet.id }, "changeSet");
|
|
15
|
+
validateTaskRecordReference({
|
|
16
|
+
taskId: changeSet.taskId,
|
|
17
|
+
localId: changeSet.workItemId
|
|
18
|
+
}, "workItem");
|
|
19
|
+
requireIdentity(changeSet.projectId, "Project id");
|
|
20
|
+
requireCommit(changeSet.baseCommit, "ChangeSet base commit");
|
|
21
|
+
requireCommit(changeSet.headCommit, "ChangeSet head commit");
|
|
22
|
+
if (changeSet.baseCommit === changeSet.headCommit) {
|
|
23
|
+
throw new Error("ChangeSet must contain at least one commit.");
|
|
24
|
+
}
|
|
25
|
+
requireText(changeSet.branch, "ChangeSet branch");
|
|
26
|
+
normalizedUniqueText(changeSet.changedPaths, "ChangeSet path");
|
|
27
|
+
requireTimestamp(changeSet.createdAt, "ChangeSet createdAt");
|
|
28
|
+
return changeSet;
|
|
29
|
+
}
|
|
30
|
+
function requireCommit(value, label) {
|
|
31
|
+
const normalized = requireText(value, label).toLowerCase();
|
|
32
|
+
if (!/^[a-f0-9]{40}(?:[a-f0-9]{24})?$/u.test(normalized)) {
|
|
33
|
+
throw new Error(`${label} is invalid.`);
|
|
34
|
+
}
|
|
35
|
+
return normalized;
|
|
36
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { requireText } from "../domain/validation.js";
|
|
2
|
+
export function normalizeCheckResult(check) {
|
|
3
|
+
if (!["passed", "failed", "skipped"].includes(check.outcome)) {
|
|
4
|
+
throw new Error(`Check outcome is invalid: ${String(check.outcome)}.`);
|
|
5
|
+
}
|
|
6
|
+
return {
|
|
7
|
+
name: requireText(check.name, "Check name"),
|
|
8
|
+
outcome: check.outcome,
|
|
9
|
+
...(check.details === undefined
|
|
10
|
+
? {}
|
|
11
|
+
: { details: requireText(check.details, "Check details") }),
|
|
12
|
+
...(check.logPath === undefined
|
|
13
|
+
? {}
|
|
14
|
+
: { logPath: requireRelativePath(check.logPath, "Check log path") })
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function requireRelativePath(value, label) {
|
|
18
|
+
const normalized = requireText(value, label);
|
|
19
|
+
if (/^(?:[A-Za-z]:[\\/]|[\\/])/u.test(normalized)
|
|
20
|
+
|| normalized.split(/[\\/]/u).includes("..")) {
|
|
21
|
+
throw new Error(`${label} must be relative.`);
|
|
22
|
+
}
|
|
23
|
+
return normalized.replaceAll("\\", "/");
|
|
24
|
+
}
|