@zq-silk/yui 0.16.1 → 1.0.0-alpha
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 +12 -0
- package/ARCHITECTURE.zh-CN.md +8 -0
- package/README.md +9 -4
- package/dist/agent/agent.js +4 -9
- package/dist/agent/executionComponents.js +4 -4
- package/dist/agent/managedRuntimeEnvironment.js +0 -4
- package/dist/agentRun/agentRun.js +13 -23
- package/dist/artifacts/managedGit.js +3 -56
- package/dist/brief/taskBrief.js +3 -3
- package/dist/cli/agentConfigurationPicker.js +24 -21
- package/dist/cli/commandCatalog.js +18 -10
- package/dist/cli/roleWizard.js +41 -30
- package/dist/cli/updateCommand.js +35 -13
- package/dist/cli/updateOrchestrator.js +73 -44
- package/dist/cli/updatePorts.js +76 -86
- package/dist/cli/upgradeCommand.js +4 -8
- package/dist/cli.js +39 -33
- package/dist/commands/controllerCommands.js +2 -2
- package/dist/commands/executionAuditCommands.js +2 -2
- package/dist/commands/projectCommands.js +1 -1
- package/dist/commands/releaseCommands.js +9 -38
- package/dist/commands/taskCommands.js +91 -81
- package/dist/commands/taskCompletionGate.js +0 -117
- package/dist/commands/taskRoleRuntimeStatus.js +2 -2
- package/dist/commands/taskUpstreamCommands.js +93 -54
- package/dist/context/runContextPack.js +30 -54
- package/dist/context/runInputContract.js +9 -0
- package/dist/context/sessionBootstrapManifest.js +11 -19
- package/dist/controller/agentHostObservation.js +4 -2
- package/dist/controller/agentRuntimeObserver.js +4 -4
- package/dist/controller/clientRuntime.js +19 -44
- package/dist/controller/controller.js +24 -10
- package/dist/controller/fileSchedulerStoreAdapter.js +91 -24
- package/dist/controller/globalInputDelivery.js +31 -8
- package/dist/controller/globalRuntimeAttention.js +34 -0
- package/dist/controller/jobSupervisor.js +3 -3
- package/dist/controller/operatorNotification.js +31 -0
- package/dist/controller/providerRetryAdmission.js +3 -1
- package/dist/controller/providerRetryDelivery.js +136 -119
- package/dist/controller/runtime.js +2 -28
- package/dist/controller/sessionOwnerReconciliation.js +42 -24
- package/dist/controller/structuredProviderObservation.js +28 -1
- package/dist/controller/updateReconciliation.js +72 -20
- package/dist/coordination/workMailbox.js +4 -4
- package/dist/core/controllerIdentity.js +25 -0
- package/dist/core/controllerProcessIdentity.js +2 -2
- package/dist/core/controllerServer.js +4 -2
- package/dist/core/protocol.js +1 -1
- package/dist/doctor/doctor.js +2 -1
- package/dist/domain/validation.js +6 -0
- package/dist/event/taskEvent.js +3 -3
- package/dist/execution/workItemExecution.js +2 -2
- package/dist/executor/agentAdapter.js +28 -96
- package/dist/executor/agentConfigurationCatalog.js +13 -68
- package/dist/executor/agentConfigurationFields.js +120 -0
- package/dist/executor/agentConfigurationProbe.js +55 -80
- package/dist/executor/agentExecutor.js +11 -8
- package/dist/executor/effectiveLaunch.js +3 -3
- package/dist/executor/executorRegistry.js +0 -9
- package/dist/executor/fileRoleLaunchPlanner.js +12 -11
- package/dist/grant/capabilityGrant.js +2 -2
- package/dist/input/inputRequest.js +4 -4
- package/dist/integration/changeSet.js +3 -3
- package/dist/integration/integrationAttempt.js +3 -3
- package/dist/integration/integrationSourceApplication.js +1 -1
- package/dist/interaction/operatorPresentation.js +2 -1
- package/dist/job/durableJob.js +1 -1
- package/dist/job/jobRunner.js +2 -2
- package/dist/message/message.js +8 -6
- package/dist/message/messageContinuation.js +8 -9
- package/dist/milestone/milestone.js +3 -3
- package/dist/observability/executionAudit.js +1 -10
- package/dist/observability/runtimeIdentity.js +0 -23
- package/dist/output/agentConfigurationPresentation.js +4 -2
- package/dist/profile/agentProfile.js +3 -3
- package/dist/release/releaseHandover.js +2 -2
- package/dist/release/releaseIdempotencyStore.js +0 -23
- package/dist/release/releaseWorkflowPorts.js +8 -4
- package/dist/release/runtimeRelease.js +9 -7
- package/dist/repository/gitWorkspace.js +66 -19
- package/dist/repository/project.js +3 -3
- package/dist/repository/taskWorkspacePreparer.js +75 -68
- package/dist/resources/liveReferences.js +1 -1
- package/dist/resources/resourceRegistry.js +90 -44
- package/dist/resources/sqliteResourceRegistry.js +5 -7
- package/dist/review/reviewRound.js +5 -5
- package/dist/role/role.js +7 -8
- package/dist/runtime/acpProtocol.js +2 -3
- package/dist/runtime/acpSession.js +21 -5
- package/dist/runtime/agentDriverObservation.js +1 -1
- package/dist/runtime/agentEndpoint.js +4 -1
- package/dist/runtime/agentHost.js +25 -65
- package/dist/runtime/agentHostCleanup.js +85 -0
- package/dist/runtime/agentHostProtocol.js +3 -3
- package/dist/runtime/builtinAgentDrivers.js +46 -119
- package/dist/runtime/builtinTranscriptObserver.js +10 -6
- package/dist/runtime/codexAppServerRuntime.js +55 -89
- package/dist/runtime/codexInteractiveHost.js +1 -1
- package/dist/runtime/jsonLineChannel.js +35 -7
- package/dist/runtime/launchBroker.js +1 -1
- package/dist/runtime/processExitObservation.js +1 -1
- package/dist/runtime/providerContinuationReconciliationService.js +86 -38
- package/dist/runtime/providerRetry.js +15 -0
- package/dist/runtime/providerRuntimeIdentity.js +3 -3
- package/dist/runtime/providerRuntimeReconciler.js +12 -2
- package/dist/runtime/runtimeCoherence.js +7 -3
- package/dist/runtime/runtimeObservation.js +3 -3
- package/dist/runtime/sessionOwnerIdentity.js +1 -1
- package/dist/runtime/structuredProviderHost.js +106 -81
- package/dist/runtime/taskRuntimeIsolation.js +3 -3
- package/dist/runtime/tmuxAdapters.js +3 -3
- package/dist/scheduler/activeRoleRunDelivery.js +5 -1
- package/dist/scheduler/operatorInputNotificationProcessor.js +7 -17
- package/dist/scheduler/taskWake.js +1 -1
- package/dist/storage/baselineSchema.js +606 -0
- package/dist/storage/homeLayout.js +5 -16
- package/dist/storage/recordValidation.js +16 -4
- package/dist/storage/sqliteSchema.js +106 -1741
- package/dist/storage/sqliteStore.js +16 -14
- package/dist/storage/storageSchema.js +8 -7
- package/dist/storage/storageVersions.js +23 -16
- package/dist/storage/taskStore.js +3 -29
- package/dist/storage/upgrade/upgradeOrchestrator.js +14 -112
- package/dist/task/nextAction.js +33 -23
- package/dist/task/task.js +17 -8
- package/dist/task/taskActivation.js +5 -4
- package/dist/telemetry/sqliteTelemetryStore.js +2 -2
- package/dist/verification/gateArtifact.js +5 -3
- package/dist/verification/verificationPlan.js +6 -7
- package/dist/web/assets/assetManifest.js +2 -0
- package/dist/web/assets/client/app.js +72 -3
- package/dist/web/assets/client/components.js +2 -1
- package/dist/web/assets/client/i18n.js +2 -0
- package/dist/web/assets/client/taskSummary.js +345 -0
- package/dist/web/assets/client/taskSurface.js +44 -26
- package/dist/web/assets/client/view.js +33 -0
- package/dist/web/assets/shell.js +1 -0
- package/dist/web/assets/styles/cards.js +21 -0
- package/dist/web/webServer.js +39 -5
- package/dist/web/webSessions.js +165 -0
- package/dist/web/webSnapshot.js +23 -0
- package/dist/web/webTaskSurface.js +23 -0
- package/dist/workItem/workItem.js +6 -6
- package/dist/workspace/cleanupInspection.js +1 -9
- package/dist/worktree/managedWorkspace.js +3 -3
- package/docs/managed-turn-and-session-runtime.md +50 -7
- package/docs/managed-turn-and-session-runtime.zh-CN.md +36 -5
- package/docs/observability/README.md +47 -0
- package/docs/observability/README.zh-CN.md +37 -0
- package/docs/project-refresh.md +9 -0
- package/docs/project-refresh.zh-CN.md +8 -0
- package/docs/provider-retry.md +35 -0
- package/docs/release-workflow.md +70 -214
- package/docs/release-workflow.zh-CN.md +53 -157
- package/docs/roles-and-configuration.md +30 -0
- package/docs/roles-and-configuration.zh-CN.md +20 -0
- package/docs/sqlite-control-plane-design.md +48 -289
- package/docs/sqlite-control-plane-design.zh-CN.md +37 -53
- package/docs/storage-baseline.md +132 -0
- package/docs/storage-baseline.zh-CN.md +106 -0
- package/docs/task-delivery.md +110 -2
- package/docs/task-delivery.zh-CN.md +82 -2
- package/docs/task-discovery.md +9 -0
- package/docs/task-discovery.zh-CN.md +6 -0
- package/docs/testing/verification-levels.md +42 -164
- package/docs/testing/verification-levels.zh-CN.md +29 -115
- package/i18n/README.zh-CN.md +7 -4
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +11 -0
- package/skills/yui-leader/references/execution.md +22 -0
- package/skills/yui-leader/references/planning.md +6 -2
- package/skills/yui-operator/SKILL.md +45 -13
- package/skills/yui-operator/references/task-delivery.md +99 -0
- package/skills/yui-runtime/SKILL.md +5 -3
- package/skills/yui-runtime/references/publication.md +56 -5
- package/skills/yui-runtime/references/recovery.md +12 -2
- package/dist/runtime/agentHostCompatibility.js +0 -127
- package/dist/storage/migrations/agentFailureContext.js +0 -22
- package/dist/storage/migrations/agentRunContract.js +0 -159
- package/dist/storage/migrations/artifactsToGit.js +0 -338
- package/dist/storage/migrations/collapseWorktreeLayout.js +0 -963
- package/dist/storage/migrations/currentInputContract.js +0 -86
- package/dist/storage/migrations/currentRuntimeContract.js +0 -228
- package/dist/storage/migrations/historicalVerificationPlan.js +0 -35
- package/dist/storage/migrations/integrationContinuation.js +0 -105
- package/dist/storage/migrations/narrowAgentFailureContext.js +0 -65
- package/dist/storage/migrations/notificationOnlyWakes.js +0 -74
- package/dist/storage/migrations/removeRuntimeGeneration.js +0 -207
- package/dist/storage/migrations/submitIntent.js +0 -126
- package/dist/storage/migrations/unifyHomeLayout.js +0 -925
- package/dist/storage/migrations/verificationPlanV1.js +0 -162
- package/dist/storage/migrations/verificationPolicy.js +0 -74
- package/dist/storage/migrations/workItemHistory.js +0 -46
|
@@ -545,7 +545,7 @@ export class FileTaskWorkspacePreparer {
|
|
|
545
545
|
const taskSegment = taskWorkspaceRefSegment(workspaceIdentity === undefined ? task : { ...task, workspaceIdentity });
|
|
546
546
|
const root = this.#taskWorkspaceRoot(task.id);
|
|
547
547
|
const prepared = [];
|
|
548
|
-
const
|
|
548
|
+
const createdClones = [];
|
|
549
549
|
const baselines = new Map();
|
|
550
550
|
try {
|
|
551
551
|
// Resolve every remote baseline before creating any Task clone. A later
|
|
@@ -595,7 +595,14 @@ export class FileTaskWorkspacePreparer {
|
|
|
595
595
|
})
|
|
596
596
|
: await this.git.inspect(previous.path, "HEAD");
|
|
597
597
|
if (previous === undefined)
|
|
598
|
-
|
|
598
|
+
createdClones.push({
|
|
599
|
+
project,
|
|
600
|
+
entry: {
|
|
601
|
+
projectId: project.id, directory: binding.directory, access: "write",
|
|
602
|
+
path: destination, branch: identity.branch,
|
|
603
|
+
baseRef: baseline.recordedBaseRef, baseCommit: physical.baseCommit
|
|
604
|
+
}
|
|
605
|
+
});
|
|
599
606
|
const physicalBranch = await this.git.headRef(physical.root);
|
|
600
607
|
if (physical.root !== (previous?.path ?? destination)
|
|
601
608
|
|| physicalBranch !== (previous?.branch ?? identity.branch)) {
|
|
@@ -794,16 +801,7 @@ export class FileTaskWorkspacePreparer {
|
|
|
794
801
|
// A failed or conflicted preparation owns no durable record: drop the
|
|
795
802
|
// branches too, so a retry mints a clean identity without half-created
|
|
796
803
|
// refs behind. Adopted (already catalogued) worktrees are never touched.
|
|
797
|
-
await this.#discardUnadoptedEntries(task, taskSegment,
|
|
798
|
-
const recorded = new Set(prepared.map(({ entry }) => entry.path));
|
|
799
|
-
for (const path of createdClonePaths) {
|
|
800
|
-
if (recorded.has(path))
|
|
801
|
-
continue;
|
|
802
|
-
const removal = await this.git.removeStrandedWorktree(path);
|
|
803
|
-
if (removal === "dirty") {
|
|
804
|
-
throw new Error(`Unadopted Task clone is dirty and was retained at ${path}; inspect it and retry.`);
|
|
805
|
-
}
|
|
806
|
-
}
|
|
804
|
+
await this.#discardUnadoptedEntries(task, taskSegment, createdClones, MAIN_WORKTREE, true, undefined, error);
|
|
807
805
|
if (activate)
|
|
808
806
|
await removeWorkspaceView(root);
|
|
809
807
|
throw error;
|
|
@@ -1125,7 +1123,7 @@ export class FileTaskWorkspacePreparer {
|
|
|
1125
1123
|
});
|
|
1126
1124
|
}
|
|
1127
1125
|
catch (error) {
|
|
1128
|
-
await this.#discardUnadoptedEntries(lockedTask, taskSegment, prepared, item.id);
|
|
1126
|
+
await this.#discardUnadoptedEntries(lockedTask, taskSegment, prepared, item.id, false, undefined, error);
|
|
1129
1127
|
throw error;
|
|
1130
1128
|
}
|
|
1131
1129
|
}
|
|
@@ -1276,7 +1274,7 @@ export class FileTaskWorkspacePreparer {
|
|
|
1276
1274
|
return workspace;
|
|
1277
1275
|
}
|
|
1278
1276
|
catch (error) {
|
|
1279
|
-
await this.#discardUnadoptedEntries(lockedTask, taskSegment, prepared, managedWorktreeName(owner), true);
|
|
1277
|
+
await this.#discardUnadoptedEntries(lockedTask, taskSegment, prepared, managedWorktreeName(owner), true, undefined, error);
|
|
1280
1278
|
throw error;
|
|
1281
1279
|
}
|
|
1282
1280
|
}
|
|
@@ -1354,48 +1352,39 @@ export class FileTaskWorkspacePreparer {
|
|
|
1354
1352
|
return "missing";
|
|
1355
1353
|
const task = requireTask(this.store, workspace.owner.taskId);
|
|
1356
1354
|
const taskSegment = this.#taskSegment(task);
|
|
1355
|
+
const root = this.#executionLaneWorkspaceRoot(task.id, workspace.owner.executionGroupId, workspace.owner.executionLaneId);
|
|
1356
|
+
if (workspace.root !== root)
|
|
1357
|
+
throw new Error("Unadopted Lane root does not match its managed owner.");
|
|
1357
1358
|
const writable = workspace.entries.filter(({ access }) => access === "write");
|
|
1358
|
-
|
|
1359
|
+
const completed = [];
|
|
1360
|
+
let target = root;
|
|
1359
1361
|
try {
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
catch (error) {
|
|
1363
|
-
// A `project migrate` between preparation and compensation switches the
|
|
1364
|
-
// catalog, so the worktree's common-dir no longer matches the Project's
|
|
1365
|
-
// current repository. Fall back to removing the stranded worktree
|
|
1366
|
-
// through its own Git identity.
|
|
1367
|
-
if (!(error instanceof Error && error.message.includes("belongs to another project"))) {
|
|
1368
|
-
throw error;
|
|
1369
|
-
}
|
|
1370
|
-
let removed = false;
|
|
1362
|
+
// This owner was never adopted. Its captured identity is sufficient to
|
|
1363
|
+
// inspect its own Git; no catalog-error matching or filesystem fallback.
|
|
1371
1364
|
for (const entry of writable) {
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1365
|
+
target = entry.path;
|
|
1366
|
+
const result = await this.git.removeStrandedWorktree(entry.path, {
|
|
1367
|
+
container: root, directory: entry.directory, taskSegment,
|
|
1368
|
+
roleName: managedWorktreeName(workspace.owner), expectedCommit: entry.baseCommit,
|
|
1369
|
+
deleteBranch: true
|
|
1370
|
+
});
|
|
1371
|
+
if (result === "dirty") {
|
|
1372
|
+
if (completed.length === 0)
|
|
1373
|
+
return "dirty";
|
|
1374
|
+
throw new Error(`Unadopted Lane is dirty and retained at ${entry.path}.`);
|
|
1375
|
+
}
|
|
1376
|
+
completed.push({ path: entry.path, result });
|
|
1376
1377
|
}
|
|
1377
|
-
|
|
1378
|
-
|
|
1378
|
+
target = root;
|
|
1379
|
+
await removeWorkspaceView(root);
|
|
1380
|
+
return completed.some(({ result }) => result === "removed") ? "removed" : "missing";
|
|
1379
1381
|
}
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
const result = await this.git.removeWorktree({
|
|
1386
|
-
repositoryPath: this.#taskRepositoryPath(task.id, project.id),
|
|
1387
|
-
container: dirname(entry.path),
|
|
1388
|
-
directory: entry.directory,
|
|
1389
|
-
taskSegment,
|
|
1390
|
-
roleName: managedWorktreeName(workspace.owner),
|
|
1391
|
-
deleteBranch: true
|
|
1392
|
-
});
|
|
1393
|
-
if (result === "dirty")
|
|
1394
|
-
return "dirty";
|
|
1395
|
-
removed ||= result === "removed";
|
|
1382
|
+
catch (error) {
|
|
1383
|
+
const result = { completed, failedPath: target,
|
|
1384
|
+
remaining: writable.map(({ path }) => path).filter(path => !completed.some(done => done.path === path)) };
|
|
1385
|
+
throw Object.assign(new Error(`Unadopted Lane cleanup failed: ${errorText(error)}. Effects: ${JSON.stringify(result)}. `
|
|
1386
|
+
+ "Failed-command effects are unknown; inspect the exact target before continuing.", { cause: error }), { result });
|
|
1396
1387
|
}
|
|
1397
|
-
await removeWorkspaceView(workspace.root);
|
|
1398
|
-
return removed ? "removed" : "missing";
|
|
1399
1388
|
}
|
|
1400
1389
|
async cleanupExecutionLaneWorkspacesForWorkItem(taskId, workItemId) {
|
|
1401
1390
|
let result = "missing";
|
|
@@ -1754,7 +1743,7 @@ export class FileTaskWorkspacePreparer {
|
|
|
1754
1743
|
});
|
|
1755
1744
|
}
|
|
1756
1745
|
catch (error) {
|
|
1757
|
-
await this.#discardUnadoptedEntries(task, taskSegment, prepared, this.#reviewWorktreeName(round), existing === null, new Set([...retained.values()].map(({ entry }) => entry.path)));
|
|
1746
|
+
await this.#discardUnadoptedEntries(task, taskSegment, prepared, this.#reviewWorktreeName(round), existing === null, new Set([...retained.values()].map(({ entry }) => entry.path)), error);
|
|
1758
1747
|
throw error;
|
|
1759
1748
|
}
|
|
1760
1749
|
}
|
|
@@ -2243,28 +2232,43 @@ export class FileTaskWorkspacePreparer {
|
|
|
2243
2232
|
return this.store.getConfig().defaultWorkspace ?? process.cwd();
|
|
2244
2233
|
}
|
|
2245
2234
|
async #discardUnadoptedEntries(task, taskSegment, prepared, roleName, deleteBranch = false, adoptedPaths = new Set(this.store.listManagedWorkspaces(task.id)
|
|
2246
|
-
.flatMap((workspace) => workspace.entries.map(({ path }) => path)))) {
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2235
|
+
.flatMap((workspace) => workspace.entries.map(({ path }) => path))), originalError) {
|
|
2236
|
+
const candidates = prepared.filter(({ entry }) => entry.access === "write" && !adoptedPaths.has(entry.path));
|
|
2237
|
+
const completed = [];
|
|
2238
|
+
for (const { project, entry } of candidates) {
|
|
2239
|
+
try {
|
|
2240
|
+
const removal = roleName === MAIN_WORKTREE
|
|
2241
|
+
? await this.git.removeTaskClone({
|
|
2242
|
+
path: entry.path, container: this.#taskWorkspaceRoot(task.id),
|
|
2243
|
+
directory: entry.directory, taskSegment, branch: entry.branch,
|
|
2244
|
+
expectedCommit: entry.baseCommit
|
|
2245
|
+
})
|
|
2246
|
+
: await this.git.removeWorktree({
|
|
2247
|
+
repositoryPath: this.#taskRepositoryPath(task.id, project.id),
|
|
2248
|
+
container: dirname(entry.path),
|
|
2249
|
+
directory: entry.directory,
|
|
2250
|
+
taskSegment,
|
|
2251
|
+
roleName,
|
|
2252
|
+
...(deleteBranch ? { deleteBranch: true } : {})
|
|
2253
|
+
});
|
|
2250
2254
|
if (removal === "dirty") {
|
|
2251
|
-
throw new Error(`Unadopted
|
|
2255
|
+
throw new Error(`Unadopted workspace is dirty and was retained at ${entry.path}.`);
|
|
2252
2256
|
}
|
|
2257
|
+
completed.push({ path: entry.path, result: removal });
|
|
2253
2258
|
this.#resourceRegistrar().markPathsDeleted([entry.path]);
|
|
2254
|
-
continue;
|
|
2255
2259
|
}
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
...(deleteBranch ? { deleteBranch: true } : {})
|
|
2263
|
-
});
|
|
2264
|
-
if (removal === "dirty") {
|
|
2265
|
-
throw new Error(`Unadopted managed worktree is dirty and was retained at ${entry.path}; inspect it and retry.`);
|
|
2260
|
+
catch (cleanupError) {
|
|
2261
|
+
const remaining = candidates.map(({ entry }) => entry.path)
|
|
2262
|
+
.filter(path => !completed.some(done => done.path === path));
|
|
2263
|
+
const result = { completed, failedPath: entry.path, remaining };
|
|
2264
|
+
throw Object.assign(new AggregateError([originalError, cleanupError], `Workspace preparation failed: ${errorText(originalError)}. Compensation failed: ${errorText(cleanupError)}. `
|
|
2265
|
+
+ `Effects: ${JSON.stringify(result)}. Remaining paths may be partially changed; inspect before retrying.`), { result });
|
|
2266
2266
|
}
|
|
2267
|
-
|
|
2267
|
+
}
|
|
2268
|
+
if (originalError instanceof Error && completed.length > 0) {
|
|
2269
|
+
// Preserve the original error class (notably a safe CAS retry), while
|
|
2270
|
+
// making completed compensation visible to the caller's existing report.
|
|
2271
|
+
originalError.message += ` Workspace compensation: ${JSON.stringify(completed)}.`;
|
|
2268
2272
|
}
|
|
2269
2273
|
}
|
|
2270
2274
|
#taskRepositoryPath(taskId, projectId) {
|
|
@@ -2653,3 +2657,6 @@ function errorCode(error) {
|
|
|
2653
2657
|
? String(error.code)
|
|
2654
2658
|
: undefined;
|
|
2655
2659
|
}
|
|
2660
|
+
function errorText(error) {
|
|
2661
|
+
return error instanceof Error ? error.message : String(error);
|
|
2662
|
+
}
|
|
@@ -91,7 +91,7 @@ export async function scanLiveReferences(input) {
|
|
|
91
91
|
diagnostics.push(...tmuxResult.diagnostics);
|
|
92
92
|
// 3. Controller discovery: a running Controller protects only its own
|
|
93
93
|
// discovery record. Its cwd and open files are covered by the /proc
|
|
94
|
-
// scan above, so a live Controller does not blanket-protect
|
|
94
|
+
// scan above, so a live Controller does not blanket-protect unattributed
|
|
95
95
|
// deployments and worktrees that no descriptor references — automatic
|
|
96
96
|
// GC (which runs inside the Controller) would otherwise be a no-op.
|
|
97
97
|
const discovery = readControllerDiscovery(home);
|
|
@@ -43,7 +43,7 @@ export function listResourceRecords(state) {
|
|
|
43
43
|
return Object.values(state.records);
|
|
44
44
|
}
|
|
45
45
|
export function parseResourceRegistryState(value) {
|
|
46
|
-
if (
|
|
46
|
+
if (!isRecord(value)) {
|
|
47
47
|
throw new Error("Resource registry root is not an object.");
|
|
48
48
|
}
|
|
49
49
|
const record = value;
|
|
@@ -51,15 +51,12 @@ export function parseResourceRegistryState(value) {
|
|
|
51
51
|
throw new Error(`Resource registry schemaVersion is ${String(record.schemaVersion)}; `
|
|
52
52
|
+ `expected ${RESOURCE_REGISTRY_SCHEMA_VERSION}.`);
|
|
53
53
|
}
|
|
54
|
-
if (
|
|
54
|
+
if (!isRecord(record.records)) {
|
|
55
55
|
throw new Error("Resource registry records is not an object.");
|
|
56
56
|
}
|
|
57
57
|
const records = {};
|
|
58
58
|
for (const [key, entry] of Object.entries(record.records)) {
|
|
59
|
-
const parsed = parseResourceRecord(entry);
|
|
60
|
-
if (parsed === undefined) {
|
|
61
|
-
throw new Error(`Resource registry record ${key} is malformed.`);
|
|
62
|
-
}
|
|
59
|
+
const parsed = parseResourceRecord(entry, key);
|
|
63
60
|
if (parsed.id !== key) {
|
|
64
61
|
throw new Error(`Resource registry record key ${key} does not match id ${parsed.id}.`);
|
|
65
62
|
}
|
|
@@ -70,47 +67,96 @@ export function parseResourceRegistryState(value) {
|
|
|
70
67
|
records: Object.freeze(records)
|
|
71
68
|
});
|
|
72
69
|
}
|
|
73
|
-
function parseResourceRecord(value) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
70
|
+
function parseResourceRecord(value, key) {
|
|
71
|
+
const invalid = (field) => {
|
|
72
|
+
throw new Error(`Resource registry record ${key} is malformed at ${field}; stored evidence was not repaired.`);
|
|
73
|
+
};
|
|
74
|
+
const object = (value, field) => isRecord(value) ? value : invalid(field);
|
|
75
|
+
const text = (value, field) => {
|
|
76
|
+
if (typeof value !== "string" || value.trim().length === 0)
|
|
77
|
+
invalid(field);
|
|
78
|
+
};
|
|
79
|
+
const timestamp = (value, field) => {
|
|
80
|
+
text(value, field);
|
|
81
|
+
if (!Number.isFinite(Date.parse(value)))
|
|
82
|
+
invalid(field);
|
|
83
|
+
};
|
|
84
|
+
const member = (value, choices, field) => {
|
|
85
|
+
if (typeof value !== "string" || !choices.includes(value))
|
|
86
|
+
invalid(field);
|
|
87
|
+
};
|
|
88
|
+
const optionalText = (record, fields, prefix = "") => {
|
|
89
|
+
for (const field of fields) {
|
|
90
|
+
if (record[field] !== undefined)
|
|
91
|
+
text(record[field], `${prefix}${field}`);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
const record = object(value, "record");
|
|
77
95
|
if (record.schemaVersion !== RESOURCE_REGISTRY_SCHEMA_VERSION)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
96
|
+
invalid("schemaVersion");
|
|
97
|
+
text(record.id, "id");
|
|
98
|
+
text(record.path, "path");
|
|
99
|
+
timestamp(record.updatedAt, "updatedAt");
|
|
100
|
+
member(record.kind, ["worktree", "deployment", "runtime-artifact"], "kind");
|
|
101
|
+
member(record.disposition, ["active", "releasable", "quarantined", "deleted",
|
|
102
|
+
"retained-dirty", "retained-unowned", "retained-unproven", "cleanup-failed"], "disposition");
|
|
103
|
+
member(record.cleanliness, ["clean", "dirty", "unknown", "n/a"], "cleanliness");
|
|
104
|
+
if (!Array.isArray(record.activeRefs))
|
|
105
|
+
invalid("activeRefs");
|
|
106
|
+
record.activeRefs.forEach((ref, index) => text(ref, `activeRefs[${index}]`));
|
|
107
|
+
const owner = object(record.owner, "owner");
|
|
108
|
+
text(owner.home, "owner.home");
|
|
109
|
+
member(owner.basis, ["durable-record", "marker", "descriptor", "naming-convention", "unattributed"], "owner.basis");
|
|
110
|
+
optionalText(owner, ["projectId", "taskId", "workItemId", "reviewRoundId", "integrationAttemptId"], "owner.");
|
|
111
|
+
for (const field of ["createdAt", "lastReferencedAt"]) {
|
|
112
|
+
if (record[field] !== undefined)
|
|
113
|
+
timestamp(record[field], field);
|
|
83
114
|
}
|
|
84
|
-
if (
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
return undefined;
|
|
88
|
-
const owner = record.owner;
|
|
89
|
-
if (typeof owner.home !== "string" || typeof owner.basis !== "string") {
|
|
90
|
-
return undefined;
|
|
115
|
+
if (record.sizeBytes !== undefined
|
|
116
|
+
&& (typeof record.sizeBytes !== "number" || !Number.isFinite(record.sizeBytes) || record.sizeBytes < 0)) {
|
|
117
|
+
invalid("sizeBytes");
|
|
91
118
|
}
|
|
119
|
+
if (record.blocker !== undefined && typeof record.blocker !== "string")
|
|
120
|
+
invalid("blocker");
|
|
121
|
+
if (record.git !== undefined) {
|
|
122
|
+
const git = object(record.git, "git");
|
|
123
|
+
text(git.repositoryPath, "git.repositoryPath");
|
|
124
|
+
optionalText(git, ["commonDir", "branch", "head"], "git.");
|
|
125
|
+
}
|
|
126
|
+
if (record.quarantine !== undefined) {
|
|
127
|
+
const quarantine = object(record.quarantine, "quarantine");
|
|
128
|
+
text(quarantine.path, "quarantine.path");
|
|
129
|
+
text(quarantine.originalPath, "quarantine.originalPath");
|
|
130
|
+
timestamp(quarantine.movedAt, "quarantine.movedAt");
|
|
131
|
+
member(quarantine.method, ["move", "git-worktree-remove"], "quarantine.method");
|
|
132
|
+
if (quarantine.gitRestore !== undefined) {
|
|
133
|
+
const restore = object(quarantine.gitRestore, "quarantine.gitRestore");
|
|
134
|
+
text(restore.repositoryPath, "quarantine.gitRestore.repositoryPath");
|
|
135
|
+
optionalText(restore, ["branch", "head"], "quarantine.gitRestore.");
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (record.cleanupReceipt !== undefined) {
|
|
139
|
+
const receipt = object(record.cleanupReceipt, "cleanupReceipt");
|
|
140
|
+
timestamp(receipt.removedAt, "cleanupReceipt.removedAt");
|
|
141
|
+
member(receipt.method, ["git-worktree-remove", "quarantine-purge", "runtime-cleanup"], "cleanupReceipt.method");
|
|
142
|
+
}
|
|
143
|
+
// Validation enforces the existing persisted contract, without defaults,
|
|
144
|
+
// filtering, or a second historical reader. Constructors own new values.
|
|
145
|
+
const parsed = record;
|
|
92
146
|
return Object.freeze({
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
...(
|
|
104
|
-
cleanliness: (record.cleanliness ?? "unknown"),
|
|
105
|
-
activeRefs: Array.isArray(record.activeRefs)
|
|
106
|
-
? Object.freeze(record.activeRefs.filter((ref) => typeof ref === "string"))
|
|
107
|
-
: Object.freeze([]),
|
|
108
|
-
disposition: record.disposition,
|
|
109
|
-
...(typeof record.blocker === "string" ? { blocker: record.blocker } : {}),
|
|
110
|
-
...(record.quarantine === undefined ? {} : { quarantine: record.quarantine }),
|
|
111
|
-
...(record.cleanupReceipt === undefined
|
|
112
|
-
? {}
|
|
113
|
-
: { cleanupReceipt: record.cleanupReceipt }),
|
|
114
|
-
updatedAt: record.updatedAt
|
|
147
|
+
...parsed,
|
|
148
|
+
owner: Object.freeze({ ...parsed.owner }),
|
|
149
|
+
activeRefs: Object.freeze([...parsed.activeRefs]),
|
|
150
|
+
...(parsed.git === undefined ? {} : { git: Object.freeze({ ...parsed.git }) }),
|
|
151
|
+
...(parsed.quarantine === undefined ? {} : { quarantine: Object.freeze({
|
|
152
|
+
...parsed.quarantine,
|
|
153
|
+
...(parsed.quarantine.gitRestore === undefined ? {} : {
|
|
154
|
+
gitRestore: Object.freeze({ ...parsed.quarantine.gitRestore })
|
|
155
|
+
})
|
|
156
|
+
}) }),
|
|
157
|
+
...(parsed.cleanupReceipt === undefined ? {} : { cleanupReceipt: Object.freeze({ ...parsed.cleanupReceipt }) })
|
|
115
158
|
});
|
|
116
159
|
}
|
|
160
|
+
function isRecord(value) {
|
|
161
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
162
|
+
}
|
|
@@ -14,7 +14,7 @@ import { existsSync } from "node:fs";
|
|
|
14
14
|
import { join } from "node:path";
|
|
15
15
|
import { isDeepStrictEqual } from "node:util";
|
|
16
16
|
import Database from "better-sqlite3";
|
|
17
|
-
import {
|
|
17
|
+
import { validateSqliteSchema } from "../storage/sqliteSchema.js";
|
|
18
18
|
import { emptyResourceRegistry, parseResourceRegistryState } from "./resourceRegistry.js";
|
|
19
19
|
import { RESOURCE_REGISTRY_SCHEMA_VERSION } from "./resourceTypes.js";
|
|
20
20
|
export const SQLITE_RESOURCE_REGISTRY_TABLE = "resource_registry";
|
|
@@ -31,10 +31,10 @@ export class SqliteResourceRegistry {
|
|
|
31
31
|
}
|
|
32
32
|
this.#db = new Database(dbPath);
|
|
33
33
|
try {
|
|
34
|
+
validateSqliteSchema(this.#db);
|
|
34
35
|
this.#db.pragma("journal_mode = WAL");
|
|
35
36
|
this.#db.pragma("foreign_keys = ON");
|
|
36
37
|
this.#db.pragma("busy_timeout = 5000");
|
|
37
|
-
migrateSqliteSchema(this.#db, { mode: "validate" });
|
|
38
38
|
}
|
|
39
39
|
catch (error) {
|
|
40
40
|
this.#db.close();
|
|
@@ -42,7 +42,7 @@ export class SqliteResourceRegistry {
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
load() {
|
|
45
|
-
const rows = this.#db.prepare(`SELECT payload FROM ${SQLITE_RESOURCE_REGISTRY_TABLE}`).all();
|
|
45
|
+
const rows = this.#db.prepare(`SELECT id, payload FROM ${SQLITE_RESOURCE_REGISTRY_TABLE}`).all();
|
|
46
46
|
if (rows.length === 0)
|
|
47
47
|
return emptyResourceRegistry();
|
|
48
48
|
const records = {};
|
|
@@ -52,14 +52,12 @@ export class SqliteResourceRegistry {
|
|
|
52
52
|
parsed = JSON.parse(row.payload);
|
|
53
53
|
}
|
|
54
54
|
catch (error) {
|
|
55
|
-
throw new Error(`SQLite resource registry has a corrupt payload: `
|
|
55
|
+
throw new Error(`SQLite resource registry record ${row.id} has a corrupt payload: `
|
|
56
56
|
+ `${error instanceof Error ? error.message : "unknown error"}.`, { cause: error });
|
|
57
57
|
}
|
|
58
58
|
const state = parseResourceRegistryState({
|
|
59
59
|
schemaVersion: RESOURCE_REGISTRY_SCHEMA_VERSION,
|
|
60
|
-
records: { [
|
|
61
|
-
? String(parsed.id)
|
|
62
|
-
: ""]: parsed }
|
|
60
|
+
records: { [row.id]: parsed }
|
|
63
61
|
});
|
|
64
62
|
Object.assign(records, state.records);
|
|
65
63
|
}
|
|
@@ -5,7 +5,7 @@ import { validateManagedWorkspace } from "../worktree/managedWorkspace.js";
|
|
|
5
5
|
import { assertExecutionGroupTransition, retryFailedExecutionLanes, validateExecutionGroup, validateReviewExecutionAssignment } from "../execution/workItemExecution.js";
|
|
6
6
|
export function createReviewRound(id, taskId, workItemId, candidateId, reviewerRoleName, requestedBy, reviewBaseCommit, now, executionGroup) {
|
|
7
7
|
return validateReviewRound({
|
|
8
|
-
schemaVersion:
|
|
8
|
+
schemaVersion: 1,
|
|
9
9
|
id: requireIdentity(id, "ReviewRound id"),
|
|
10
10
|
taskId: requireIdentity(taskId, "Task id"),
|
|
11
11
|
workItemId: requireIdentity(workItemId, "Work Item id"),
|
|
@@ -22,7 +22,7 @@ export function createReviewRound(id, taskId, workItemId, candidateId, reviewerR
|
|
|
22
22
|
export function createTaskReviewRound(id, taskId, reviewerRoleName, requestedBy, taskCandidate, now, taskFinalReviewContract, executionGroup) {
|
|
23
23
|
const candidate = validateTaskReviewCandidate(taskCandidate);
|
|
24
24
|
return validateReviewRound({
|
|
25
|
-
schemaVersion:
|
|
25
|
+
schemaVersion: 1,
|
|
26
26
|
id: requireIdentity(id, "ReviewRound id"),
|
|
27
27
|
taskId: requireIdentity(taskId, "Task id"),
|
|
28
28
|
reviewerRoleName: requireIdentity(reviewerRoleName, "Reviewer Role"),
|
|
@@ -48,7 +48,7 @@ export function createTaskReviewRound(id, taskId, reviewerRoleName, requestedBy,
|
|
|
48
48
|
export function createTaskDeltaReviewRound(id, taskId, reviewerRoleName, requestedBy, taskCandidate, deltaRecheck, now, taskFinalReviewContract, executionGroup) {
|
|
49
49
|
const candidate = validateTaskReviewCandidate(taskCandidate);
|
|
50
50
|
return validateReviewRound({
|
|
51
|
-
schemaVersion:
|
|
51
|
+
schemaVersion: 1,
|
|
52
52
|
id: requireIdentity(id, "ReviewRound id"),
|
|
53
53
|
taskId: requireIdentity(taskId, "Task id"),
|
|
54
54
|
reviewerRoleName: requireIdentity(reviewerRoleName, "Reviewer Role"),
|
|
@@ -285,8 +285,8 @@ export function validateReviewRound(round) {
|
|
|
285
285
|
"createdAt",
|
|
286
286
|
"endedAt"
|
|
287
287
|
], "ReviewRound");
|
|
288
|
-
if (round.schemaVersion !==
|
|
289
|
-
throw new Error("ReviewRound must use schemaVersion
|
|
288
|
+
if (round.schemaVersion !== 1)
|
|
289
|
+
throw new Error("ReviewRound must use schemaVersion 1.");
|
|
290
290
|
validateTaskRecordReference({ taskId: round.taskId, localId: round.id }, "reviewRound");
|
|
291
291
|
requireIdentity(round.reviewerRoleName, "Reviewer Role");
|
|
292
292
|
requireCommit(round.reviewBaseCommit, "Review base commit");
|
package/dist/role/role.js
CHANGED
|
@@ -30,14 +30,14 @@ export function createRole(taskId, name, bindings, activeAgentId, workspace, now
|
|
|
30
30
|
const owner = createRoleOwner(name, bindings, activeAgentId, workspace, now, profile, defaultAccess);
|
|
31
31
|
return validateTaskRole({
|
|
32
32
|
...owner,
|
|
33
|
-
schemaVersion:
|
|
33
|
+
schemaVersion: 1,
|
|
34
34
|
taskId: requireSafeIdentity(taskId, "Task id")
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
37
|
export function createGlobalRole(name, bindings, activeAgentId, workspace, now, profile = {}, defaultAccess = "write") {
|
|
38
38
|
return validateGlobalRole({
|
|
39
39
|
...createRoleOwner(name, bindings, activeAgentId, workspace, now, profile, defaultAccess),
|
|
40
|
-
schemaVersion:
|
|
40
|
+
schemaVersion: 1
|
|
41
41
|
});
|
|
42
42
|
}
|
|
43
43
|
export function copyGlobalRoleToTaskRole(globalRole, taskId, now, name = globalRole.name) {
|
|
@@ -45,7 +45,7 @@ export function copyGlobalRoleToTaskRole(globalRole, taskId, now, name = globalR
|
|
|
45
45
|
const timestamp = now.toISOString();
|
|
46
46
|
return validateTaskRole({
|
|
47
47
|
...cloneProfile(globalRole),
|
|
48
|
-
schemaVersion:
|
|
48
|
+
schemaVersion: 1,
|
|
49
49
|
launchRevision: 1,
|
|
50
50
|
defaultAccess: globalRole.defaultAccess,
|
|
51
51
|
taskId: requireSafeIdentity(taskId, "Task id"),
|
|
@@ -189,6 +189,8 @@ export function unbindRoleAgent(role, sessions, agentId, now) {
|
|
|
189
189
|
return { role: updatedRole, sessions: updatedSessions };
|
|
190
190
|
}
|
|
191
191
|
export function validateGlobalRole(role) {
|
|
192
|
+
if (Object.hasOwn(role, "taskId"))
|
|
193
|
+
throw new Error("Global Role cannot carry a Task identity.");
|
|
192
194
|
return validateRoleOwner(role);
|
|
193
195
|
}
|
|
194
196
|
export function validateTaskRole(role) {
|
|
@@ -218,8 +220,7 @@ function createRoleOwner(name, bindings, activeAgentId, workspace, now, profile,
|
|
|
218
220
|
};
|
|
219
221
|
}
|
|
220
222
|
function validateRoleOwner(role) {
|
|
221
|
-
|
|
222
|
-
if (role.schemaVersion !== expectedSchemaVersion) {
|
|
223
|
+
if (role.schemaVersion !== 1) {
|
|
223
224
|
throw new Error("Role schema version is invalid.");
|
|
224
225
|
}
|
|
225
226
|
if (!Number.isSafeInteger(role.launchRevision) || role.launchRevision < 1) {
|
|
@@ -256,9 +257,7 @@ function validateRoleOwner(role) {
|
|
|
256
257
|
function validateRoleAgentBinding(binding) {
|
|
257
258
|
const agentId = requireSafeIdentity(binding.agentId, "Role Agent id");
|
|
258
259
|
const adapterId = requireSupportedAdapterId(binding.adapterId);
|
|
259
|
-
//
|
|
260
|
-
// a corrupt record rather than an old one. Defaulting it would invent a
|
|
261
|
-
// product identity for data that never lost one.
|
|
260
|
+
// The current contract requires an explicit execution component.
|
|
262
261
|
if (binding.component === undefined) {
|
|
263
262
|
throw new Error(`Role Agent binding is missing its execution component: ${agentId}.`);
|
|
264
263
|
}
|
|
@@ -126,9 +126,8 @@ export function acpPromptRequest(sessionId, text) {
|
|
|
126
126
|
/**
|
|
127
127
|
* Read a `configOptions` array from a session setup or set-option result.
|
|
128
128
|
*
|
|
129
|
-
* Returns undefined when the field is absent
|
|
130
|
-
*
|
|
131
|
-
* answering with an empty list, which offers nothing configurable. Callers must
|
|
129
|
+
* Returns undefined when the field is absent: configuration support is then
|
|
130
|
+
* unobserved. An explicit empty list instead offers nothing configurable. Callers must
|
|
132
131
|
* be able to tell those apart, so the absence is not flattened to `[]`.
|
|
133
132
|
*/
|
|
134
133
|
export function readAcpConfigOptions(value) {
|
|
@@ -5,6 +5,7 @@ import { ACP_CONFIGURATION_ORDER, acpRunConfigurationOptions, confirmAcpConfigur
|
|
|
5
5
|
import { handshakeObservationFrom, unknownAgentRunConfiguration } from "./agentRunConfiguration.js";
|
|
6
6
|
import { JsonLineChannel, terminateProcessGroup } from "./jsonLineChannel.js";
|
|
7
7
|
import { ProviderDeliveryUnknownError, ProviderTurnRejectedError } from "./providerErrors.js";
|
|
8
|
+
import { providerDeliveryFailureFrom } from "./agentError.js";
|
|
8
9
|
/**
|
|
9
10
|
* One Agent Client Protocol Session over an Agent's stdio.
|
|
10
11
|
*
|
|
@@ -86,9 +87,24 @@ export class AcpStructuredProviderSession {
|
|
|
86
87
|
this.mirror = mirror;
|
|
87
88
|
}
|
|
88
89
|
static async open(input) {
|
|
89
|
-
|
|
90
|
+
let receivingAttemptId;
|
|
91
|
+
const channel = new JsonLineChannel(input.child, input.mirror, error => {
|
|
92
|
+
// Before session/new has answered, the opening caller owns the failure.
|
|
93
|
+
if (!session.#sessionId)
|
|
94
|
+
return;
|
|
95
|
+
input.onDiagnostic?.({
|
|
96
|
+
nativeSessionId: session.#sessionId,
|
|
97
|
+
...((receivingAttemptId ?? session.#activeAttemptId) === undefined
|
|
98
|
+
? {} : { attemptId: receivingAttemptId ?? session.#activeAttemptId }),
|
|
99
|
+
failure: providerDeliveryFailureFrom(error, { phase: "turn-reconcile", inputDisposition: "unknown" })
|
|
100
|
+
});
|
|
101
|
+
});
|
|
90
102
|
const session = new AcpStructuredProviderSession(input.child, input.exit, input.processInstanceId, channel, input.onTerminal, input.mirror);
|
|
91
|
-
channel.onMessage((message) =>
|
|
103
|
+
channel.onMessage((message) => {
|
|
104
|
+
receivingAttemptId = session.#activeAttemptId;
|
|
105
|
+
session.#receive(message);
|
|
106
|
+
receivingAttemptId = undefined;
|
|
107
|
+
});
|
|
92
108
|
channel.onClose((error) => session.#fail(error));
|
|
93
109
|
const negotiated = readAcpInitializeResult(await session.#request("initialize", acpInitializeRequest(input.clientVersion)));
|
|
94
110
|
session.#negotiated = negotiated;
|
|
@@ -463,7 +479,7 @@ export class AcpStructuredProviderSession {
|
|
|
463
479
|
if (message.id === undefined)
|
|
464
480
|
this.#notification(method, message.params);
|
|
465
481
|
else
|
|
466
|
-
void this.#serve(method, message);
|
|
482
|
+
void this.#serve(method, message).catch(error => this.#fail(error));
|
|
467
483
|
}
|
|
468
484
|
#response(message) {
|
|
469
485
|
const id = typeof message.id === "number" ? message.id : undefined;
|
|
@@ -638,8 +654,8 @@ export class AcpStructuredProviderSession {
|
|
|
638
654
|
...(error === undefined ? { result: result ?? {} } : { error })
|
|
639
655
|
});
|
|
640
656
|
}
|
|
641
|
-
catch {
|
|
642
|
-
|
|
657
|
+
catch (error) {
|
|
658
|
+
this.#fail(error instanceof Error ? error : new Error(String(error)));
|
|
643
659
|
}
|
|
644
660
|
}
|
|
645
661
|
#fail(error) {
|
|
@@ -40,7 +40,7 @@ function observation(input, mapped) {
|
|
|
40
40
|
const eventId = hookEventId(input, mapped, requestOccurrenceId);
|
|
41
41
|
const fence = { ...input.fence, ...mapped.fence };
|
|
42
42
|
return createRuntimeObservation({
|
|
43
|
-
schemaVersion:
|
|
43
|
+
schemaVersion: 1,
|
|
44
44
|
eventId,
|
|
45
45
|
semanticKey: requestOccurrenceId === undefined
|
|
46
46
|
? runtimeObservationSemanticKey({
|
|
@@ -46,6 +46,7 @@ export function createAgentEndpointFactory(start = startStructuredProviderSessio
|
|
|
46
46
|
onStarted: (value) => emit({ type: "started", value }),
|
|
47
47
|
onTerminal: (value) => emit({ type: "terminal", value }),
|
|
48
48
|
onInput: (value) => emit({ type: "input", value }),
|
|
49
|
+
onDiagnostic: (value) => emit({ type: "diagnostic", value }),
|
|
49
50
|
onGoal: (value) => emit({ type: "goal", value })
|
|
50
51
|
});
|
|
51
52
|
endpoint = new BuiltinAgentEndpoint(opened.session, configuration, opened.recoveredTerminal);
|
|
@@ -193,7 +194,9 @@ class BuiltinAgentEndpoint {
|
|
|
193
194
|
});
|
|
194
195
|
}
|
|
195
196
|
observe(value) {
|
|
196
|
-
if (value.type
|
|
197
|
+
if (value.type === "diagnostic" && value.value.nativeSessionId !== this.nativeSessionId)
|
|
198
|
+
return;
|
|
199
|
+
if (value.type !== "goal" && value.type !== "diagnostic"
|
|
197
200
|
&& (value.value.nativeSessionId !== this.nativeSessionId || value.value.conversationId !== this.conversationId))
|
|
198
201
|
return;
|
|
199
202
|
if (value.type === "goal" && value.value !== null && value.value.conversationId !== this.conversationId)
|