@zq-silk/yui 0.6.2 → 0.6.4
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 +28 -4
- package/README.md +60 -97
- package/dist/agent/argumentPolicy.js +1 -1
- package/dist/agent/managedRuntimeEnvironment.js +1 -0
- package/dist/cli/commandCatalog.js +19 -9
- package/dist/cli/interactionPolicy.js +4 -2
- package/dist/cli.js +77 -32
- package/dist/commands/taskCommands.js +46 -11
- package/dist/commands/taskContextCommand.js +1 -1
- package/dist/commands/taskRoleRuntimeStatus.js +170 -10
- package/dist/controller/agentRuntimeObserver.js +210 -0
- package/dist/controller/clientRuntime.js +3 -21
- package/dist/controller/controller.js +47 -7
- package/dist/controller/fileSchedulerStoreAdapter.js +522 -388
- package/dist/controller/runtime.js +9 -3
- package/dist/controller/runtimeEventInbox.js +49 -295
- package/dist/controller/runtimeEventProcessor.js +184 -321
- package/dist/controller/runtimeHookRunFence.js +226 -0
- package/dist/controller/runtimeLaunchCoordinator.js +91 -26
- package/dist/controller/runtimeObservationHook.js +112 -0
- package/dist/core/controllerServer.js +5 -0
- package/dist/executor/agentAdapter.js +18 -3
- package/dist/executor/fileRoleLaunchPlanner.js +64 -15
- package/dist/executor/managedClaudeRunner.js +121 -0
- package/dist/observability/executionAudit.js +6 -3
- package/dist/repository/taskWorkspacePreparer.js +1 -4
- package/dist/run/providerRetryConfig.js +8 -3
- package/dist/runtime/agentDriver.js +229 -0
- package/dist/runtime/agentDriverObservation.js +57 -0
- package/dist/runtime/builtinAgentDrivers.js +235 -0
- package/dist/runtime/builtinTranscriptObserver.js +290 -0
- package/dist/runtime/builtinTranscriptUsage.js +97 -0
- package/dist/runtime/exactControlPlane.js +2 -2
- package/dist/runtime/index.js +1 -1
- package/dist/runtime/ports.js +12 -1
- package/dist/runtime/runtimeObservation.js +297 -0
- package/dist/runtime/runtimeProjection.js +277 -0
- package/dist/runtime/sessionTerminationGuard.js +78 -22
- package/dist/runtime/tmuxAdapters.js +35 -0
- package/dist/scheduler/activeRoleRunDelivery.js +28 -13
- package/dist/scheduler/leaderWakeupProcessor.js +21 -2
- package/dist/scheduler/roleRunLiveness.js +2 -2
- package/dist/scheduler/roleRunStall.js +62 -114
- package/dist/storage/migration/productionRegistry.js +85 -0
- package/dist/storage/sqliteStore.js +3 -3
- package/dist/storage/storageVersions.js +1 -1
- package/dist/storage/upgrade/sqliteRecordMigrationTarget.js +2 -1
- package/dist/storage/upgrade/sqliteStateMigration.js +123 -0
- package/dist/telemetry/sqliteTelemetryStore.js +0 -28
- package/dist/telemetry/telemetryCompaction.js +1 -0
- package/dist/telemetry/telemetryConfig.js +4 -5
- package/dist/tmux/tmuxManager.js +136 -22
- package/dist/web/assets/client/view.js +1 -1
- package/dist/web/tmuxWebTerminal.js +17 -12
- package/dist/web/webSnapshot.js +1 -1
- package/dist/worktree/managedWorkspace.js +14 -0
- package/i18n/README.zh-CN.md +12 -7
- package/package.json +1 -1
- package/dist/controller/claudeLifecycleHook.js +0 -203
- package/dist/controller/codexLifecycleHook.js +0 -108
- package/dist/controller/providerHookRunFence.js +0 -156
- package/dist/lifecycle/providerLifecycleMapping.js +0 -190
- package/dist/telemetry/telemetryRouter.js +0 -32
|
@@ -17,6 +17,7 @@ import { formatTaskRecordReference } from "../task/taskRecordReference.js";
|
|
|
17
17
|
import { parseDurableJobAcknowledgeParams, parseDurableJobCancelParams, parseDurableJobRefParams, parseDurableJobStartParams } from "./jobControl.js";
|
|
18
18
|
const DEFAULT_RECONCILIATION_INTERVAL_MS = reconciliationIntervalMilliseconds();
|
|
19
19
|
const DEFAULT_SIGNAL_WINDOW_MS = 100;
|
|
20
|
+
const DEFAULT_RUNTIME_OBSERVER_INTERVAL_MS = 1_000;
|
|
20
21
|
const DEFAULT_DELIVERY_RETRY_MS = 250;
|
|
21
22
|
const DEFAULT_DELIVERY_RETRY_LIMIT = 60;
|
|
22
23
|
const DEFAULT_TASK_ORCHESTRATION_RETRY_LIMIT = 2;
|
|
@@ -39,7 +40,7 @@ const ZERO_DRAIN_METRICS = Object.freeze({
|
|
|
39
40
|
* Runs one lean scheduler pass. Due native Turn completions are folded before
|
|
40
41
|
* liveness, so a valid Hook boundary fences destructive process reconciliation.
|
|
41
42
|
*/
|
|
42
|
-
export async function runControllerSchedulerPass(store, delivery, now, workspacePreparer, scope = { kind: "full" }, includeOperator = true, runtimeCleanupOutcomes = [], lifecycleHost, stallWindowMs = DEFAULT_STALL_WINDOW_MS,
|
|
43
|
+
export async function runControllerSchedulerPass(store, delivery, now, workspacePreparer, scope = { kind: "full" }, includeOperator = true, runtimeCleanupOutcomes = [], lifecycleHost, stallWindowMs = DEFAULT_STALL_WINDOW_MS, maintenanceFence, onMaintenanceFenceDefer) {
|
|
43
44
|
const compiledSelection = compileReconcileSelection(scope);
|
|
44
45
|
const selection = includeOperator
|
|
45
46
|
? compiledSelection
|
|
@@ -108,7 +109,7 @@ export async function runControllerSchedulerPass(store, delivery, now, workspace
|
|
|
108
109
|
const resourceEvidence = new Map();
|
|
109
110
|
const failedRunRefs = await reconcileExitedRoleRuns(store, delivery, now, roleSelection, unsettledRunRefs, liveStatuses, resourceEvidence);
|
|
110
111
|
await controlEventLoopTurn();
|
|
111
|
-
await reconcileStalledRoleRuns(store, delivery, now, roleSelection, stallWindowMs, liveStatuses, resourceEvidence
|
|
112
|
+
await reconcileStalledRoleRuns(store, delivery, now, roleSelection, stallWindowMs, liveStatuses, resourceEvidence);
|
|
112
113
|
await controlEventLoopTurn();
|
|
113
114
|
await reconcileDormantRuntimeOwners(store, delivery, lifecycleHost, scope, now);
|
|
114
115
|
const autoResolvedInputs = selection.full
|
|
@@ -690,9 +691,9 @@ export class FileTaskController {
|
|
|
690
691
|
#deliveryRetryLimit;
|
|
691
692
|
#taskOrchestrationRetryLimit;
|
|
692
693
|
#stallWindowMs;
|
|
693
|
-
/** Narrow-port fallback; FileSchedulerStoreAdapter durably records these keys. */
|
|
694
|
-
#resourceSuppressionKeys = new Set();
|
|
695
694
|
#runtimeEventProcessor;
|
|
695
|
+
#runtimeObserver;
|
|
696
|
+
#runtimeObserverIntervalMs;
|
|
696
697
|
#lifecycleHost;
|
|
697
698
|
#deliveryRetryAttempts = new Map();
|
|
698
699
|
#deliveryRetryTimers = new Map();
|
|
@@ -700,6 +701,7 @@ export class FileTaskController {
|
|
|
700
701
|
#passRetryAttempt = 0;
|
|
701
702
|
#timer;
|
|
702
703
|
#deadlineTimer;
|
|
704
|
+
#runtimeObserverTimer;
|
|
703
705
|
#signalScheduler;
|
|
704
706
|
#operatorSignalScheduler;
|
|
705
707
|
#configuration;
|
|
@@ -711,6 +713,7 @@ export class FileTaskController {
|
|
|
711
713
|
#jobSupervisor;
|
|
712
714
|
#current;
|
|
713
715
|
#operatorCurrent;
|
|
716
|
+
#runtimeObserverCurrent;
|
|
714
717
|
#pendingFull = false;
|
|
715
718
|
#pendingKeys = new Set();
|
|
716
719
|
#operatorStartupRetryArmed = false;
|
|
@@ -734,6 +737,8 @@ export class FileTaskController {
|
|
|
734
737
|
this.#taskOrchestrationRetryLimit = positiveInteger(options.taskOrchestrationRetryLimit, DEFAULT_TASK_ORCHESTRATION_RETRY_LIMIT, "Controller Task orchestration retry limit");
|
|
735
738
|
this.#stallWindowMs = positiveInteger(options.stallWindowMs, DEFAULT_STALL_WINDOW_MS, "Controller Run stall window");
|
|
736
739
|
this.#runtimeEventProcessor = options.runtimeEventProcessor;
|
|
740
|
+
this.#runtimeObserver = options.runtimeObserver;
|
|
741
|
+
this.#runtimeObserverIntervalMs = positiveInteger(options.runtimeObserverIntervalMs, DEFAULT_RUNTIME_OBSERVER_INTERVAL_MS, "Controller runtime observer interval");
|
|
737
742
|
this.#lifecycleHost = options.lifecycleHost;
|
|
738
743
|
this.#configuration = options.configuration;
|
|
739
744
|
this.#resourceReaper = options.resourceReaper;
|
|
@@ -820,6 +825,7 @@ export class FileTaskController {
|
|
|
820
825
|
if (this.#stopped)
|
|
821
826
|
throw new Error("Controller runtime is stopped.");
|
|
822
827
|
this.#requestBackgroundPump();
|
|
828
|
+
this.#requestRuntimeObservation();
|
|
823
829
|
// Arm the Operator lane once for work that was already pending when the
|
|
824
830
|
// Controller started. Subsequent main-lane passes signal it only when a
|
|
825
831
|
// new Operator batch is durably queued; an unchanged pending batch must
|
|
@@ -829,6 +835,12 @@ export class FileTaskController {
|
|
|
829
835
|
this.#requestBackgroundPump();
|
|
830
836
|
}, this.#intervalMs);
|
|
831
837
|
this.#timer.unref();
|
|
838
|
+
if (this.#runtimeObserver !== undefined) {
|
|
839
|
+
this.#runtimeObserverTimer = setInterval(() => {
|
|
840
|
+
this.#requestRuntimeObservation();
|
|
841
|
+
}, this.#runtimeObserverIntervalMs);
|
|
842
|
+
this.#runtimeObserverTimer.unref();
|
|
843
|
+
}
|
|
832
844
|
}
|
|
833
845
|
stop() {
|
|
834
846
|
this.#stopped = true;
|
|
@@ -842,6 +854,10 @@ export class FileTaskController {
|
|
|
842
854
|
clearInterval(this.#timer);
|
|
843
855
|
this.#timer = undefined;
|
|
844
856
|
}
|
|
857
|
+
if (this.#runtimeObserverTimer !== undefined) {
|
|
858
|
+
clearInterval(this.#runtimeObserverTimer);
|
|
859
|
+
this.#runtimeObserverTimer = undefined;
|
|
860
|
+
}
|
|
845
861
|
for (const timer of this.#deliveryRetryTimers.values())
|
|
846
862
|
clearTimeout(timer);
|
|
847
863
|
this.#deliveryRetryTimers.clear();
|
|
@@ -855,7 +871,8 @@ export class FileTaskController {
|
|
|
855
871
|
this.stop();
|
|
856
872
|
await Promise.allSettled([
|
|
857
873
|
this.#current ?? Promise.resolve(),
|
|
858
|
-
this.#operatorCurrent ?? Promise.resolve()
|
|
874
|
+
this.#operatorCurrent ?? Promise.resolve(),
|
|
875
|
+
this.#runtimeObserverCurrent ?? Promise.resolve()
|
|
859
876
|
]);
|
|
860
877
|
}
|
|
861
878
|
/** Adds one dirty Task key to the fixed-window wake queue and returns immediately. */
|
|
@@ -875,6 +892,21 @@ export class FileTaskController {
|
|
|
875
892
|
pump() {
|
|
876
893
|
return this.#requestPass({ kind: "full" });
|
|
877
894
|
}
|
|
895
|
+
#requestRuntimeObservation() {
|
|
896
|
+
if (this.#stopped || this.#runtimeObserver === undefined
|
|
897
|
+
|| this.#runtimeObserverCurrent !== undefined)
|
|
898
|
+
return;
|
|
899
|
+
const running = this.#runtimeObserver.sample(this.#now()).then((keys) => {
|
|
900
|
+
if (this.#stopped)
|
|
901
|
+
return;
|
|
902
|
+
for (const key of keys)
|
|
903
|
+
this.signal(key);
|
|
904
|
+
}).catch(this.#onError).finally(() => {
|
|
905
|
+
if (this.#runtimeObserverCurrent === running)
|
|
906
|
+
this.#runtimeObserverCurrent = undefined;
|
|
907
|
+
});
|
|
908
|
+
this.#runtimeObserverCurrent = running;
|
|
909
|
+
}
|
|
878
910
|
armOperatorStartupRetry() {
|
|
879
911
|
if (this.#stopped)
|
|
880
912
|
return;
|
|
@@ -954,7 +986,7 @@ export class FileTaskController {
|
|
|
954
986
|
// terminal job's Leader wakeup is enqueued in the same pass that
|
|
955
987
|
// processes Leader wakeups.
|
|
956
988
|
this.#jobSupervisor?.reconcile(this.#now());
|
|
957
|
-
result = await runControllerSchedulerPass(this.store, this.delivery, this.#now(), this.#workspacePreparer, scope, false, runtimeCleanupOutcomes, this.#lifecycleHost, this.#stallWindowMs, this.#
|
|
989
|
+
result = await runControllerSchedulerPass(this.store, this.delivery, this.#now(), this.#workspacePreparer, scope, false, runtimeCleanupOutcomes, this.#lifecycleHost, this.#stallWindowMs, this.#maintenanceFence, this.#onMaintenanceFenceDefer);
|
|
958
990
|
const secondRuntimeDrain = await this.#drainRuntimeEvents();
|
|
959
991
|
pendingRuntimeDrain = ((secondRuntimeDrain?.remainingEventCount ?? 0) > 0
|
|
960
992
|
&& ((firstRuntimeDrain?.acknowledgedEventIds.length ?? 0) > 0
|
|
@@ -1133,6 +1165,7 @@ export class FileTaskController {
|
|
|
1133
1165
|
#scheduleDeliveryRetries(result) {
|
|
1134
1166
|
const retry = new Map();
|
|
1135
1167
|
const settled = new Set();
|
|
1168
|
+
const writerBlocked = new Set();
|
|
1136
1169
|
const resignal = new Set();
|
|
1137
1170
|
for (const delivery of result.activeRunDeliveries) {
|
|
1138
1171
|
const key = `role:${encodeURIComponent(delivery.taskId)}/${encodeURIComponent(delivery.roleName)}`;
|
|
@@ -1140,6 +1173,8 @@ export class FileTaskController {
|
|
|
1140
1173
|
settled.add(key);
|
|
1141
1174
|
resignal.add(key);
|
|
1142
1175
|
}
|
|
1176
|
+
else if (delivery.reason === "writer-attached")
|
|
1177
|
+
writerBlocked.add(key);
|
|
1143
1178
|
else if (delivery.reason === "not-ready"
|
|
1144
1179
|
|| delivery.reason === "runtime-unavailable"
|
|
1145
1180
|
|| delivery.reason === "delivery-uncertain") {
|
|
@@ -1155,7 +1190,10 @@ export class FileTaskController {
|
|
|
1155
1190
|
}
|
|
1156
1191
|
for (const wakeup of result.wakeups) {
|
|
1157
1192
|
const key = `role:${encodeURIComponent(wakeup.taskId)}/leader`;
|
|
1158
|
-
if (wakeup.reason === "
|
|
1193
|
+
if (wakeup.reason === "writer-attached") {
|
|
1194
|
+
writerBlocked.add(key);
|
|
1195
|
+
}
|
|
1196
|
+
else if (wakeup.reason === "not-ready"
|
|
1159
1197
|
|| wakeup.reason === "delivery-uncertain") {
|
|
1160
1198
|
retry.set(key, { identity: wakeup.runId ?? key });
|
|
1161
1199
|
}
|
|
@@ -1183,6 +1221,8 @@ export class FileTaskController {
|
|
|
1183
1221
|
}
|
|
1184
1222
|
for (const key of settled)
|
|
1185
1223
|
this.#clearDeliveryRetry(key);
|
|
1224
|
+
for (const key of writerBlocked)
|
|
1225
|
+
this.#clearDeliveryRetry(key);
|
|
1186
1226
|
for (const key of resignal)
|
|
1187
1227
|
this.signal(key);
|
|
1188
1228
|
for (const [key, candidate] of retry) {
|