@zq-silk/yui 0.6.4 → 0.6.5

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 CHANGED
@@ -21,7 +21,7 @@ yui setup
21
21
  yui doctor
22
22
  ```
23
23
 
24
- `setup` is interactive. It detects installed Agent CLIs, asks which Agents to configure, selects the default and Operator Agent, and probes each selected CLI for its current models. It configures the Leader and Operator, then explains that the global Worker configuration is copied into new Task Roles and asks whether Worker should reuse Leader or be configured separately. Model selection is followed by that model's supported reasoning efforts. Setup also confirms the Project workspace outside Yui home and offers shell-completion setup. The picker includes the native CLI default and a custom-value option. Running setup again preserves existing Tasks, Roles, and the installation's Project workspace while allowing safe configuration changes.
24
+ `setup` is interactive. It detects installed Agent CLIs, asks which Agents to configure, selects the default and Operator Agent, and probes each selected CLI for its current models. It configures the Leader and Operator, then explains that the global Worker configuration is copied into new Task Roles and asks whether Worker should reuse Leader or be configured separately. Model selection is followed by that model's supported reasoning efforts. Setup also confirms the Project workspace outside Yui home and offers shell-completion setup. The picker includes the native CLI default and a custom-value option. Running setup again preserves existing Tasks, Roles, and the installation's Project workspace while allowing safe configuration changes. A successful setup ensures the current Home's detached Controller is running before it returns.
25
25
 
26
26
  Model and effort are per-Agent Role settings, so Operator, Leader, and the global Worker can use different values even when they share an Agent CLI. Interactive Role flows validate those settings against the selected Agent runtime. Worker Profile model and effort fields are provider-neutral child-execution hints and therefore remain explicit, scriptable values rather than Agent capability selections.
27
27
 
@@ -737,6 +737,12 @@ hiding the resources that remain. Use `--all` to include discovered Yui homes.
737
737
 
738
738
  `controller restart` replaces the Controller process and its scheduler/socket services with the currently installed Yui version. It does not stop or restart managed tmux/Agent sessions.
739
739
 
740
+ Successful `setup`, `upgrade`, and `update` commands ensure that the current
741
+ Home has a running Controller, starting one when the Home was previously idle.
742
+ Read-only commands and `upgrade --dry-run` do not start a Controller. `update`
743
+ also replaces an already-running Controller only after the new binary passes its
744
+ health checks.
745
+
740
746
  Its recovery reconciliation runs every 120 seconds by default. Normal durable state changes enqueue a Task, Role, or Operator key and return immediately; keys received in the same fixed 100 ms window trigger one non-overlapping targeted pass. Operator presentation has an independent lane, so a blocked Task workspace operation cannot delay a user question. Periodic Git/worktree work is limited to Tasks with durable Task-mailbox work, while active Role liveness uses one tmux inventory. Agent Driver Hooks write exact-fenced observations to the durable runtime inbox without starting or waiting for the Controller. A terminal Turn observation gives a legal yield/input/completion two seconds to win before a forgotten Run fails its workflow contract. Durable mailboxes freeze the current batch while new signals merge into the next batch. Task-orchestration failures retain the exact Controller-owned processing batch for two bounded fast retries and later periodic recovery; a successful retry completes that batch before newer pending work is claimed. Recommended InputRequest and pending Turn deadlines share one nearest-deadline selector and therefore do not wait for the recovery interval. Explicit `task reconcile` still requests an immediate recovery pass. The retained loop is:
741
747
 
742
748
  1. dispatch pending Leader wakes whose Task workspaces are already ready;
@@ -821,8 +827,10 @@ preflight does not create or validate a staged Home and is not
821
827
  stops the exact old Controller PID. Current and compatible-old Homes use the
822
828
  no-Home-mutation fast path; migration-required Homes first require a clear
823
829
  offline Run/Session/lifecycle inventory, then use the timestamped-backup switch.
824
- Both paths promote the binary only after an exact PID-fenced old-Controller stop
825
- and run a new-binary health check before the authenticated replacement starts.
830
+ Both paths run a new-binary health check before the authenticated Controller
831
+ handoff. When an old Controller exists, it is stopped with an exact PID fence;
832
+ when no old Controller existed, the same verified new Controller is started
833
+ before the update reports success.
826
834
  Yui promotes the **same artifact it staged**
827
835
  (binary activation pins the exact staged version, never a second bare `@latest`);
828
836
  the staged version must be a **concrete semver** — a `latest`/dist-tag sentinel,
@@ -223,12 +223,15 @@ function activateAndVerify(ports, staged, home, storageBackupPath, lifecycle, pa
223
223
  };
224
224
  return restoreBeforeSwitchOrReport(ports, home, lifecycle, storageBackupPath, failure);
225
225
  }
226
- if (lifecycle?.wasRunning === true) {
226
+ if (lifecycle?.ensureRunning === true) {
227
227
  try {
228
228
  ports.startController(home);
229
229
  }
230
230
  catch (error) {
231
231
  const unknownActive = isUnknownActiveControllerFailure(error);
232
+ const startFailureAction = lifecycle.wasRunning
233
+ ? "The Home was not migrated. Keep writes quiesced and restore the previously running Controller identity before retrying."
234
+ : "The Home was not migrated. Keep writes quiesced and start the replacement Controller after verifying the activated binary.";
232
235
  const failure = {
233
236
  outcome: "aborted",
234
237
  phase: "post-verify",
@@ -237,7 +240,7 @@ function activateAndVerify(ports, staged, home, storageBackupPath, lifecycle, pa
237
240
  action: unknownActive
238
241
  ? unknownActiveControllerAction(home, storageBackupPath)
239
242
  : storageBackupPath === undefined
240
- ? "The Home was not migrated. Keep writes quiesced and restore the previously running Controller identity before retrying."
243
+ ? startFailureAction
241
244
  : postSwitchRecoveryAction(home, storageBackupPath),
242
245
  recoverable: false,
243
246
  version: staged.version,
@@ -276,8 +279,9 @@ function captureControllerLifecycle(ports, version, home) {
276
279
  ports.startController,
277
280
  ports.restoreController
278
281
  ].some((port) => port !== undefined);
279
- if (!supplied)
280
- return { lifecycle: { wasRunning: false, stopped: false } };
282
+ if (!supplied) {
283
+ return { lifecycle: { ensureRunning: false, wasRunning: false, stopped: false } };
284
+ }
281
285
  if (ports.controllerStatus === undefined
282
286
  || ports.stopController === undefined
283
287
  || ports.startController === undefined
@@ -315,8 +319,9 @@ function captureControllerLifecycle(ports, version, home) {
315
319
  version
316
320
  };
317
321
  }
318
- if (!status.running)
319
- return { lifecycle: { wasRunning: false, stopped: false } };
322
+ if (!status.running) {
323
+ return { lifecycle: { ensureRunning: true, wasRunning: false, stopped: false } };
324
+ }
320
325
  if (!isPositivePid(status.pid)) {
321
326
  return {
322
327
  outcome: "aborted",
@@ -365,6 +370,7 @@ function captureControllerLifecycle(ports, version, home) {
365
370
  }
366
371
  return {
367
372
  lifecycle: {
373
+ ensureRunning: true,
368
374
  wasRunning: true,
369
375
  stopped: true,
370
376
  identity: status.identity
package/dist/cli.js CHANGED
@@ -177,6 +177,10 @@ export async function main() {
177
177
  };
178
178
  validateSetupInvocation(args.slice(1), setupIo);
179
179
  const output = await runSetupCommand(args.slice(1), process.env, new NodeCommandExecutor(), setupIo);
180
+ // A successful setup leaves the Home ready for normal Yui work. Start the
181
+ // detached per-Home Controller even when setup began with no Controller;
182
+ // read-only commands and failed setup still remain non-starting paths.
183
+ await ensureFileTaskController(home, { environment: process.env });
180
184
  const refresh = await refreshRunningFileTaskControllerEnvironment(home, openCompatibleFileTaskStore(home), process.env);
181
185
  emit(withControllerRefreshWarning(output, refresh, "Agent environment"));
182
186
  return;
@@ -220,6 +224,14 @@ export async function main() {
220
224
  const result = await runUpgradeCommand(args.slice(1), home, process.env.YUI_UPDATE_EXTERNALLY_QUIESCED === "1"
221
225
  ? { controllerLifecycle: "externally-quiesced" }
222
226
  : {});
227
+ // Public execute upgrades leave the Home operational even when no
228
+ // Controller existed before the command. Dry-run and the staged updater's
229
+ // externally-quiesced preflight must remain read-only/lifecycle-neutral.
230
+ if (args.length === 1
231
+ && result.exitCode === 0
232
+ && process.env.YUI_UPDATE_EXTERNALLY_QUIESCED !== "1") {
233
+ await ensureFileTaskController(home, { environment: process.env });
234
+ }
223
235
  process.exitCode = result.exitCode;
224
236
  emit(result.output, false, result.data);
225
237
  return;
@@ -52,7 +52,8 @@ Leader 和 Operator,再说明全局 Worker 配置会复制到新建的 Task Ro
52
52
  支持的思考强度。随后 setup 会确认位于 Yui home 外部的 Project workspace,
53
53
  并询问 shell completion。选择器同时提供原生 CLI 默认值和自定义值入口。
54
54
  再次运行不会删除已有 Task/Role,也不会改变当前安装的 Project workspace,
55
- 可用于安全地调整配置。
55
+ 可用于安全地调整配置。setup 成功返回前会确保当前 Home 的后台 Controller
56
+ 已经启动。
56
57
 
57
58
  模型与思考强度属于 Agent binding 设置,因此 Operator、Leader 和全局
58
59
  Worker 即使使用同一个 Agent CLI,也可以采用不同配置。Profile 中的
@@ -477,6 +478,11 @@ yui controller restart
477
478
 
478
479
  `controller restart` 会用当前安装的 Yui 版本替换 Controller 进程及其调度循环、socket 服务,不会停止或重启已受管的 tmux/Agent 会话。
479
480
 
481
+ 成功的 `setup`、`upgrade` 和 `update` 都会确保当前 Home 有一个运行中的
482
+ Controller;如果之前没有运行,会在完成后启动。只读命令和
483
+ `upgrade --dry-run` 不会启动 Controller。`update` 只有在新二进制健康检查通过后,
484
+ 才会替换或启动 Controller。
485
+
480
486
  恢复 reconciliation 默认每 120 秒执行一次。普通持久状态变化只会将 Task、Role 或 Operator key 放入队列并立即返回;固定 100ms 窗口内到达的 key 会合并触发一次不重叠的定向处理。Operator 呈现使用独立 lane,不会被 Task 的 Git/worktree 操作阻塞;周期 Git/worktree 处理只覆盖仍有持久 Task mailbox 工作的 Task,活动 Role 的存活检查合并为一次 tmux inventory。Codex turn-complete Hook 直接写入存储,不启动或等待 Controller,并给合法的 yield、输入请求或完成动作保留 2 秒竞争窗口;到期后才关闭被 Agent 遗忘的活动 Role Run。持久 WorkMailbox 会冻结当前 processing 批次,期间的新事件合并到下一 pending 批次;失败会释放当前批次供恢复。推荐输入与 pending Turn 共用最近 deadline 选择器,不依赖恢复扫描间隔;显式 `task reconcile` 仍会立即请求恢复扫描。保留的闭环为:
481
487
 
482
488
  1. 准备 active Project Task 的主 worktree;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zq-silk/yui",
3
- "version": "0.6.4",
3
+ "version": "0.6.5",
4
4
  "description": "Local control plane for long-running native agent CLI sessions backed by tmux.",
5
5
  "license": "MIT",
6
6
  "private": false,