@zq-silk/yui 0.6.0 → 0.6.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/README.md +5 -5
- package/dist/agent/managedRuntimeEnvironment.js +2 -1
- package/dist/cli/commandCatalog.js +251 -13
- package/dist/cli/updateOrchestrator.js +8 -0
- package/dist/cli/updatePorts.js +76 -22
- package/dist/cli.js +264 -20
- package/dist/commands/configCommands.js +83 -9
- package/dist/commands/controllerCommands.js +103 -0
- package/dist/commands/deliveryGuardPreflight.js +30 -0
- package/dist/commands/durableJobCommands.js +231 -0
- package/dist/commands/executionAuditCommands.js +193 -0
- package/dist/commands/grantCommands.js +374 -0
- package/dist/commands/projectCommands.js +119 -81
- package/dist/commands/releaseCommands.js +444 -0
- package/dist/commands/resourcesCommands.js +274 -0
- package/dist/commands/sessionCommands.js +104 -0
- package/dist/commands/taskActor.js +117 -0
- package/dist/commands/taskChangeSetCommands.js +60 -0
- package/dist/commands/taskCommands.js +618 -202
- package/dist/commands/taskCompletionGate.js +78 -1
- package/dist/commands/taskContextCommand.js +33 -6
- package/dist/commands/taskInputCommands.js +1 -1
- package/dist/commands/taskIntegrationCommands.js +136 -33
- package/dist/commands/taskIntegrationQueueCommands.js +228 -0
- package/dist/commands/taskNextActionCommand.js +100 -0
- package/dist/commands/taskOverlapCommands.js +120 -0
- package/dist/commands/taskOverviewCommand.js +36 -8
- package/dist/commands/telemetryCommands.js +330 -0
- package/dist/commands/workflowCommands.js +415 -0
- package/dist/config/yuiConfig.js +62 -0
- package/dist/controller/clientRuntime.js +42 -1
- package/dist/controller/controller.js +402 -56
- package/dist/controller/controllerMain.js +25 -2
- package/dist/controller/domainIdentity.js +16 -8
- package/dist/controller/fileSchedulerStoreAdapter.js +423 -31
- package/dist/controller/handoverCandidate.js +168 -0
- package/dist/controller/jobClient.js +102 -0
- package/dist/controller/jobControl.js +613 -0
- package/dist/controller/jobSupervisor.js +498 -0
- package/dist/controller/providerHookRunFence.js +34 -5
- package/dist/controller/resourceCleanupLinux.js +18 -9
- package/dist/controller/resourceInventoryLinux.js +90 -39
- package/dist/controller/runtime.js +165 -15
- package/dist/controller/runtimeEventInbox.js +234 -57
- package/dist/controller/runtimeEventProcessor.js +297 -58
- package/dist/controller/sessionOwnerReconciliation.js +321 -0
- package/dist/core/controllerServer.js +416 -27
- package/dist/core/controllerTelemetry.js +167 -0
- package/dist/doctor/doctor.js +113 -16
- package/dist/domain/validation.js +9 -0
- package/dist/execution/executionGroup.js +40 -3
- package/dist/executor/agentExecutor.js +6 -3
- package/dist/executor/effectiveLaunch.js +52 -0
- package/dist/executor/executorRegistry.js +50 -0
- package/dist/executor/fileRoleLaunchPlanner.js +61 -6
- package/dist/grant/capabilityGrant.js +282 -0
- package/dist/integration/changeSet.js +16 -3
- package/dist/integration/changeSetManifest.js +46 -0
- package/dist/integration/gitIntegrationService.js +528 -147
- package/dist/integration/integrationAttempt.js +54 -5
- package/dist/integration/integrationQueueEntry.js +221 -0
- package/dist/integration/integrationQueueService.js +955 -0
- package/dist/integration/manifestTags.js +99 -0
- package/dist/integration/overlapDiagnostics.js +211 -0
- package/dist/job/durableJob.js +449 -0
- package/dist/job/jobRunner.js +350 -0
- package/dist/lifecycle/exactRunTerminalization.js +24 -2
- package/dist/lifecycle/providerErrorClass.js +126 -0
- package/dist/message/message.js +16 -3
- package/dist/observability/executionAudit.js +545 -0
- package/dist/observability/faultClassification.js +160 -0
- package/dist/observability/runtimeIdentity.js +367 -0
- package/dist/release/fakeReleasePorts.js +55 -0
- package/dist/release/releaseHandover.js +475 -0
- package/dist/release/releaseIdempotencyStore.js +165 -0
- package/dist/release/releaseWorkflow.js +459 -0
- package/dist/release/releaseWorkflowEngine.js +688 -0
- package/dist/release/releaseWorkflowPorts.js +1720 -0
- package/dist/release/runtimeRelease.js +495 -0
- package/dist/release/workflowFileLock.js +218 -0
- package/dist/repository/gitWorkspace.js +177 -1
- package/dist/repository/projectMaintenanceLock.js +315 -0
- package/dist/repository/taskWorkspaceCoordinator.js +87 -17
- package/dist/repository/taskWorkspacePreparer.js +1091 -517
- package/dist/resources/autoResourceGc.js +116 -0
- package/dist/resources/liveReferences.js +574 -0
- package/dist/resources/resourceDiscovery.js +477 -0
- package/dist/resources/resourceGc.js +645 -0
- package/dist/resources/resourceRegistrar.js +256 -0
- package/dist/resources/resourceRegistry.js +150 -0
- package/dist/resources/resourceRegistryStore.js +41 -0
- package/dist/resources/resourceTypes.js +42 -0
- package/dist/resources/sqliteResourceRegistry.js +111 -0
- package/dist/review/reviewConfig.js +10 -0
- package/dist/review/reviewFinding.js +240 -0
- package/dist/review/reviewFindingLedger.js +545 -0
- package/dist/review/reviewOutcomeClassifier.js +61 -0
- package/dist/review/reviewRound.js +56 -4
- package/dist/run/agentRun.js +80 -4
- package/dist/run/providerRetry.js +84 -0
- package/dist/run/providerRetryConfig.js +63 -0
- package/dist/run/yieldReceipt.js +65 -0
- package/dist/runtime/exactControlPlane.js +79 -2
- package/dist/runtime/index.js +4 -0
- package/dist/runtime/sessionOwnerIdentity.js +269 -0
- package/dist/runtime/sessionOwnerRegistry.js +132 -0
- package/dist/runtime/sessionReconciliation.js +93 -0
- package/dist/runtime/sessionTerminationGuard.js +211 -0
- package/dist/runtime/taskRuntimeIsolation.js +13 -0
- package/dist/runtime/tmuxAdapters.js +34 -1
- package/dist/scheduler/actionability.js +155 -0
- package/dist/scheduler/activeRoleRunDelivery.js +14 -5
- package/dist/scheduler/activeTaskProgress.js +60 -0
- package/dist/scheduler/leaderWakeupProcessor.js +22 -11
- package/dist/scheduler/roleRunStall.js +135 -29
- package/dist/scheduler/taskExecutionProjection.js +11 -0
- package/dist/storage/compatibleTaskStore.js +112 -5
- package/dist/storage/migration/productionRegistry.js +736 -1
- package/dist/storage/sqliteSchema.js +264 -3
- package/dist/storage/sqliteStore.js +487 -13
- package/dist/storage/storeRpc.js +21 -0
- package/dist/storage/taskStore.js +974 -21
- package/dist/storage/upgrade/homeClassification.js +120 -2
- package/dist/storage/upgrade/migrationReceipt.js +67 -0
- package/dist/storage/upgrade/pseudoLayoutRepair.js +241 -0
- package/dist/storage/upgrade/recordVersions.js +10 -1
- package/dist/storage/upgrade/sqliteMigrationTarget.js +58 -6
- package/dist/storage/upgrade/sqliteRecordMigrationTarget.js +290 -0
- package/dist/storage/upgrade/sqliteStateMigration.js +258 -2
- package/dist/storage/upgrade/upgradeOrchestrator.js +482 -16
- package/dist/task/deliveryGuard.js +226 -0
- package/dist/task/nextAction.js +738 -0
- package/dist/task/repairWave.js +137 -0
- package/dist/task/taskRecordReference.js +6 -1
- package/dist/telemetry/sqliteTelemetryStore.js +387 -0
- package/dist/telemetry/telemetryCompaction.js +251 -0
- package/dist/telemetry/telemetryConfig.js +64 -0
- package/dist/telemetry/telemetryRouter.js +32 -0
- package/dist/telemetry/telemetryStore.js +19 -0
- package/dist/telemetry/telemetryWiring.js +33 -0
- package/dist/tmux/tmuxManager.js +20 -1
- package/dist/tmux/tmuxSocketEndpoint.js +20 -0
- package/dist/verification/gateArtifact.js +216 -0
- package/dist/verification/gateArtifactStore.js +87 -0
- package/dist/verification/verificationGateService.js +414 -0
- package/dist/verification/verificationPlan.js +308 -0
- package/dist/workspace/gitChangeSetCapture.js +12 -2
- package/dist/workspace/workItemChangeSetManager.js +60 -3
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +8 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Controller handover candidate prelude (Issue 02).
|
|
3
|
+
*
|
|
4
|
+
* A handover candidate is the new release's Controller process started while
|
|
5
|
+
* the old Controller still owns the Home. It does NOT bind the main socket or
|
|
6
|
+
* run the scheduler: it proves the new release starts, publishes its identity
|
|
7
|
+
* receipt, and waits until the old owner exits AND the active release pointer
|
|
8
|
+
* names its release. Only then does it promote itself by starting the full
|
|
9
|
+
* Controller runtime in-process.
|
|
10
|
+
*
|
|
11
|
+
* If the old owner stays live after the commit (a stuck Controller), the
|
|
12
|
+
* candidate stays read-only and reports `dualOwner: true` in its identity
|
|
13
|
+
* receipt; it never writes while another owner is live.
|
|
14
|
+
*/
|
|
15
|
+
import { fileURLToPath } from "node:url";
|
|
16
|
+
import { buildRuntimeIdentityReceipt } from "../core/controllerServer.js";
|
|
17
|
+
import { resolveStoreWorkerEnabledForHome } from "../storage/storeRpc.js";
|
|
18
|
+
import { resolveTaskStoreBackendForHome } from "../storage/sqliteStore.js";
|
|
19
|
+
import { detectRunningRelease, isOwnerLive, readActiveReleasePointer, readHandoverFence, removeCandidateDiscovery, removeHandoverFence, writeCandidateDiscovery, writeHandoverFence, writeHandoverReceipt, writeRuntimeIdentity } from "../release/runtimeRelease.js";
|
|
20
|
+
import { startFileTaskControllerRuntime } from "./runtime.js";
|
|
21
|
+
import { readLinuxProcessStartIdentity } from "./domainIdentity.js";
|
|
22
|
+
export const CONTROLLER_CANDIDATE_ENV = "YUI_CONTROLLER_CANDIDATE";
|
|
23
|
+
export const CONTROLLER_HANDOVER_ID_ENV = "YUI_CONTROLLER_HANDOVER_ID";
|
|
24
|
+
const DEFAULT_POLL_INTERVAL_MS = 100;
|
|
25
|
+
/**
|
|
26
|
+
* The grace a committed candidate waits for the old owner to exit before it
|
|
27
|
+
* latches `dualOwner: true`. This is the single authoritative old-owner exit
|
|
28
|
+
* grace: the activator trusts the candidate's latched signal and does not add
|
|
29
|
+
* a second independent grace (see `DEFAULT_DUAL_OWNER_GRACE_MS` in
|
|
30
|
+
* `releaseHandover.ts`, which is only an optional confirmation debounce).
|
|
31
|
+
*/
|
|
32
|
+
export const DEFAULT_DUAL_OWNER_GRACE_MS = 30_000;
|
|
33
|
+
/** Reads the candidate configuration from the process environment. */
|
|
34
|
+
export function handoverCandidateFromEnvironment(environment) {
|
|
35
|
+
if (environment[CONTROLLER_CANDIDATE_ENV] !== "1")
|
|
36
|
+
return null;
|
|
37
|
+
const handoverId = environment[CONTROLLER_HANDOVER_ID_ENV];
|
|
38
|
+
if (typeof handoverId !== "string"
|
|
39
|
+
|| handoverId.length === 0
|
|
40
|
+
|| handoverId.length > 128) {
|
|
41
|
+
throw new Error(`Handover candidate requires ${CONTROLLER_HANDOVER_ID_ENV} with a valid handover id.`);
|
|
42
|
+
}
|
|
43
|
+
return { handoverId };
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Runs the candidate prelude and, on promotion, the full Controller runtime.
|
|
47
|
+
* Resolves when the promoted Controller closes or the candidate aborts.
|
|
48
|
+
*/
|
|
49
|
+
export async function runHandoverCandidate(home, handoverId, options = {}) {
|
|
50
|
+
const environment = options.environment ?? process.env;
|
|
51
|
+
const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
52
|
+
const dualOwnerGraceMs = options.dualOwnerGraceMs ?? DEFAULT_DUAL_OWNER_GRACE_MS;
|
|
53
|
+
const now = options.now ?? (() => new Date());
|
|
54
|
+
const release = detectRunningRelease(fileURLToPath(import.meta.url));
|
|
55
|
+
const startIdentity = readLinuxProcessStartIdentity(process.pid);
|
|
56
|
+
if (startIdentity === undefined) {
|
|
57
|
+
throw new Error(`Cannot read process start identity for handover candidate PID ${process.pid}.`);
|
|
58
|
+
}
|
|
59
|
+
const fence = readHandoverFence(home);
|
|
60
|
+
if (fence === null || fence.handoverId !== handoverId) {
|
|
61
|
+
throw new Error(`Handover fence for ${handoverId} is missing or does not match; aborting candidate.`);
|
|
62
|
+
}
|
|
63
|
+
// A candidate only starts from the `fenced` phase. If the activator already
|
|
64
|
+
// rolled the handover back (fence written as `rolled-back`, old Controller
|
|
65
|
+
// restored), a slow-starting candidate must not resurrect the fence to
|
|
66
|
+
// `candidate-ready`: that would leak the candidate process and could lead a
|
|
67
|
+
// later `release activate` recovery into a split-brain commit.
|
|
68
|
+
if (fence.phase !== "fenced") {
|
|
69
|
+
removeCandidateDiscovery(home);
|
|
70
|
+
return {
|
|
71
|
+
outcome: "aborted",
|
|
72
|
+
reason: `Handover fence is in phase '${fence.phase}', not 'fenced'; the handover was rolled back.`
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
// Publish the candidate identity so the activator can read back build ID,
|
|
76
|
+
// backend, and worker state before committing the handover.
|
|
77
|
+
writeCandidateDiscovery(home, { pid: process.pid, processStartIdentity: startIdentity });
|
|
78
|
+
writeRuntimeIdentity(home, buildRuntimeIdentityReceipt({
|
|
79
|
+
home,
|
|
80
|
+
release,
|
|
81
|
+
storageBackend: resolveTaskStoreBackendForHome(home, environment),
|
|
82
|
+
workerEnabled: resolveStoreWorkerEnabledForHome(home, environment),
|
|
83
|
+
processStartIdentity: startIdentity,
|
|
84
|
+
mode: "candidate",
|
|
85
|
+
dualOwner: false
|
|
86
|
+
}));
|
|
87
|
+
advanceFence(home, fence, "candidate-ready", now().toISOString());
|
|
88
|
+
const committedAt = Date.now();
|
|
89
|
+
let dualOwnerReported = false;
|
|
90
|
+
for (;;) {
|
|
91
|
+
const current = readHandoverFence(home);
|
|
92
|
+
if (current === null || current.handoverId !== handoverId) {
|
|
93
|
+
removeCandidateDiscovery(home);
|
|
94
|
+
return {
|
|
95
|
+
outcome: "aborted",
|
|
96
|
+
reason: "Handover fence disappeared; the handover was rolled back."
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
if (current.phase === "rolled-back") {
|
|
100
|
+
removeCandidateDiscovery(home);
|
|
101
|
+
return {
|
|
102
|
+
outcome: "aborted",
|
|
103
|
+
reason: "Handover was rolled back while the candidate was polling."
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
const oldDead = !isOwnerLive(current.old);
|
|
107
|
+
const pointer = readActiveReleasePointer(home);
|
|
108
|
+
const pointerSwitched = pointer !== null && pointer.releaseId === current.toReleaseId;
|
|
109
|
+
if (oldDead && pointerSwitched) {
|
|
110
|
+
return await promote(home, current, environment, now);
|
|
111
|
+
}
|
|
112
|
+
if (current.phase === "committed"
|
|
113
|
+
&& !oldDead
|
|
114
|
+
&& Date.now() - committedAt > dualOwnerGraceMs
|
|
115
|
+
&& !dualOwnerReported) {
|
|
116
|
+
// The old Controller was told to exit but is still live. Stay read-only
|
|
117
|
+
// and make the dual-owner condition visible; never write concurrently.
|
|
118
|
+
dualOwnerReported = true;
|
|
119
|
+
writeRuntimeIdentity(home, buildRuntimeIdentityReceipt({
|
|
120
|
+
home,
|
|
121
|
+
release,
|
|
122
|
+
storageBackend: resolveTaskStoreBackendForHome(home, environment),
|
|
123
|
+
workerEnabled: resolveStoreWorkerEnabledForHome(home, environment),
|
|
124
|
+
processStartIdentity: startIdentity,
|
|
125
|
+
mode: "candidate",
|
|
126
|
+
dualOwner: true
|
|
127
|
+
}));
|
|
128
|
+
}
|
|
129
|
+
await delay(pollIntervalMs);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async function promote(home, fence, environment, now) {
|
|
133
|
+
removeCandidateDiscovery(home);
|
|
134
|
+
const controller = await startFileTaskControllerRuntime(home, { environment });
|
|
135
|
+
// The promoted Controller server has already published its primary identity
|
|
136
|
+
// receipt. Complete the handover record and release the fence.
|
|
137
|
+
writeHandoverReceipt(home, Object.freeze({
|
|
138
|
+
schemaVersion: 1,
|
|
139
|
+
handoverId: fence.handoverId,
|
|
140
|
+
outcome: "completed",
|
|
141
|
+
old: fence.old,
|
|
142
|
+
candidate: fence.candidate,
|
|
143
|
+
previousReleaseId: fence.fromReleaseId,
|
|
144
|
+
activatedReleaseId: fence.toReleaseId,
|
|
145
|
+
startedAt: fence.createdAt,
|
|
146
|
+
completedAt: now().toISOString()
|
|
147
|
+
}));
|
|
148
|
+
removeHandoverFence(home);
|
|
149
|
+
const stop = () => {
|
|
150
|
+
void controller.close().catch(() => undefined);
|
|
151
|
+
};
|
|
152
|
+
process.once("SIGINT", stop);
|
|
153
|
+
process.once("SIGTERM", stop);
|
|
154
|
+
try {
|
|
155
|
+
await controller.closed;
|
|
156
|
+
}
|
|
157
|
+
finally {
|
|
158
|
+
process.removeListener("SIGINT", stop);
|
|
159
|
+
process.removeListener("SIGTERM", stop);
|
|
160
|
+
}
|
|
161
|
+
return { outcome: "promoted", reason: "Candidate promoted and Controller closed." };
|
|
162
|
+
}
|
|
163
|
+
function advanceFence(home, fence, phase, updatedAt) {
|
|
164
|
+
writeHandoverFence(home, Object.freeze({ ...fence, phase, updatedAt }));
|
|
165
|
+
}
|
|
166
|
+
function delay(ms) {
|
|
167
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
168
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { resolveJobCaller } from "../commands/taskActor.js";
|
|
2
|
+
import { callFileTaskController } from "./clientRuntime.js";
|
|
3
|
+
export async function startDurableJob(home, params, clientOptions = {}) {
|
|
4
|
+
// rr6/f2: Route through callFileTaskController so an Integration-issued
|
|
5
|
+
// job.start starts a stopped per-Home Controller on demand, mirroring the
|
|
6
|
+
// `job start` CLI. A bare callController only reads discovery and fails.
|
|
7
|
+
const result = await callFileTaskController(home, "job.start", params, clientOptions);
|
|
8
|
+
return parseStartResult(result);
|
|
9
|
+
}
|
|
10
|
+
export async function getDurableJob(home, taskId, jobId, clientOptions = {}) {
|
|
11
|
+
const result = await callFileTaskController(home, "job.get", { taskId, jobId }, clientOptions);
|
|
12
|
+
return parseJobResult(result);
|
|
13
|
+
}
|
|
14
|
+
export async function acknowledgeDurableJob(home, taskId, jobId, caller, clientOptions = {}) {
|
|
15
|
+
const result = await callFileTaskController(home, "job.acknowledge", {
|
|
16
|
+
taskId,
|
|
17
|
+
jobId,
|
|
18
|
+
caller
|
|
19
|
+
}, clientOptions);
|
|
20
|
+
if (typeof result !== "object" || result === null || Array.isArray(result)
|
|
21
|
+
|| typeof result.acknowledged !== "boolean") {
|
|
22
|
+
throw new Error("Controller job.acknowledge returned an invalid result.");
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
job: parseJobResult(result),
|
|
26
|
+
acknowledged: result.acknowledged
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export async function cancelDurableJob(home, taskId, jobId, caller, clientOptions = {}) {
|
|
30
|
+
const result = await callFileTaskController(home, "job.cancel", { taskId, jobId, caller }, clientOptions);
|
|
31
|
+
if (typeof result !== "object" || result === null || Array.isArray(result)
|
|
32
|
+
|| typeof result.cancelRequested !== "boolean") {
|
|
33
|
+
throw new Error("Controller job.cancel returned an invalid result.");
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
job: parseJobResult(result),
|
|
37
|
+
cancelRequested: result.cancelRequested
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function parseStartResult(value) {
|
|
41
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)
|
|
42
|
+
|| typeof value.created !== "boolean") {
|
|
43
|
+
throw new Error("Controller job.start returned an invalid result.");
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
job: parseJobResult(value),
|
|
47
|
+
created: value.created
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function parseJobResult(value) {
|
|
51
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
52
|
+
throw new Error("Controller returned an invalid DurableJob result.");
|
|
53
|
+
}
|
|
54
|
+
const job = value.job;
|
|
55
|
+
if (typeof job !== "object" || job === null || Array.isArray(job)) {
|
|
56
|
+
throw new Error("Controller returned an invalid DurableJob record.");
|
|
57
|
+
}
|
|
58
|
+
return job;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Production IntegrationJobPort: Integration checks ask the Controller socket
|
|
62
|
+
* for their DurableJob. The Controller owns the detached runner, so a Leader
|
|
63
|
+
* exit or Session replacement never kills a running check.
|
|
64
|
+
*
|
|
65
|
+
* rr6/f2: The port routes through callFileTaskController, so an Integration
|
|
66
|
+
* operation that issues a job.* RPC (start/continue/abort, and job-backed Task
|
|
67
|
+
* completion) starts a stopped per-Home Controller on demand. Read-only
|
|
68
|
+
* list/show paths do not use this port and stay lean.
|
|
69
|
+
*/
|
|
70
|
+
export function createControllerIntegrationJobPort(home, clientOptions = {}) {
|
|
71
|
+
const { store, ...controllerOptions } = clientOptions;
|
|
72
|
+
return {
|
|
73
|
+
async startCheckJob(input) {
|
|
74
|
+
const owner = {
|
|
75
|
+
kind: "integration-attempt",
|
|
76
|
+
integrationAttemptId: input.integrationId
|
|
77
|
+
};
|
|
78
|
+
// rr8/rr12: Bind the Integration-issued job to the caller's managed
|
|
79
|
+
// identity. A user-scope caller carries a verified Leader assertion.
|
|
80
|
+
const caller = resolveJobCaller(controllerOptions.environment, input.taskId, store);
|
|
81
|
+
const { job } = await startDurableJob(home, {
|
|
82
|
+
taskId: input.taskId,
|
|
83
|
+
owner,
|
|
84
|
+
projectId: input.projectId,
|
|
85
|
+
head: input.head,
|
|
86
|
+
workspace: input.workspace,
|
|
87
|
+
env: input.env,
|
|
88
|
+
steps: input.steps,
|
|
89
|
+
caller
|
|
90
|
+
}, controllerOptions);
|
|
91
|
+
return job;
|
|
92
|
+
},
|
|
93
|
+
async getJob(taskId, jobId) {
|
|
94
|
+
return getDurableJob(home, taskId, jobId, controllerOptions);
|
|
95
|
+
},
|
|
96
|
+
async cancelJob(taskId, jobId) {
|
|
97
|
+
// rr8/rr12: Bind the cancel request to the caller's managed identity.
|
|
98
|
+
const caller = resolveJobCaller(controllerOptions.environment, taskId, store);
|
|
99
|
+
await cancelDurableJob(home, taskId, jobId, caller, controllerOptions);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|