@zq-silk/yui 0.8.9 → 0.10.0
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 +48 -46
- package/README.md +72 -42
- package/dist/cli/commandCatalog.js +16 -8
- package/dist/cli.js +27 -32
- package/dist/commands/executionAuditCommands.js +2 -2
- package/dist/commands/globalRoleCommands.js +0 -12
- package/dist/commands/sessionCommands.js +116 -0
- package/dist/commands/taskBaseCommands.js +1 -11
- package/dist/commands/taskCommands.js +123 -340
- package/dist/commands/taskCompletionGate.js +15 -12
- package/dist/commands/taskContextCommand.js +18 -11
- package/dist/commands/taskNextActionCommand.js +4 -5
- package/dist/commands/taskWorkspaceCommands.js +2 -2
- package/dist/controller/clientRuntime.js +65 -0
- package/dist/controller/fileSchedulerStoreAdapter.js +2 -49
- package/dist/doctor/doctor.js +16 -12
- package/dist/execution/executionGroup.js +0 -3
- package/dist/executor/agentAdapter.js +39 -42
- package/dist/executor/agentExecutor.js +4 -2
- package/dist/executor/codexConfigConflict.js +40 -16
- package/dist/executor/effectiveLaunch.js +33 -3
- package/dist/executor/fileRoleLaunchPlanner.js +15 -24
- package/dist/integration/deliveryObligation.js +72 -0
- package/dist/integration/gitIntegrationService.js +1 -1
- package/dist/lifecycle/exactRunTerminalization.js +12 -8
- package/dist/observability/orchestrationMetrics.js +12 -26
- package/dist/profile/agentProfile.js +1 -1
- package/dist/repository/taskBaseFreshness.js +5 -11
- package/dist/repository/taskWorkspaceCoordinator.js +2 -0
- package/dist/repository/taskWorkspacePreparer.js +173 -26
- package/dist/review/reviewRound.js +41 -24
- package/dist/role/role.js +0 -9
- package/dist/runtime/{firstProgressStopLoss.js → firstProgressAdvisory.js} +7 -21
- package/dist/scheduler/leaderWakeupProcessor.js +0 -25
- package/dist/setup/setupCommand.js +0 -5
- package/dist/storage/migration/productionRegistry.js +138 -0
- package/dist/storage/sqliteStore.js +2 -1
- package/dist/storage/taskStore.js +27 -27
- package/dist/storage/upgrade/upgradeOrchestrator.js +35 -7
- package/dist/task/completionReadiness.js +35 -25
- package/dist/task/nextAction.js +70 -78
- package/dist/task/task.js +12 -19
- package/dist/web/assets/client/components.js +3 -1
- package/dist/web/assets/client/i18n.js +6 -0
- package/dist/web/webSnapshot.js +0 -3
- package/i18n/README.zh-CN.md +33 -24
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +55 -52
- package/skills/yui-operator/SKILL.md +31 -40
- package/skills/yui-reviewer/SKILL.md +18 -12
- package/skills/yui-worker/SKILL.md +5 -3
package/ARCHITECTURE.md
CHANGED
|
@@ -5,31 +5,32 @@ runtimes. The user talks to one Operator. The Operator routes each request to
|
|
|
5
5
|
the right Project and Task; that Task's Leader owns decomposition, execution
|
|
6
6
|
choice, review, integration, and completion.
|
|
7
7
|
|
|
8
|
-
## One outcome
|
|
9
|
-
|
|
10
|
-
`Task` is the bounded user outcome. Its
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
managed Task main without
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
8
|
+
## One outcome, Leader-chosen execution topology
|
|
9
|
+
|
|
10
|
+
`Task` is the bounded user outcome. Its optional `type` describes intent, not
|
|
11
|
+
execution topology; software Projects normally use `feature` or `bugfix`, while
|
|
12
|
+
other Projects may define their own types. Yui does not store a direct versus
|
|
13
|
+
integrated delivery mode.
|
|
14
|
+
|
|
15
|
+
A software bugfix is Leader-owned: the Leader implements and verifies it in the
|
|
16
|
+
managed Task main without manufacturing a WorkItem. If the scope proves to need
|
|
17
|
+
independent delivery owners, reclassify it as a feature before creating those
|
|
18
|
+
units. For a feature, the Leader judges whether the whole result is small
|
|
19
|
+
enough to own in the same way or large enough to need independently owned
|
|
20
|
+
delivery units.
|
|
21
|
+
|
|
22
|
+
`WorkItem` means one substantial, independently acceptable requirement with a
|
|
23
|
+
clear owner. Create multiple WorkItems only when multiple Workers can own and
|
|
24
|
+
advance those requirements independently, normally in parallel. Internal
|
|
25
|
+
implementation steps, test runs, review findings, and local fixes remain Run,
|
|
26
|
+
Event, report, or commit evidence under the existing Task or WorkItem; they are
|
|
27
|
+
not new WorkItems.
|
|
28
|
+
|
|
29
|
+
Each WorkItem may use a native subagent inside the Leader conversation or a
|
|
30
|
+
Task Role AgentRun backed by a durable Worker Session. There is no Yui
|
|
31
|
+
subagent launcher or child-session record. AgentRun is an execution attempt,
|
|
32
|
+
not a requirement, and repeated Runs may continue the same compatible Role
|
|
33
|
+
Session.
|
|
33
34
|
|
|
34
35
|
## Profiles, Roles, and Agents
|
|
35
36
|
|
|
@@ -49,8 +50,10 @@ independent execution additionally records an AgentRun.
|
|
|
49
50
|
- A `WorkItemCandidate` is the explicit result currently awaiting Leader
|
|
50
51
|
acceptance. It snapshots the WorkItem revision, summary, and either a
|
|
51
52
|
yielded execution Run or a Leader-managed direct source.
|
|
52
|
-
- `ReviewRound` records
|
|
53
|
-
|
|
53
|
+
- `ReviewRound` records one semantic judgment. A WorkItem Review references
|
|
54
|
+
that WorkItem's immutable Candidate. A Task-final Review references the
|
|
55
|
+
frozen Task heads directly and has no synthetic WorkItem/Candidate anchor.
|
|
56
|
+
It is never another WorkItem.
|
|
54
57
|
|
|
55
58
|
Adding another Agent requires an explicit adapter implementation. Profiles do
|
|
56
59
|
not choose adapters, own Sessions, or carry credentials.
|
|
@@ -65,7 +68,7 @@ effort, round, result, and checks.
|
|
|
65
68
|
|
|
66
69
|
## Lifecycle and acceptance
|
|
67
70
|
|
|
68
|
-
|
|
71
|
+
Native-subagent WorkItem execution follows:
|
|
69
72
|
|
|
70
73
|
```text
|
|
71
74
|
todo -> running -> done | failed
|
|
@@ -92,16 +95,12 @@ Every result awaiting acceptance is stored as an explicit WorkItem candidate.
|
|
|
92
95
|
`always` dispatches a review AgentRun for every candidate, whether it comes
|
|
93
96
|
from a yielded execution Run or a Leader-managed direct result; `leader`
|
|
94
97
|
leaves every candidate for the Leader to accept directly or review explicitly.
|
|
95
|
-
`final`
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
A
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
provenance.
|
|
102
|
-
Any established immutable Task-final contract or Round remains an obligation.
|
|
103
|
-
A changed integrated head queues a new round; the previous report remains
|
|
104
|
-
evidence. This final Reviewer evaluates the whole
|
|
98
|
+
`final` keeps WorkItem acceptance and Integration independent and supplies the
|
|
99
|
+
default Reviewer Role when the Leader decides the frozen Task result warrants
|
|
100
|
+
an independent final Review. An immutable Task-final contract can require that
|
|
101
|
+
Review. A Leader-requested Round remains evidence without becoming policy: a
|
|
102
|
+
later Task head does not require another Round unless the Leader requests one
|
|
103
|
+
or an explicit Task contract requires it. This final Reviewer evaluates the whole
|
|
105
104
|
Task, so normal delivery does not pay for a complete review of every WorkItem.
|
|
106
105
|
Review Runs complete only their exact ReviewRound, leave the WorkItem awaiting
|
|
107
106
|
acceptance, and never trigger another review or append a Candidate. Successful
|
|
@@ -114,9 +113,12 @@ never merges it automatically.
|
|
|
114
113
|
Roles describe Agent capability, but they do not own repository workspaces. A
|
|
115
114
|
`ManagedWorkspace` is keyed by its durable owner (`Task`, `WorkItem`,
|
|
116
115
|
`ReviewRound`, or `IntegrationAttempt`); an AgentRun carries only a launch
|
|
117
|
-
snapshot. Review workspaces are
|
|
118
|
-
|
|
119
|
-
|
|
116
|
+
snapshot. Review workspaces are writable copies at the frozen commit, so
|
|
117
|
+
diagnostics cannot redirect Develop or become a ChangeSet source. Task-final
|
|
118
|
+
Rounds keep independent immutable records but may reassign one clean physical
|
|
119
|
+
workspace to the next Round for the same Reviewer Role. This lets the native
|
|
120
|
+
Reviewer Session continue while every Run remains bound to its exact Round and
|
|
121
|
+
head.
|
|
120
122
|
|
|
121
123
|
Dependencies are enforced at dispatch. A Role cannot have overlapping active
|
|
122
124
|
Runs, and terminal Task state fences new messages, dispatches, retries, and
|
|
@@ -147,8 +149,8 @@ Projects and Task-main context for the rest. The managed dispatch and
|
|
|
147
149
|
writable set. Provider permission is binding configuration: every managed Role
|
|
148
150
|
defaults to `bypass`, while `default` and `configured` preserve provider-native
|
|
149
151
|
behavior. Provider permission and Profile access intent do not grant Project
|
|
150
|
-
writes. A
|
|
151
|
-
|
|
152
|
+
writes. A Leader-owned source write requires the exact Task-main owner. A
|
|
153
|
+
WorkItem source write requires an exact WorkItem write scope and matching
|
|
152
154
|
managed workspace; a review write instead
|
|
153
155
|
requires an exact ReviewRound owner and frozen Candidate base. Profiles and
|
|
154
156
|
Skills constrain behavior even when provider prompts are bypassed. Provider
|
|
@@ -185,9 +187,9 @@ independently acceptable ownership.
|
|
|
185
187
|
|
|
186
188
|
Capture at the same HEAD reuses the existing ChangeSet. A repaired HEAD creates
|
|
187
189
|
a new candidate; only the latest reviewed candidate may satisfy acceptance.
|
|
188
|
-
An isolated WorkItem cannot be accepted, or
|
|
189
|
-
any writable Project's latest result is uncaptured or unintegrated.
|
|
190
|
-
completion instead requires a clean committed exact Task-main snapshot.
|
|
190
|
+
An isolated WorkItem cannot be accepted, or a Task with WorkItems completed,
|
|
191
|
+
while any writable Project's latest result is uncaptured or unintegrated.
|
|
192
|
+
Leader-owned completion instead requires a clean committed exact Task-main snapshot.
|
|
191
193
|
Workspace roots are
|
|
192
194
|
multi-Project; ChangeSets and Integration Attempts remain single-Project Git
|
|
193
195
|
boundaries.
|
package/README.md
CHANGED
|
@@ -144,6 +144,21 @@ Input by itself do not block. A blocker reports the total and exact available
|
|
|
144
144
|
Task/Role/Run/native-session/launch identities and reason, leaves the scene
|
|
145
145
|
unchanged, and tells the user to re-run `yui update` after the listed work clears;
|
|
146
146
|
it never kills, resets, rebinds, retries, or drains on the user's behalf.
|
|
147
|
+
After every listed Turn or Run finishes, the user can stop all idle managed
|
|
148
|
+
Sessions from a normal shell and retry the update:
|
|
149
|
+
|
|
150
|
+
```sh
|
|
151
|
+
yui session stop --all
|
|
152
|
+
yui update
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
`session stop --all` first checks every current Session and refuses without
|
|
156
|
+
stopping anything while any Session still has a running Turn/Run or pending
|
|
157
|
+
lifecycle work. Once clear, it fences new Leader dispatch, stops and drains the
|
|
158
|
+
Controller, rechecks the runtime facts, then stops every exact idle Session. The
|
|
159
|
+
Controller remains stopped so `yui update` can enter its offline window. When the
|
|
160
|
+
installed version predates this command, exit every listed managed Session
|
|
161
|
+
manually instead; a staged new CLI cannot write the older migration-required Home.
|
|
147
162
|
|
|
148
163
|
Only that user re-run may enter the existing full migration. Once its preflight
|
|
149
164
|
is clear, the update parent captures and stops the exact old Controller PID. The
|
|
@@ -250,8 +265,8 @@ yui project update app --alias app-cli
|
|
|
250
265
|
yui project refresh app
|
|
251
266
|
yui project list
|
|
252
267
|
|
|
253
|
-
yui task create "Fix CSV escaping" --project app --
|
|
254
|
-
yui task create "Ship CSV export" --project app --
|
|
268
|
+
yui task create "Fix CSV escaping" --project app --type bugfix
|
|
269
|
+
yui task create "Ship CSV export" --project app --type feature
|
|
255
270
|
yui task update <task-id> --priority high --tags release,csv --due-at 2026-08-01T00:00:00Z
|
|
256
271
|
yui task update <task-id> --clear-priority --clear-tags --clear-due-at
|
|
257
272
|
yui task show <task-id>
|
|
@@ -259,18 +274,18 @@ yui task context <task-id>
|
|
|
259
274
|
yui task activate <task-id>
|
|
260
275
|
```
|
|
261
276
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
277
|
+
Task type describes intent rather than selecting an execution protocol.
|
|
278
|
+
Software Projects use `bugfix` or `feature`: a bugfix is Leader-owned; if it
|
|
279
|
+
grows into independently owned delivery requirements, reclassify it as a
|
|
280
|
+
feature before creating WorkItems. The Leader decides whether a feature is
|
|
281
|
+
small enough to deliver on Task main or large enough for independently owned WorkItems. A WorkItem is
|
|
282
|
+
one substantial requirement for one Worker, not a development step, test run,
|
|
283
|
+
review finding, or local fix. Multiple WorkItems are useful only when distinct
|
|
284
|
+
Workers can advance meaningful requirements independently. A WorkItem's
|
|
285
|
+
governing Candidate defines its delivery obligation: its current ChangeSets
|
|
286
|
+
must reach committed Integration or an explicit superseded queue disposition
|
|
287
|
+
before Task-final Review or completion. Older Candidate and ChangeSet records
|
|
288
|
+
remain audit evidence without keeping the Task open.
|
|
274
289
|
|
|
275
290
|
`project refresh` is the explicit network operation for a stable Project checkout. It fetches the
|
|
276
291
|
configured stable branch directly from the Project remote URL and advances only through a clean,
|
|
@@ -313,9 +328,9 @@ yui config show
|
|
|
313
328
|
yui config workflow clear review
|
|
314
329
|
```
|
|
315
330
|
|
|
316
|
-
For Project-backed software delivery, use `--trigger final` to
|
|
317
|
-
|
|
318
|
-
|
|
331
|
+
For Project-backed software delivery, use `--trigger final` to supply the
|
|
332
|
+
default Reviewer Role when the Leader decides the complete frozen Task result
|
|
333
|
+
needs an independent Review:
|
|
319
334
|
|
|
320
335
|
```sh
|
|
321
336
|
yui config workflow set review --role reviewer --trigger final
|
|
@@ -330,10 +345,13 @@ or a Leader-managed direct result; `leader` leaves the candidate awaiting
|
|
|
330
345
|
acceptance so the Leader can accept it directly or run
|
|
331
346
|
`yui task work review <task-id>/<work-item-id>`. A configured review rule therefore keeps
|
|
332
347
|
Leader-managed candidates awaiting a decision instead of marking them done.
|
|
333
|
-
`final` does not create WorkItem ReviewRounds
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
348
|
+
`final` does not create WorkItem ReviewRounds or decide Task topology. The
|
|
349
|
+
Leader explicitly requests a Task-scoped Review, unless an immutable Task
|
|
350
|
+
contract requires one. The Round freezes Task main directly, so even a
|
|
351
|
+
Leader-owned Task with no WorkItem can be reviewed. A changed frozen head needs
|
|
352
|
+
a new semantic Round; the same compatible Reviewer Session may continue in its
|
|
353
|
+
stable workspace, while every Run remains bound to its exact Round and head.
|
|
354
|
+
The Reviewer follows Project Policy/Knowledge and reports reachable, material,
|
|
337
355
|
actionable findings across the complete Task.
|
|
338
356
|
A ReviewRound freezes the Candidate's exact Git commit and creates a fresh,
|
|
339
357
|
ReviewRound-owned writable worktree on a unique branch. Its AgentRun may edit,
|
|
@@ -385,7 +403,7 @@ expands:
|
|
|
385
403
|
yui task create "Update authentication" \
|
|
386
404
|
--project backend --project frontend \
|
|
387
405
|
--base backend=develop --base frontend=main \
|
|
388
|
-
--
|
|
406
|
+
--type feature
|
|
389
407
|
yui task project add <task-id> shared-sdk --base main
|
|
390
408
|
```
|
|
391
409
|
|
|
@@ -401,7 +419,9 @@ yui task base status <task-id> --refresh
|
|
|
401
419
|
The default check is offline and uses local remote-tracking refs. `--refresh`
|
|
402
420
|
is the explicit authorization to query the configured remote; Yui never
|
|
403
421
|
fetches, rebases, merges, or force-pushes as a hidden side effect of Task
|
|
404
|
-
completion.
|
|
422
|
+
completion. Behind, diverged, or unavailable remote state is reported as
|
|
423
|
+
delivery-risk evidence for the Leader; it does not replace the Leader's choice
|
|
424
|
+
of delivery base. A dirty Task workspace remains a completion blocker.
|
|
405
425
|
|
|
406
426
|
Implementation WorkItems declare the Projects they may modify. Their workspace
|
|
407
427
|
keeps the same relative layout, creates isolated worktrees only for that write
|
|
@@ -565,15 +585,15 @@ bounded next options. Yield records immutable Run/Candidate or Review evidence
|
|
|
565
585
|
only; it does not imply acceptance, WorkItem completion, ChangeSet capture,
|
|
566
586
|
Integration, or Task completion.
|
|
567
587
|
|
|
568
|
-
For
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
588
|
+
For one substantial feature requirement, the Leader may create a WorkItem and
|
|
589
|
+
give it to a native subagent or Task Role Worker. A small Task or bugfix stays
|
|
590
|
+
on Task main. Do not create a WorkItem merely to record implementation steps,
|
|
591
|
+
tests, review, or follow-up fixes:
|
|
572
592
|
|
|
573
593
|
```sh
|
|
574
|
-
yui task work create <task-id> "
|
|
575
|
-
--objective "
|
|
576
|
-
--accept "
|
|
594
|
+
yui task work create <task-id> "Implement the export API" \
|
|
595
|
+
--objective "Deliver the independently acceptable export API requirement" \
|
|
596
|
+
--accept "The API contract and focused validation are complete"
|
|
577
597
|
yui task work update <task-id>/<work-item-id> running
|
|
578
598
|
yui config profile show reviewer
|
|
579
599
|
```
|
|
@@ -703,17 +723,18 @@ yui task complete <task-id> --summary-file delivery.txt \
|
|
|
703
723
|
--accept-published-tree <publication-id>
|
|
704
724
|
```
|
|
705
725
|
|
|
706
|
-
This
|
|
726
|
+
This is an independent exact-tree authorization. Yui requires the current,
|
|
707
727
|
unsuperseded Publication to be merged and verified, its local commit to equal
|
|
708
728
|
the physical Task head, its remote commit to be ancestry-divergent, and both
|
|
709
|
-
commits to resolve to the same exact tree.
|
|
710
|
-
|
|
729
|
+
commits to resolve to the same exact tree. When a Task-final Review obligation
|
|
730
|
+
exists, completion also requires the latest semantic Round to attest the
|
|
731
|
+
accepted Task head; otherwise completion does not invent a ReviewRound.
|
|
711
732
|
`--refresh-remote` fetches
|
|
712
733
|
the remote object graph before resolving that Publication commit. For a Task
|
|
713
|
-
governed by a durable
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
734
|
+
governed by a durable final-review contract, the stored contract continues to
|
|
735
|
+
require its Reviewer policy, but compatible CLI and Controller updates do not
|
|
736
|
+
need to reproduce its historical control-plane digest. Tasks without that
|
|
737
|
+
contract retain the one-step explicit completion path. The Task event
|
|
717
738
|
audit records the authorization and, on completion, the accepted Project,
|
|
718
739
|
Publication, optional ReviewRound, both commits, and tree.
|
|
719
740
|
|
|
@@ -762,14 +783,22 @@ Global Operator and global Role sessions remain native interactive CLIs:
|
|
|
762
783
|
yui session enter <global-role>
|
|
763
784
|
```
|
|
764
785
|
|
|
786
|
+
An offline Home migration requires a short maintenance window with no managed
|
|
787
|
+
Agent Session running. Once current Turns and Runs have finished, use
|
|
788
|
+
`yui session stop --all` from a normal shell. The command stops Task and global
|
|
789
|
+
Role Sessions only after every one is idle, and leaves all Sessions untouched
|
|
790
|
+
when any Role is still busy. On success it also leaves the Controller stopped;
|
|
791
|
+
run `yui update` next rather than resuming ordinary Task work.
|
|
792
|
+
|
|
765
793
|
tmux fixes a pane's history capacity when that pane is created. Existing panes
|
|
766
794
|
retain their configured capacity; managed runtime output remains observable in
|
|
767
795
|
the Agent Host pane without becoming lifecycle or acknowledgement evidence.
|
|
768
796
|
|
|
769
|
-
Each Role, including a Task-bound Worker instance, can bind multiple
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
ready-to-switch configurations
|
|
797
|
+
Each Role, including Operator and a Task-bound Worker instance, can bind multiple
|
|
798
|
+
configured Agents, has one active Agent, and keeps a separate native session per
|
|
799
|
+
Agent binding. Multiple bindings may use the same adapter for different accounts,
|
|
800
|
+
models, profiles, or environment sources. They are ready-to-switch configurations,
|
|
801
|
+
not parallel writers: the active binding remains the unique authority. Operator can
|
|
773
802
|
keep multiple conversations for each binding. `operator new` and
|
|
774
803
|
`operator resume` reuse the single Operator tmux pane: when a process is
|
|
775
804
|
running, Yui asks before stopping it and switching the conversation. On a
|
|
@@ -811,7 +840,7 @@ movement cannot conceal a workflow that is not advancing.
|
|
|
811
840
|
|
|
812
841
|
Stable Role context is also launch metadata, never a bootstrap turn. Yui passes Role policy and `systemPrompt` through the Agent's native system/developer-instruction channel. Task execution Runs receive the generic Leader or Worker Skill, while review Runs receive the generic Reviewer Skill based on durable Run purpose rather than a configured Role name. These Yui-owned Role Skills define portable orchestration only. Project Skills remain ordinary versioned files in the Project and are discovered, selected, and loaded by the Agent through its native project mechanism; Yui does not scan, parse, copy, or inject them.
|
|
813
842
|
|
|
814
|
-
Native Codex developer instructions carry compact absolute references only for Yui-owned Role Skills, which Codex reads on demand.
|
|
843
|
+
Native Codex developer instructions carry compact absolute references only for Yui-owned Role Skills, which Codex reads on demand. Yui applies this scalar as an invocation-local override, so existing user, profile, project, and system values do not make the Session unusable and the underlying config file is never mutated. A higher-precedence managed `developer_instructions` value remains a bounded launch blocker because Codex will not let invocation flags replace it. Interactive Codex Sessions apply the same rule to Yui's structured `notify` callback; Doctor reports ordinary overridden sources as context and rejects an effective managed conflict. Managed Runs instead use invocation-local Agent Driver Hooks as their sole lifecycle authority and do not claim `notify`. `skills.config` is not misused because it only enables or disables already-discovered Skills. Claude receives the same Yui-owned Role Skill content from a private `0600` managed context file rather than a large or sensitive argv value; retries and resumes reuse the purpose-specific Role path. Non-Operator global Roles stay neutral and receive no Task orchestration Skill. Operator therefore opens at an empty native composer, so the user's text remains its first user message. Leader wakeups and Worker or Reviewer Run assignments remain real mailbox-delivered work messages. An adapter without a native instruction channel must reject this context rather than silently converting it into a first user prompt.
|
|
815
844
|
|
|
816
845
|
## Controller and failure handling
|
|
817
846
|
|
|
@@ -927,6 +956,7 @@ yui config role add|list|show|update|remove|bind|unbind
|
|
|
927
956
|
yui config profile add|list|show|update|remove|reset
|
|
928
957
|
yui config completion [bash|zsh|fish]
|
|
929
958
|
yui session enter|record|replace|reconcile
|
|
959
|
+
yui session stop --all
|
|
930
960
|
yui project add|clone|refresh|update|discover|list|show|knowledge
|
|
931
961
|
```
|
|
932
962
|
|
|
@@ -199,6 +199,12 @@ const globalSessionChildren = [
|
|
|
199
199
|
usage: "yui session replace <role> --native-id <id> --reason <text>",
|
|
200
200
|
options: ["--native-id", "--reason"]
|
|
201
201
|
},
|
|
202
|
+
{
|
|
203
|
+
name: "stop",
|
|
204
|
+
summary: "Stop all idle managed Sessions and the Controller before an offline update.",
|
|
205
|
+
usage: "yui session stop --all",
|
|
206
|
+
options: ["--all"]
|
|
207
|
+
},
|
|
202
208
|
{
|
|
203
209
|
name: "reconcile",
|
|
204
210
|
summary: "Reconcile durable Session owners with native sessions.",
|
|
@@ -241,9 +247,9 @@ const taskChildren = [
|
|
|
241
247
|
{
|
|
242
248
|
name: "create",
|
|
243
249
|
summary: "Create a Draft Task.",
|
|
244
|
-
usage: "yui task create <title> [--
|
|
245
|
-
options: ["--
|
|
246
|
-
optionValues: { "--
|
|
250
|
+
usage: "yui task create <title> [--type <project-defined-type>] [--project <project> ...] [--base <project>=<ref> ...]",
|
|
251
|
+
options: ["--type", "--project", "--base"],
|
|
252
|
+
optionValues: { "--type": ["feature", "bugfix"] }
|
|
247
253
|
},
|
|
248
254
|
{
|
|
249
255
|
name: "project",
|
|
@@ -266,15 +272,15 @@ const taskChildren = [
|
|
|
266
272
|
{
|
|
267
273
|
name: "update",
|
|
268
274
|
summary: "Update Task metadata.",
|
|
269
|
-
usage: "yui task update <id> [--title <text>] [--description <text>|--clear-description] [--priority <low|medium|high|urgent>|--clear-priority] [--tags <comma-separated>|--clear-tags] [--due-at <RFC3339>|--clear-due-at]
|
|
275
|
+
usage: "yui task update <id> [--title <text>] [--type <project-defined-type>|--clear-type] [--description <text>|--clear-description] [--priority <low|medium|high|urgent>|--clear-priority] [--tags <comma-separated>|--clear-tags] [--due-at <RFC3339>|--clear-due-at]",
|
|
270
276
|
options: [
|
|
271
|
-
"--title", "--description", "--priority", "--tags", "--due-at",
|
|
277
|
+
"--title", "--type", "--description", "--priority", "--tags", "--due-at",
|
|
278
|
+
"--clear-type",
|
|
272
279
|
"--clear-description", "--clear-priority", "--clear-tags", "--clear-due-at",
|
|
273
|
-
"--delivery", "--require-integration"
|
|
274
280
|
],
|
|
275
281
|
optionValues: {
|
|
276
282
|
"--priority": ["low", "medium", "high", "urgent"],
|
|
277
|
-
"--
|
|
283
|
+
"--type": ["feature", "bugfix"]
|
|
278
284
|
}
|
|
279
285
|
},
|
|
280
286
|
{ name: "activate", summary: "Activate a Draft Task.", usage: "yui task activate <id>" },
|
|
@@ -1357,14 +1363,16 @@ export const ROOT_COMMAND = buildNode({
|
|
|
1357
1363
|
},
|
|
1358
1364
|
{
|
|
1359
1365
|
name: "session",
|
|
1360
|
-
summary: "
|
|
1366
|
+
summary: "Enter, stop, and reconcile managed Role sessions.",
|
|
1361
1367
|
examples: [
|
|
1362
1368
|
"yui session context operator --json",
|
|
1363
1369
|
"yui session enter operator",
|
|
1370
|
+
"yui session stop --all",
|
|
1364
1371
|
"yui session reconcile --report"
|
|
1365
1372
|
],
|
|
1366
1373
|
sections: [
|
|
1367
1374
|
{ id: "global", title: "Global Role sessions", entries: ["context", "enter", "record", "replace"] },
|
|
1375
|
+
{ id: "maintenance", title: "Maintenance", entries: ["stop"] },
|
|
1368
1376
|
{ id: "recovery", title: "Recovery", entries: ["reconcile"] }
|
|
1369
1377
|
],
|
|
1370
1378
|
children: globalSessionChildren
|
package/dist/cli.js
CHANGED
|
@@ -28,7 +28,7 @@ import { CONFIG_DOMAINS } from "./config/configCatalog.js";
|
|
|
28
28
|
import { runConfigOverview } from "./commands/configOverview.js";
|
|
29
29
|
import { parseControllerCleanupOptions, parseControllerStatusOptions, parseControllerRuntimeSnapshot, renderControllerResourceStatus, renderRuntimeIdentitySection, summarizeDurablePhysicalMismatch, runInteractiveControllerCleanup } from "./commands/controllerCommands.js";
|
|
30
30
|
import { parseExecutionAuditOptions, runExecutionAuditCommand } from "./commands/executionAuditCommands.js";
|
|
31
|
-
import { parseSessionReconcileOptions, runSessionReconcileCommand } from "./commands/sessionCommands.js";
|
|
31
|
+
import { parseSessionReconcileOptions, parseSessionStopOptions, runSessionReconcileCommand, runSessionStopCommand } from "./commands/sessionCommands.js";
|
|
32
32
|
import { SessionOwnerReconciliation } from "./controller/sessionOwnerReconciliation.js";
|
|
33
33
|
import { runJobCommand } from "./commands/jobCommands.js";
|
|
34
34
|
import { runDurableJobCommand } from "./commands/durableJobCommands.js";
|
|
@@ -667,6 +667,31 @@ export async function main() {
|
|
|
667
667
|
return;
|
|
668
668
|
}
|
|
669
669
|
if (resolved[0] === "session") {
|
|
670
|
+
if (resolved[1] === "stop") {
|
|
671
|
+
const options = parseSessionStopOptions(resolved.slice(2));
|
|
672
|
+
const result = await runSessionStopCommand({
|
|
673
|
+
options,
|
|
674
|
+
runtime: {
|
|
675
|
+
beginMaintenance: () => acquireHandoverLock(home),
|
|
676
|
+
snapshot: () => ({
|
|
677
|
+
candidates: schedulerStore.listRuntimeSessionCandidates(),
|
|
678
|
+
dormant: schedulerStore.listDormantRuntimeOwners()
|
|
679
|
+
}),
|
|
680
|
+
drainController: () => runtime.drainController(),
|
|
681
|
+
stopController: () => stopFileTaskController(home, {
|
|
682
|
+
environment: process.env
|
|
683
|
+
}),
|
|
684
|
+
startController: async () => {
|
|
685
|
+
await ensureFileTaskController(home, { environment: process.env });
|
|
686
|
+
},
|
|
687
|
+
stopDormantSession: (candidate) => runtime.stopDormantSession(candidate)
|
|
688
|
+
},
|
|
689
|
+
environment: process.env
|
|
690
|
+
});
|
|
691
|
+
process.exitCode = result.exitCode;
|
|
692
|
+
emit(result.output, false, result.data);
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
670
695
|
const roleOptions = {
|
|
671
696
|
yuiHome: home,
|
|
672
697
|
env: process.env,
|
|
@@ -1844,36 +1869,6 @@ async function prepareReviewLaneWorkspaces(taskId, reviewRoundId, store, prepare
|
|
|
1844
1869
|
return map;
|
|
1845
1870
|
}
|
|
1846
1871
|
async function directTaskMainSnapshotForTaskCommand(args, store, preparer, environment, taskFinalReviewContract) {
|
|
1847
|
-
const deliveryOption = args.indexOf("--delivery", 3);
|
|
1848
|
-
const deliveryPromotion = args[0] === "task"
|
|
1849
|
-
&& args[1] === "update"
|
|
1850
|
-
&& args[2] !== undefined
|
|
1851
|
-
&& (args.includes("--require-integration", 3)
|
|
1852
|
-
|| (deliveryOption >= 0 && args[deliveryOption + 1] === "integrated"));
|
|
1853
|
-
if (deliveryPromotion) {
|
|
1854
|
-
const task = store.getTask(args[2]);
|
|
1855
|
-
if (task === null
|
|
1856
|
-
|| (task.status !== "active" && task.status !== "draft")
|
|
1857
|
-
|| task.requireIntegration === true
|
|
1858
|
-
|| task.projectBindings.length === 0) {
|
|
1859
|
-
return undefined;
|
|
1860
|
-
}
|
|
1861
|
-
const workspace = store.getTaskWorkspace(task.id);
|
|
1862
|
-
if (task.status === "draft" && workspace === null)
|
|
1863
|
-
return undefined;
|
|
1864
|
-
if (workspace === null
|
|
1865
|
-
|| workspace.owner.type !== "task"
|
|
1866
|
-
|| workspace.owner.taskId !== task.id) {
|
|
1867
|
-
throw usageError(`Task has no authoritative main workspace: ${task.id}.`);
|
|
1868
|
-
}
|
|
1869
|
-
try {
|
|
1870
|
-
return await preparer.snapshotDirectTaskMain(workspace, task.projectBindings.map(({ projectId }) => projectId));
|
|
1871
|
-
}
|
|
1872
|
-
catch (error) {
|
|
1873
|
-
throw usageError(`Delivery promotion Task-main verification failed for ${task.id}: `
|
|
1874
|
-
+ `${error instanceof Error ? error.message : String(error)}`);
|
|
1875
|
-
}
|
|
1876
|
-
}
|
|
1877
1872
|
if (taskFinalReviewContract === undefined
|
|
1878
1873
|
|| args[0] !== "task"
|
|
1879
1874
|
|| args[1] !== "work"
|
|
@@ -1913,7 +1908,7 @@ async function actualTaskReviewCandidateForTaskCommand(args, store, preparer, en
|
|
|
1913
1908
|
if (task === null || task.status !== "active" || task.projectBindings.length === 0) {
|
|
1914
1909
|
return undefined;
|
|
1915
1910
|
}
|
|
1916
|
-
// Every Project-backed completion
|
|
1911
|
+
// Every Project-backed completion must freeze
|
|
1917
1912
|
// a clean committed Task-main snapshot. Review policy only decides whether
|
|
1918
1913
|
// that head also needs an independent ReviewRound.
|
|
1919
1914
|
taskId = task.id;
|
|
@@ -219,7 +219,7 @@ export function renderExecutionAudit(report, width = defaultTableWidth()) {
|
|
|
219
219
|
if (orchestration.tasks.length > 0) {
|
|
220
220
|
lines.push(renderTable("Task orchestration metrics", [
|
|
221
221
|
{ header: "Task", minWidth: 7, maxWidth: 14 },
|
|
222
|
-
{ header: "
|
|
222
|
+
{ header: "Type", minWidth: 8, maxWidth: 12 },
|
|
223
223
|
{ header: "Runs", minWidth: 4, maxWidth: 6 },
|
|
224
224
|
{ header: "WIs", minWidth: 3, maxWidth: 5 },
|
|
225
225
|
{ header: "Review F/D/N", minWidth: 12, maxWidth: 16 },
|
|
@@ -229,7 +229,7 @@ export function renderExecutionAudit(report, width = defaultTableWidth()) {
|
|
|
229
229
|
{ header: "Advice", minWidth: 6, maxWidth: 8 }
|
|
230
230
|
], orchestration.tasks.map((task) => [
|
|
231
231
|
task.taskId,
|
|
232
|
-
task.
|
|
232
|
+
task.taskType ?? "unspecified",
|
|
233
233
|
String(task.runs.total),
|
|
234
234
|
String(task.workItems),
|
|
235
235
|
`${task.reviews.full}/${task.reviews.delta}/${task.reviews.nonSemantic}`,
|
|
@@ -198,7 +198,6 @@ function updateRole(args, store, options) {
|
|
|
198
198
|
if (changesAgentConfig) {
|
|
199
199
|
const agentId = parsed.one("--agent")?.trim() || role.activeAgentId;
|
|
200
200
|
const agent = requireAgent(agentId, tx);
|
|
201
|
-
assertOperatorAdapterAvailable(role, agent);
|
|
202
201
|
const binding = role.agentBindings[agentId] ?? createRoleAgentBinding(definition(agent));
|
|
203
202
|
bindings = { ...role.agentBindings, [agentId]: patchRoleAgentBinding(binding, parsed) };
|
|
204
203
|
}
|
|
@@ -231,7 +230,6 @@ function bindRole(args, store) {
|
|
|
231
230
|
roleName: role.name
|
|
232
231
|
}, "desired Agent binding update");
|
|
233
232
|
const agent = requireAgent(agentId, tx);
|
|
234
|
-
assertOperatorAdapterAvailable(role, agent);
|
|
235
233
|
const binding = role.agentBindings[agentId] ?? createRoleAgentBinding(definition(agent));
|
|
236
234
|
const withBinding = updateGlobalRole(role, {
|
|
237
235
|
agentBindings: { ...role.agentBindings, [agentId]: binding }
|
|
@@ -260,16 +258,6 @@ function bindRole(args, store) {
|
|
|
260
258
|
});
|
|
261
259
|
return presentRole(result.message, result.role, store);
|
|
262
260
|
}
|
|
263
|
-
function assertOperatorAdapterAvailable(role, agent) {
|
|
264
|
-
if (role.name !== "operator" || Object.hasOwn(role.agentBindings, agent.id))
|
|
265
|
-
return;
|
|
266
|
-
const existing = Object.values(role.agentBindings).find((binding) => binding.adapterId === agent.adapterId);
|
|
267
|
-
if (existing !== undefined) {
|
|
268
|
-
throw usageError(`Operator already has a ${agent.adapterId} Agent: ${existing.agentId}. `
|
|
269
|
-
+ "Update that Agent's configuration, or activate another adapter and "
|
|
270
|
-
+ "unbind it before binding this Agent.");
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
261
|
function removeRole(args, store) {
|
|
274
262
|
const [rawName, ...rest] = args;
|
|
275
263
|
const name = roleName(rawName);
|