@zq-silk/yui 0.6.2 → 0.6.3

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.
Files changed (61) hide show
  1. package/ARCHITECTURE.md +28 -4
  2. package/README.md +62 -24
  3. package/dist/agent/argumentPolicy.js +1 -1
  4. package/dist/agent/managedRuntimeEnvironment.js +1 -0
  5. package/dist/cli/commandCatalog.js +19 -9
  6. package/dist/cli/interactionPolicy.js +4 -2
  7. package/dist/cli.js +77 -32
  8. package/dist/commands/taskCommands.js +46 -11
  9. package/dist/commands/taskContextCommand.js +1 -1
  10. package/dist/commands/taskRoleRuntimeStatus.js +170 -10
  11. package/dist/controller/agentRuntimeObserver.js +210 -0
  12. package/dist/controller/clientRuntime.js +3 -21
  13. package/dist/controller/controller.js +47 -7
  14. package/dist/controller/fileSchedulerStoreAdapter.js +522 -388
  15. package/dist/controller/runtime.js +9 -3
  16. package/dist/controller/runtimeEventInbox.js +49 -295
  17. package/dist/controller/runtimeEventProcessor.js +184 -321
  18. package/dist/controller/runtimeHookRunFence.js +226 -0
  19. package/dist/controller/runtimeLaunchCoordinator.js +91 -26
  20. package/dist/controller/runtimeObservationHook.js +112 -0
  21. package/dist/core/controllerServer.js +5 -0
  22. package/dist/executor/agentAdapter.js +18 -3
  23. package/dist/executor/fileRoleLaunchPlanner.js +64 -15
  24. package/dist/executor/managedClaudeRunner.js +121 -0
  25. package/dist/observability/executionAudit.js +6 -3
  26. package/dist/repository/taskWorkspacePreparer.js +1 -4
  27. package/dist/run/providerRetryConfig.js +8 -3
  28. package/dist/runtime/agentDriver.js +229 -0
  29. package/dist/runtime/agentDriverObservation.js +57 -0
  30. package/dist/runtime/builtinAgentDrivers.js +235 -0
  31. package/dist/runtime/builtinTranscriptObserver.js +290 -0
  32. package/dist/runtime/builtinTranscriptUsage.js +97 -0
  33. package/dist/runtime/exactControlPlane.js +2 -2
  34. package/dist/runtime/index.js +1 -1
  35. package/dist/runtime/ports.js +12 -1
  36. package/dist/runtime/runtimeObservation.js +297 -0
  37. package/dist/runtime/runtimeProjection.js +277 -0
  38. package/dist/runtime/sessionTerminationGuard.js +78 -22
  39. package/dist/runtime/tmuxAdapters.js +35 -0
  40. package/dist/scheduler/activeRoleRunDelivery.js +28 -13
  41. package/dist/scheduler/leaderWakeupProcessor.js +21 -2
  42. package/dist/scheduler/roleRunLiveness.js +2 -2
  43. package/dist/scheduler/roleRunStall.js +62 -114
  44. package/dist/storage/migration/productionRegistry.js +41 -0
  45. package/dist/storage/sqliteStore.js +3 -3
  46. package/dist/storage/storageVersions.js +1 -1
  47. package/dist/telemetry/sqliteTelemetryStore.js +0 -28
  48. package/dist/telemetry/telemetryCompaction.js +1 -0
  49. package/dist/telemetry/telemetryConfig.js +4 -5
  50. package/dist/tmux/tmuxManager.js +136 -22
  51. package/dist/web/assets/client/view.js +1 -1
  52. package/dist/web/tmuxWebTerminal.js +17 -12
  53. package/dist/web/webSnapshot.js +1 -1
  54. package/dist/worktree/managedWorkspace.js +14 -0
  55. package/i18n/README.zh-CN.md +7 -5
  56. package/package.json +1 -1
  57. package/dist/controller/claudeLifecycleHook.js +0 -203
  58. package/dist/controller/codexLifecycleHook.js +0 -108
  59. package/dist/controller/providerHookRunFence.js +0 -156
  60. package/dist/lifecycle/providerLifecycleMapping.js +0 -190
  61. 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, resourceSuppressionKeys = new Set(), maintenanceFence, onMaintenanceFenceDefer) {
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, resourceSuppressionKeys);
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.#resourceSuppressionKeys, this.#maintenanceFence, this.#onMaintenanceFenceDefer);
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 === "not-ready"
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) {