@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
|
@@ -66,7 +66,7 @@ export class FileRuntimeEventInbox {
|
|
|
66
66
|
}
|
|
67
67
|
enqueueProviderProgress(input) {
|
|
68
68
|
const normalized = normalizeProviderProgressInput(input);
|
|
69
|
-
return this.
|
|
69
|
+
return this.publishProgress(Object.freeze({
|
|
70
70
|
schemaVersion: 1,
|
|
71
71
|
id: runtimeEventId("native-turn-progress", normalized),
|
|
72
72
|
type: "native-turn-progress",
|
|
@@ -74,6 +74,16 @@ export class FileRuntimeEventInbox {
|
|
|
74
74
|
...normalized
|
|
75
75
|
}));
|
|
76
76
|
}
|
|
77
|
+
enqueueDurableJobTerminal(input) {
|
|
78
|
+
const normalized = normalizeDurableJobTerminalInput(input);
|
|
79
|
+
return this.publish(Object.freeze({
|
|
80
|
+
schemaVersion: 1,
|
|
81
|
+
id: runtimeEventId("durable-job-terminal", normalized),
|
|
82
|
+
type: "durable-job-terminal",
|
|
83
|
+
receivedAt: this.now().toISOString(),
|
|
84
|
+
...normalized
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
77
87
|
list() {
|
|
78
88
|
if (!existsSync(this.directory))
|
|
79
89
|
return [];
|
|
@@ -99,8 +109,7 @@ export class FileRuntimeEventInbox {
|
|
|
99
109
|
}
|
|
100
110
|
}
|
|
101
111
|
}
|
|
102
|
-
return events.sort(
|
|
103
|
-
|| left.id.localeCompare(right.id)));
|
|
112
|
+
return events.sort(compareRuntimeEvents);
|
|
104
113
|
}
|
|
105
114
|
read(id) {
|
|
106
115
|
assertEventId(id);
|
|
@@ -145,6 +154,44 @@ export class FileRuntimeEventInbox {
|
|
|
145
154
|
throw error;
|
|
146
155
|
}
|
|
147
156
|
}
|
|
157
|
+
acknowledgeMany(ids) {
|
|
158
|
+
if (ids.length === 0)
|
|
159
|
+
return [];
|
|
160
|
+
const acknowledged = [];
|
|
161
|
+
try {
|
|
162
|
+
for (const id of ids) {
|
|
163
|
+
assertEventId(id);
|
|
164
|
+
try {
|
|
165
|
+
unlinkSync(this.eventPath(id));
|
|
166
|
+
acknowledged.push(id);
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
if (!isNodeError(error, "ENOENT"))
|
|
170
|
+
throw error;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
finally {
|
|
175
|
+
// Preserve the old per-event durability guarantee even when a later
|
|
176
|
+
// unlink in the batch fails after earlier entries were removed.
|
|
177
|
+
if (acknowledged.length > 0)
|
|
178
|
+
fsyncDirectory(this.directory);
|
|
179
|
+
}
|
|
180
|
+
return acknowledged;
|
|
181
|
+
}
|
|
182
|
+
publishProgress(event) {
|
|
183
|
+
return withUpgradeCoordinationLock(this.home, () => {
|
|
184
|
+
this.hooks.afterAdmission?.();
|
|
185
|
+
const result = this.publishUnlocked(event);
|
|
186
|
+
if (!result.created)
|
|
187
|
+
return result;
|
|
188
|
+
const superseded = this.supersededProgressIds(event);
|
|
189
|
+
if (superseded.length === 0)
|
|
190
|
+
return result;
|
|
191
|
+
this.acknowledgeMany(superseded);
|
|
192
|
+
return { ...result, coalescedEventCount: superseded.length };
|
|
193
|
+
});
|
|
194
|
+
}
|
|
148
195
|
publish(event) {
|
|
149
196
|
// The fence check and the complete durable write share one sibling
|
|
150
197
|
// coordination lock with upgrade's final inbox scan/copy/two-step switch.
|
|
@@ -153,45 +200,77 @@ export class FileRuntimeEventInbox {
|
|
|
153
200
|
// UpgradeFenceError after the cutover holder releases the lock.
|
|
154
201
|
return withUpgradeCoordinationLock(this.home, () => {
|
|
155
202
|
this.hooks.afterAdmission?.();
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
203
|
+
return this.publishUnlocked(event);
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
publishUnlocked(event) {
|
|
207
|
+
const content = `${JSON.stringify(event)}\n`;
|
|
208
|
+
if (Buffer.byteLength(content, "utf8") > MAX_RUNTIME_EVENT_FILE_BYTES) {
|
|
209
|
+
throw new RuntimeEventInboxError("RUNTIME_EVENT_TOO_LARGE", "Runtime event exceeds the durable inbox limit.");
|
|
210
|
+
}
|
|
211
|
+
ensureInboxDirectory(this.directory);
|
|
212
|
+
const target = this.eventPath(event.id);
|
|
213
|
+
const temporary = join(this.directory, `.${event.id}.tmp-${process.pid}-${randomUUID()}`);
|
|
214
|
+
let descriptor = null;
|
|
215
|
+
try {
|
|
216
|
+
descriptor = openSync(temporary, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY, 0o600);
|
|
217
|
+
writeFileSync(descriptor, content, "utf8");
|
|
218
|
+
fchmodSync(descriptor, 0o600);
|
|
219
|
+
fsyncSync(descriptor);
|
|
220
|
+
closeSync(descriptor);
|
|
221
|
+
descriptor = null;
|
|
164
222
|
try {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
return { event, created:
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
if (!isNodeError(error, "EEXIST"))
|
|
179
|
-
throw error;
|
|
180
|
-
const existing = this.read(event.id);
|
|
181
|
-
if (existing === null)
|
|
182
|
-
return { event, created: false };
|
|
183
|
-
if (!hasSameIdentity(existing, event)) {
|
|
184
|
-
throw new RuntimeEventInboxError("RUNTIME_EVENT_CONFLICT", `Runtime event id conflicts with an existing file: ${event.id}`);
|
|
185
|
-
}
|
|
186
|
-
return { event: existing, created: false };
|
|
223
|
+
linkSync(temporary, target);
|
|
224
|
+
unlinkSync(temporary);
|
|
225
|
+
fsyncDirectory(this.directory);
|
|
226
|
+
return { event, created: true };
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
if (!isNodeError(error, "EEXIST"))
|
|
230
|
+
throw error;
|
|
231
|
+
const existing = this.read(event.id);
|
|
232
|
+
if (existing === null)
|
|
233
|
+
return { event, created: false };
|
|
234
|
+
if (!hasSameIdentity(existing, event)) {
|
|
235
|
+
throw new RuntimeEventInboxError("RUNTIME_EVENT_CONFLICT", `Runtime event id conflicts with an existing file: ${event.id}`);
|
|
187
236
|
}
|
|
237
|
+
return { event: existing, created: false };
|
|
188
238
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
239
|
+
}
|
|
240
|
+
finally {
|
|
241
|
+
if (descriptor !== null)
|
|
242
|
+
closeSync(descriptor);
|
|
243
|
+
rmSync(temporary, { force: true });
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
supersededProgressIds(event) {
|
|
247
|
+
const events = this.list();
|
|
248
|
+
const segment = semanticSegment(events, event);
|
|
249
|
+
const candidates = events.filter((candidate) => (candidate.type === "native-turn-progress"
|
|
250
|
+
&& sameProgressStream(candidate, event)
|
|
251
|
+
&& compareRuntimeEvents(candidate, segment.before) > 0
|
|
252
|
+
&& (segment.after === undefined || compareRuntimeEvents(candidate, segment.after) < 0)));
|
|
253
|
+
let latestReceivedAt = "";
|
|
254
|
+
let greatestSequence;
|
|
255
|
+
for (const candidate of candidates) {
|
|
256
|
+
const receivedAtOrder = candidate.receivedAt.localeCompare(latestReceivedAt);
|
|
257
|
+
if (receivedAtOrder > 0) {
|
|
258
|
+
latestReceivedAt = candidate.receivedAt;
|
|
259
|
+
greatestSequence = candidate.sequence;
|
|
193
260
|
}
|
|
194
|
-
|
|
261
|
+
else if (receivedAtOrder === 0
|
|
262
|
+
&& candidate.sequence !== undefined
|
|
263
|
+
&& (greatestSequence === undefined || candidate.sequence > greatestSequence)) {
|
|
264
|
+
greatestSequence = candidate.sequence;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return candidates.flatMap((candidate) => (candidate.receivedAt.localeCompare(latestReceivedAt) < 0
|
|
268
|
+
|| (candidate.receivedAt === latestReceivedAt
|
|
269
|
+
&& candidate.sequence !== undefined
|
|
270
|
+
&& greatestSequence !== undefined
|
|
271
|
+
&& candidate.sequence < greatestSequence)
|
|
272
|
+
? [candidate.id]
|
|
273
|
+
: []));
|
|
195
274
|
}
|
|
196
275
|
eventPath(id) {
|
|
197
276
|
return join(this.directory, `${id}.json`);
|
|
@@ -221,22 +300,37 @@ export class RuntimeEventInboxError extends Error {
|
|
|
221
300
|
}
|
|
222
301
|
}
|
|
223
302
|
function runtimeEventId(type, input) {
|
|
303
|
+
if (type === "durable-job-terminal") {
|
|
304
|
+
const job = input;
|
|
305
|
+
return `turn-${createHash("sha256").update(JSON.stringify([
|
|
306
|
+
1,
|
|
307
|
+
type,
|
|
308
|
+
job.scope,
|
|
309
|
+
job.taskId,
|
|
310
|
+
job.jobId,
|
|
311
|
+
job.status,
|
|
312
|
+
job.outcome
|
|
313
|
+
])).digest("hex")}`;
|
|
314
|
+
}
|
|
315
|
+
// The durable-job-terminal branch returned above; narrow the union so
|
|
316
|
+
// provider-only identity fields are accessible without `in` guards.
|
|
317
|
+
const provider = input;
|
|
224
318
|
const common = [
|
|
225
319
|
1,
|
|
226
320
|
type,
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
"turnId" in
|
|
235
|
-
|
|
236
|
-
"progressId" in
|
|
237
|
-
"sequence" in
|
|
238
|
-
"sessionSource" in
|
|
239
|
-
"receiptId" in
|
|
321
|
+
provider.scope,
|
|
322
|
+
provider.taskId ?? null,
|
|
323
|
+
provider.roleName,
|
|
324
|
+
provider.agentId,
|
|
325
|
+
provider.adapterId,
|
|
326
|
+
provider.launchId ?? null,
|
|
327
|
+
provider.nativeSessionId,
|
|
328
|
+
"turnId" in provider ? provider.turnId : null,
|
|
329
|
+
provider.runId ?? null,
|
|
330
|
+
"progressId" in provider ? provider.progressId : null,
|
|
331
|
+
"sequence" in provider ? provider.sequence ?? null : null,
|
|
332
|
+
"sessionSource" in provider ? provider.sessionSource ?? null : null,
|
|
333
|
+
"receiptId" in provider ? provider.receiptId ?? null : null
|
|
240
334
|
];
|
|
241
335
|
return `turn-${createHash("sha256").update(JSON.stringify(common)).digest("hex")}`;
|
|
242
336
|
}
|
|
@@ -357,6 +451,23 @@ function normalizeProviderProgressInput(input) {
|
|
|
357
451
|
...(input.sequence === undefined ? {} : { sequence: input.sequence })
|
|
358
452
|
};
|
|
359
453
|
}
|
|
454
|
+
function normalizeDurableJobTerminalInput(input) {
|
|
455
|
+
if (input.scope !== "task")
|
|
456
|
+
throw invalidEvent();
|
|
457
|
+
const terminalStatuses = [
|
|
458
|
+
"succeeded", "failed", "timed-out", "cancelled", "unknown-needs-attention"
|
|
459
|
+
];
|
|
460
|
+
if (!terminalStatuses.includes(input.status)) {
|
|
461
|
+
throw invalidEvent();
|
|
462
|
+
}
|
|
463
|
+
return {
|
|
464
|
+
scope: "task",
|
|
465
|
+
taskId: requireIdentityText(input.taskId, "Task id"),
|
|
466
|
+
jobId: requireIdentityText(input.jobId, "Job id"),
|
|
467
|
+
status: input.status,
|
|
468
|
+
outcome: requireIdentityText(input.outcome, "Job outcome")
|
|
469
|
+
};
|
|
470
|
+
}
|
|
360
471
|
function parseRuntimeEvent(value) {
|
|
361
472
|
if (!isObject(value))
|
|
362
473
|
throw invalidEvent();
|
|
@@ -366,6 +477,7 @@ function parseRuntimeEvent(value) {
|
|
|
366
477
|
case "native-session-lifecycle": return parseSessionLifecycleEvent(value);
|
|
367
478
|
case "native-prompt-accepted": return parsePromptAcceptedEvent(value);
|
|
368
479
|
case "native-turn-progress": return parseProviderProgressEvent(value);
|
|
480
|
+
case "durable-job-terminal": return parseDurableJobTerminalEvent(value);
|
|
369
481
|
default: throw invalidEvent();
|
|
370
482
|
}
|
|
371
483
|
}
|
|
@@ -420,6 +532,22 @@ function parseProviderProgressEvent(value) {
|
|
|
420
532
|
...normalized
|
|
421
533
|
});
|
|
422
534
|
}
|
|
535
|
+
function parseDurableJobTerminalEvent(value) {
|
|
536
|
+
const expected = [
|
|
537
|
+
"schemaVersion", "id", "type", "receivedAt", "scope", "taskId",
|
|
538
|
+
"jobId", "status", "outcome"
|
|
539
|
+
];
|
|
540
|
+
if (value.schemaVersion !== 1 || !hasExactKeys(value, expected))
|
|
541
|
+
throw invalidEvent();
|
|
542
|
+
const normalized = normalizeDurableJobTerminalInput(value);
|
|
543
|
+
return Object.freeze({
|
|
544
|
+
schemaVersion: 1,
|
|
545
|
+
id: requireIdentityText(value.id, "Event id"),
|
|
546
|
+
type: "durable-job-terminal",
|
|
547
|
+
receivedAt: requireTimestamp(value.receivedAt),
|
|
548
|
+
...normalized
|
|
549
|
+
});
|
|
550
|
+
}
|
|
423
551
|
function parseCodexEvent(value) {
|
|
424
552
|
const scope = value.scope;
|
|
425
553
|
const expected = scope === "task"
|
|
@@ -535,17 +663,66 @@ function hasSameIdentity(left, right) {
|
|
|
535
663
|
&& left.type === right.type
|
|
536
664
|
&& left.scope === right.scope
|
|
537
665
|
&& left.taskId === right.taskId
|
|
666
|
+
&& (!("roleName" in left) || !("roleName" in right) || left.roleName === right.roleName)
|
|
667
|
+
&& (!("agentId" in left) || !("agentId" in right) || left.agentId === right.agentId)
|
|
668
|
+
&& (!("adapterId" in left) || !("adapterId" in right) || left.adapterId === right.adapterId)
|
|
669
|
+
&& (!("launchId" in left) || !("launchId" in right) || left.launchId === right.launchId)
|
|
670
|
+
&& (!("nativeSessionId" in left)
|
|
671
|
+
|| !("nativeSessionId" in right)
|
|
672
|
+
|| left.nativeSessionId === right.nativeSessionId)
|
|
673
|
+
&& (!("runId" in left) || !("runId" in right) || left.runId === right.runId)
|
|
674
|
+
&& (!("turnId" in left) || !("turnId" in right) || left.turnId === right.turnId)
|
|
675
|
+
&& (!("progressId" in left)
|
|
676
|
+
|| !("progressId" in right)
|
|
677
|
+
|| left.progressId === right.progressId)
|
|
678
|
+
&& (!("sequence" in left) || !("sequence" in right) || left.sequence === right.sequence)
|
|
679
|
+
&& (!("jobId" in left) || !("jobId" in right) || left.jobId === right.jobId);
|
|
680
|
+
}
|
|
681
|
+
function compareRuntimeEvents(left, right) {
|
|
682
|
+
return left.receivedAt.localeCompare(right.receivedAt)
|
|
683
|
+
|| left.id.localeCompare(right.id);
|
|
684
|
+
}
|
|
685
|
+
/** Chooses one latest fact inside an already-isolated exact progress stream. */
|
|
686
|
+
export function compareRuntimeProgressRecency(left, right) {
|
|
687
|
+
const receivedAt = left.receivedAt.localeCompare(right.receivedAt);
|
|
688
|
+
if (receivedAt !== 0)
|
|
689
|
+
return receivedAt;
|
|
690
|
+
if (left.sequence !== undefined
|
|
691
|
+
&& right.sequence !== undefined
|
|
692
|
+
&& left.sequence !== right.sequence) {
|
|
693
|
+
return left.sequence - right.sequence;
|
|
694
|
+
}
|
|
695
|
+
// A content-derived event id is identity, not arrival evidence. Without two
|
|
696
|
+
// comparable provider sequences, same-timestamp facts remain incomparable.
|
|
697
|
+
return 0;
|
|
698
|
+
}
|
|
699
|
+
function semanticSegment(events, current) {
|
|
700
|
+
let before = {
|
|
701
|
+
receivedAt: "",
|
|
702
|
+
id: ""
|
|
703
|
+
};
|
|
704
|
+
let after;
|
|
705
|
+
for (const event of events) {
|
|
706
|
+
if (event.type === "native-turn-progress")
|
|
707
|
+
continue;
|
|
708
|
+
const order = compareRuntimeEvents(event, current);
|
|
709
|
+
if (order < 0 && compareRuntimeEvents(event, before) > 0) {
|
|
710
|
+
before = event;
|
|
711
|
+
}
|
|
712
|
+
else if (order > 0 && (after === undefined || compareRuntimeEvents(event, after) < 0)) {
|
|
713
|
+
after = event;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
return { before, ...(after === undefined ? {} : { after }) };
|
|
717
|
+
}
|
|
718
|
+
function sameProgressStream(left, right) {
|
|
719
|
+
return left.taskId === right.taskId
|
|
538
720
|
&& left.roleName === right.roleName
|
|
539
721
|
&& left.agentId === right.agentId
|
|
540
722
|
&& left.adapterId === right.adapterId
|
|
541
723
|
&& left.launchId === right.launchId
|
|
542
724
|
&& left.nativeSessionId === right.nativeSessionId
|
|
543
|
-
&& left.runId === right.runId
|
|
544
|
-
&& (!("turnId" in left) || !("turnId" in right) || left.turnId === right.turnId)
|
|
545
|
-
&& (!("progressId" in left)
|
|
546
|
-
|| !("progressId" in right)
|
|
547
|
-
|| left.progressId === right.progressId)
|
|
548
|
-
&& (!("sequence" in left) || !("sequence" in right) || left.sequence === right.sequence);
|
|
725
|
+
&& left.runId === right.runId;
|
|
549
726
|
}
|
|
550
727
|
function hasExactKeys(value, expected) {
|
|
551
728
|
const actual = Object.keys(value).sort();
|