@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.
Files changed (193) hide show
  1. package/ARCHITECTURE.md +12 -0
  2. package/ARCHITECTURE.zh-CN.md +8 -0
  3. package/README.md +9 -4
  4. package/dist/agent/agent.js +4 -9
  5. package/dist/agent/executionComponents.js +4 -4
  6. package/dist/agent/managedRuntimeEnvironment.js +0 -4
  7. package/dist/agentRun/agentRun.js +13 -23
  8. package/dist/artifacts/managedGit.js +3 -56
  9. package/dist/brief/taskBrief.js +3 -3
  10. package/dist/cli/agentConfigurationPicker.js +24 -21
  11. package/dist/cli/commandCatalog.js +18 -10
  12. package/dist/cli/roleWizard.js +41 -30
  13. package/dist/cli/updateCommand.js +35 -13
  14. package/dist/cli/updateOrchestrator.js +73 -44
  15. package/dist/cli/updatePorts.js +76 -86
  16. package/dist/cli/upgradeCommand.js +4 -8
  17. package/dist/cli.js +39 -33
  18. package/dist/commands/controllerCommands.js +2 -2
  19. package/dist/commands/executionAuditCommands.js +2 -2
  20. package/dist/commands/projectCommands.js +1 -1
  21. package/dist/commands/releaseCommands.js +9 -38
  22. package/dist/commands/taskCommands.js +91 -81
  23. package/dist/commands/taskCompletionGate.js +0 -117
  24. package/dist/commands/taskRoleRuntimeStatus.js +2 -2
  25. package/dist/commands/taskUpstreamCommands.js +93 -54
  26. package/dist/context/runContextPack.js +30 -54
  27. package/dist/context/runInputContract.js +9 -0
  28. package/dist/context/sessionBootstrapManifest.js +11 -19
  29. package/dist/controller/agentHostObservation.js +4 -2
  30. package/dist/controller/agentRuntimeObserver.js +4 -4
  31. package/dist/controller/clientRuntime.js +19 -44
  32. package/dist/controller/controller.js +24 -10
  33. package/dist/controller/fileSchedulerStoreAdapter.js +91 -24
  34. package/dist/controller/globalInputDelivery.js +31 -8
  35. package/dist/controller/globalRuntimeAttention.js +34 -0
  36. package/dist/controller/jobSupervisor.js +3 -3
  37. package/dist/controller/operatorNotification.js +31 -0
  38. package/dist/controller/providerRetryAdmission.js +3 -1
  39. package/dist/controller/providerRetryDelivery.js +136 -119
  40. package/dist/controller/runtime.js +2 -28
  41. package/dist/controller/sessionOwnerReconciliation.js +42 -24
  42. package/dist/controller/structuredProviderObservation.js +28 -1
  43. package/dist/controller/updateReconciliation.js +72 -20
  44. package/dist/coordination/workMailbox.js +4 -4
  45. package/dist/core/controllerIdentity.js +25 -0
  46. package/dist/core/controllerProcessIdentity.js +2 -2
  47. package/dist/core/controllerServer.js +4 -2
  48. package/dist/core/protocol.js +1 -1
  49. package/dist/doctor/doctor.js +2 -1
  50. package/dist/domain/validation.js +6 -0
  51. package/dist/event/taskEvent.js +3 -3
  52. package/dist/execution/workItemExecution.js +2 -2
  53. package/dist/executor/agentAdapter.js +28 -96
  54. package/dist/executor/agentConfigurationCatalog.js +13 -68
  55. package/dist/executor/agentConfigurationFields.js +120 -0
  56. package/dist/executor/agentConfigurationProbe.js +55 -80
  57. package/dist/executor/agentExecutor.js +11 -8
  58. package/dist/executor/effectiveLaunch.js +3 -3
  59. package/dist/executor/executorRegistry.js +0 -9
  60. package/dist/executor/fileRoleLaunchPlanner.js +12 -11
  61. package/dist/grant/capabilityGrant.js +2 -2
  62. package/dist/input/inputRequest.js +4 -4
  63. package/dist/integration/changeSet.js +3 -3
  64. package/dist/integration/integrationAttempt.js +3 -3
  65. package/dist/integration/integrationSourceApplication.js +1 -1
  66. package/dist/interaction/operatorPresentation.js +2 -1
  67. package/dist/job/durableJob.js +1 -1
  68. package/dist/job/jobRunner.js +2 -2
  69. package/dist/message/message.js +8 -6
  70. package/dist/message/messageContinuation.js +8 -9
  71. package/dist/milestone/milestone.js +3 -3
  72. package/dist/observability/executionAudit.js +1 -10
  73. package/dist/observability/runtimeIdentity.js +0 -23
  74. package/dist/output/agentConfigurationPresentation.js +4 -2
  75. package/dist/profile/agentProfile.js +3 -3
  76. package/dist/release/releaseHandover.js +2 -2
  77. package/dist/release/releaseIdempotencyStore.js +0 -23
  78. package/dist/release/releaseWorkflowPorts.js +8 -4
  79. package/dist/release/runtimeRelease.js +9 -7
  80. package/dist/repository/gitWorkspace.js +66 -19
  81. package/dist/repository/project.js +3 -3
  82. package/dist/repository/taskWorkspacePreparer.js +75 -68
  83. package/dist/resources/liveReferences.js +1 -1
  84. package/dist/resources/resourceRegistry.js +90 -44
  85. package/dist/resources/sqliteResourceRegistry.js +5 -7
  86. package/dist/review/reviewRound.js +5 -5
  87. package/dist/role/role.js +7 -8
  88. package/dist/runtime/acpProtocol.js +2 -3
  89. package/dist/runtime/acpSession.js +21 -5
  90. package/dist/runtime/agentDriverObservation.js +1 -1
  91. package/dist/runtime/agentEndpoint.js +4 -1
  92. package/dist/runtime/agentHost.js +25 -65
  93. package/dist/runtime/agentHostCleanup.js +85 -0
  94. package/dist/runtime/agentHostProtocol.js +3 -3
  95. package/dist/runtime/builtinAgentDrivers.js +46 -119
  96. package/dist/runtime/builtinTranscriptObserver.js +10 -6
  97. package/dist/runtime/codexAppServerRuntime.js +55 -89
  98. package/dist/runtime/codexInteractiveHost.js +1 -1
  99. package/dist/runtime/jsonLineChannel.js +35 -7
  100. package/dist/runtime/launchBroker.js +1 -1
  101. package/dist/runtime/processExitObservation.js +1 -1
  102. package/dist/runtime/providerContinuationReconciliationService.js +86 -38
  103. package/dist/runtime/providerRetry.js +15 -0
  104. package/dist/runtime/providerRuntimeIdentity.js +3 -3
  105. package/dist/runtime/providerRuntimeReconciler.js +12 -2
  106. package/dist/runtime/runtimeCoherence.js +7 -3
  107. package/dist/runtime/runtimeObservation.js +3 -3
  108. package/dist/runtime/sessionOwnerIdentity.js +1 -1
  109. package/dist/runtime/structuredProviderHost.js +106 -81
  110. package/dist/runtime/taskRuntimeIsolation.js +3 -3
  111. package/dist/runtime/tmuxAdapters.js +3 -3
  112. package/dist/scheduler/activeRoleRunDelivery.js +5 -1
  113. package/dist/scheduler/operatorInputNotificationProcessor.js +7 -17
  114. package/dist/scheduler/taskWake.js +1 -1
  115. package/dist/storage/baselineSchema.js +606 -0
  116. package/dist/storage/homeLayout.js +5 -16
  117. package/dist/storage/recordValidation.js +16 -4
  118. package/dist/storage/sqliteSchema.js +106 -1741
  119. package/dist/storage/sqliteStore.js +16 -14
  120. package/dist/storage/storageSchema.js +8 -7
  121. package/dist/storage/storageVersions.js +23 -16
  122. package/dist/storage/taskStore.js +3 -29
  123. package/dist/storage/upgrade/upgradeOrchestrator.js +14 -112
  124. package/dist/task/nextAction.js +33 -23
  125. package/dist/task/task.js +17 -8
  126. package/dist/task/taskActivation.js +5 -4
  127. package/dist/telemetry/sqliteTelemetryStore.js +2 -2
  128. package/dist/verification/gateArtifact.js +5 -3
  129. package/dist/verification/verificationPlan.js +6 -7
  130. package/dist/web/assets/assetManifest.js +2 -0
  131. package/dist/web/assets/client/app.js +72 -3
  132. package/dist/web/assets/client/components.js +2 -1
  133. package/dist/web/assets/client/i18n.js +2 -0
  134. package/dist/web/assets/client/taskSummary.js +345 -0
  135. package/dist/web/assets/client/taskSurface.js +44 -26
  136. package/dist/web/assets/client/view.js +33 -0
  137. package/dist/web/assets/shell.js +1 -0
  138. package/dist/web/assets/styles/cards.js +21 -0
  139. package/dist/web/webServer.js +39 -5
  140. package/dist/web/webSessions.js +165 -0
  141. package/dist/web/webSnapshot.js +23 -0
  142. package/dist/web/webTaskSurface.js +23 -0
  143. package/dist/workItem/workItem.js +6 -6
  144. package/dist/workspace/cleanupInspection.js +1 -9
  145. package/dist/worktree/managedWorkspace.js +3 -3
  146. package/docs/managed-turn-and-session-runtime.md +50 -7
  147. package/docs/managed-turn-and-session-runtime.zh-CN.md +36 -5
  148. package/docs/observability/README.md +47 -0
  149. package/docs/observability/README.zh-CN.md +37 -0
  150. package/docs/project-refresh.md +9 -0
  151. package/docs/project-refresh.zh-CN.md +8 -0
  152. package/docs/provider-retry.md +35 -0
  153. package/docs/release-workflow.md +70 -214
  154. package/docs/release-workflow.zh-CN.md +53 -157
  155. package/docs/roles-and-configuration.md +30 -0
  156. package/docs/roles-and-configuration.zh-CN.md +20 -0
  157. package/docs/sqlite-control-plane-design.md +48 -289
  158. package/docs/sqlite-control-plane-design.zh-CN.md +37 -53
  159. package/docs/storage-baseline.md +132 -0
  160. package/docs/storage-baseline.zh-CN.md +106 -0
  161. package/docs/task-delivery.md +110 -2
  162. package/docs/task-delivery.zh-CN.md +82 -2
  163. package/docs/task-discovery.md +9 -0
  164. package/docs/task-discovery.zh-CN.md +6 -0
  165. package/docs/testing/verification-levels.md +42 -164
  166. package/docs/testing/verification-levels.zh-CN.md +29 -115
  167. package/i18n/README.zh-CN.md +7 -4
  168. package/package.json +1 -1
  169. package/skills/yui-leader/SKILL.md +11 -0
  170. package/skills/yui-leader/references/execution.md +22 -0
  171. package/skills/yui-leader/references/planning.md +6 -2
  172. package/skills/yui-operator/SKILL.md +45 -13
  173. package/skills/yui-operator/references/task-delivery.md +99 -0
  174. package/skills/yui-runtime/SKILL.md +5 -3
  175. package/skills/yui-runtime/references/publication.md +56 -5
  176. package/skills/yui-runtime/references/recovery.md +12 -2
  177. package/dist/runtime/agentHostCompatibility.js +0 -127
  178. package/dist/storage/migrations/agentFailureContext.js +0 -22
  179. package/dist/storage/migrations/agentRunContract.js +0 -159
  180. package/dist/storage/migrations/artifactsToGit.js +0 -338
  181. package/dist/storage/migrations/collapseWorktreeLayout.js +0 -963
  182. package/dist/storage/migrations/currentInputContract.js +0 -86
  183. package/dist/storage/migrations/currentRuntimeContract.js +0 -228
  184. package/dist/storage/migrations/historicalVerificationPlan.js +0 -35
  185. package/dist/storage/migrations/integrationContinuation.js +0 -105
  186. package/dist/storage/migrations/narrowAgentFailureContext.js +0 -65
  187. package/dist/storage/migrations/notificationOnlyWakes.js +0 -74
  188. package/dist/storage/migrations/removeRuntimeGeneration.js +0 -207
  189. package/dist/storage/migrations/submitIntent.js +0 -126
  190. package/dist/storage/migrations/unifyHomeLayout.js +0 -925
  191. package/dist/storage/migrations/verificationPlanV1.js +0 -162
  192. package/dist/storage/migrations/verificationPolicy.js +0 -74
  193. package/dist/storage/migrations/workItemHistory.js +0 -46
package/ARCHITECTURE.md CHANGED
@@ -67,6 +67,18 @@ AgentHost serializes submission through AgentEndpoint. The Provider binding
67
67
  records actual acceptance and native correlation. A notification can settle
68
68
  on acceptance without requiring a final execution report.
69
69
 
70
+ Operator attention has a separate, local handoff boundary: one transaction
71
+ saves the exact batch as a Global system Message and consumes only that mailbox
72
+ claim. `queued` (with the Message id) means durable queue ownership, not Provider
73
+ acceptance or Agent processing. Later events form a new batch without repeating
74
+ the handed-off refs. Global Messages alone own subsequent native delivery,
75
+ including rejection, unknown acceptance and Session-target mismatch; none causes
76
+ automatic reissuance under a different key. A pass can mark multiple definitively
77
+ unsent stale-target entries undelivered before reaching successor input, but never
78
+ bypass an uncertain attempt or an interrupt-then reservation. Original Messages
79
+ and source Task/Input/Event records remain inspectable. Notifications ask Agents
80
+ to reread facts; they do not authorize replaying prior operations.
81
+
70
82
  Busy with proven non-acceptance preserves the input for a subsequent attempt.
71
83
  Transport submission alone does not prove acceptance. Unknown effects remain
72
84
  visible and fenced: no blind resend or inferred success. Explicit replacement
@@ -53,6 +53,14 @@ AgentRun 记录一次明确请求的执行,带有冻结的 Context 和生效
53
53
  mailbox 批次;AgentHost 通过 AgentEndpoint 串行化提交。Provider 绑定记录实际接受和原生
54
54
  关联。一条通知可以在接受时结算,而不要求最终执行报告。
55
55
 
56
+ Operator attention 有独立的本地交接边界:同一事务把精确批次保存为 Global 系统 Message,
57
+ 并且只消费该 mailbox claim。`queued`(带 Message id)表示持久队列已接管,不代表 Provider
58
+ 接受或 Agent 已处理。后到事件形成新批次,不重复已经交出的 refs。后续原生投递仅由
59
+ Global Message 负责,包括拒绝、接受结果未知和 Session 目标失效;这些结果都不会自动换键
60
+ 重发。一轮可将多个已明确未提交且目标失效的条目标为未投递,再处理后继输入,但不能越过
61
+ 不确定尝试或 interrupt-then 预约。原始 Message 和来源 Task/Input/Event 仍可查阅。通知
62
+ 只要求 Agent 重读事实,不授予重放先前操作的权限。
63
+
56
64
  忙碌且已证明未接受会为后续尝试保留输入。仅有传输提交不证明接受。未知效果保持可见且被
57
65
  围栏隔离:不盲目重发,也不推断成功。显式替换先解决实际的原生执行,再丢弃其工程占用。
58
66
  在一个已认领批次期间到达的输入,留待下一个批次。读取 Context 不消费投递。
package/README.md CHANGED
@@ -34,8 +34,9 @@ not from terminal windows you juggle or details you have to remember.
34
34
  - **Isolated by default** — repository work happens in managed Git worktrees;
35
35
  the stable checkout stays read-only.
36
36
 
37
- > **Status:** pre-1.0 (0.15.x). CLI surfaces and configuration may still change
38
- > between releases; each upgrade migrates valid existing Homes.
37
+ > **Status:** 1.0.0-alpha, with a clean storage 1.0 baseline. Default updates
38
+ > support only declared minor upgrades within one storage major. Existing v37
39
+ > Homes require the separate [one-time conversion](docs/storage-baseline.md).
39
40
 
40
41
  [Quick start](#quick-start) · [Working through conversation](#working-through-conversation) · [Architecture](#architecture) · [Design principles](#design-principles)
41
42
 
@@ -140,6 +141,9 @@ For a visual overview, run `yui web` in another terminal. The local Web view
140
141
  shows the same tasks and pending questions and lets you send messages, answer
141
142
  questions and explicitly queue, steer or interrupt Task input. These authenticated
142
143
  Task controls use the same operations as the CLI; Web is not a separate task system.
144
+ The detail prioritizes user input, native Session activity, Task progress and key
145
+ conclusions; fixed file results and delivery evidence open on demand. See
146
+ [attention and progress](docs/observability/README.md#web-attention-and-progress).
143
147
  See [Web permissions](docs/architecture/capabilities-and-resources.md#cli-and-web)
144
148
  and [input timing](docs/managed-turn-and-session-runtime.md#input-timing-queue-steer-and-interrupt).
145
149
 
@@ -380,8 +384,9 @@ npm users do not need to compile it.
380
384
 
381
385
  To exercise your checkout, run `make install-local`, then use the absolute
382
386
  `<checkout>/output/dev/bin/yui` launcher. It defaults to an isolated Home under
383
- that checkout; run its `setup` before stateful use. Do not use the global `yui`
384
- or `make link` to validate local changes. Live-model, paid or shared-resource
387
+ that checkout; run its `setup` before stateful use. Development tooling does not
388
+ manage global installations; do not use the global `yui` to validate local changes.
389
+ Live-model, paid or shared-resource
385
390
  tests require an explicit request for those resources.
386
391
 
387
392
  ## Community and support
@@ -9,7 +9,7 @@ export function createConfiguredAgent(id, adapterId, command, baseArgs, environm
9
9
  validateAgentBaseArguments(adapterId, baseArgs);
10
10
  const timestamp = now.toISOString();
11
11
  return {
12
- schemaVersion: 3,
12
+ schemaVersion: 1,
13
13
  id: normalizedId,
14
14
  // An unnamed component resolves from the plan, which for ACP means the
15
15
  // unidentified entry rather than a guess at which product is installed.
@@ -45,18 +45,13 @@ export function resolveAgentEnvironment(agent, processEnvironment = process.env)
45
45
  }));
46
46
  }
47
47
  export function validateConfiguredAgent(agent) {
48
- if (agent.schemaVersion !== 3)
48
+ if (agent.schemaVersion !== 1)
49
49
  throw new Error("Agent schema version is invalid.");
50
50
  requireSafeIdentity(agent.id, "Agent id");
51
51
  if (!isAgentAdapterId(agent.adapterId))
52
52
  throw new Error(`Agent adapter is unsupported: ${agent.adapterId}.`);
53
- // A schema 3 record always carries a component: storage 10 backfilled every
54
- // stored Agent, and the constructor resolves one for every new Agent. So an
55
- // absent value here is a corrupt record, not an old one, and resolving it to
56
- // the plan default would invent a product identity for data that never lost
57
- // one. That default belongs to the constructor, where an operator naming
58
- // only a plan is a real and supported request — this validator reads records
59
- // that were already written, where the same silence means something else.
53
+ // Creation resolves an omitted component before persistence. Reading a
54
+ // stored record must not invent a missing product identity.
60
55
  if (agent.component === undefined) {
61
56
  throw new Error(`Agent is missing its execution component: ${agent.id}.`);
62
57
  }
@@ -138,10 +138,10 @@ export function displayExecutionComponent(adapterId, componentId) {
138
138
  /**
139
139
  * Resolve the component for a connection plan, given what the caller stated.
140
140
  *
141
- * An absent component is not an error: it means the caller named only the plan,
142
- * which is how every binding made before this axis existed reads. It resolves
143
- * to the plan's default, which for ACP is the unidentified entry — the value is
144
- * never inferred from a command, an argument or an environment variable.
141
+ * Creation may name only a connection plan. Resolve its default before
142
+ * persistence; current stored Agents and bindings require an explicit component.
143
+ * ACP defaults to the unidentified entry, never a product inferred from command,
144
+ * arguments or environment.
145
145
  */
146
146
  export function resolveAgentExecutionComponent(adapterId, componentId) {
147
147
  if (componentId === undefined)
@@ -19,10 +19,6 @@ export const YUI_MANAGED_RUNTIME_ENVIRONMENT_NAMES = Object.freeze([
19
19
  "YUI_RUN_ID",
20
20
  "YUI_NATIVE_SESSION_ROOT",
21
21
  "YUI_NATIVE_SESSION_ID",
22
- // Retired: Yui no longer publishes a frozen control-plane descriptor into a
23
- // managed process. Sessions launched by an earlier release still carry it, so
24
- // it stays in this sanitize list.
25
- "YUI_CONTROL_PLANE_DESCRIPTOR",
26
22
  "YUI_TASK_RUNTIME_ISOLATION_DESCRIPTOR",
27
23
  "YUI_TASK_RUNTIME_SERVICE_NAMESPACE",
28
24
  "YUI_SESSION_TITLE",
@@ -1,7 +1,7 @@
1
1
  import { validateEffectiveLaunchSnapshot } from "../executor/effectiveLaunch.js";
2
2
  import { validateTaskRecordReference } from "../task/taskRecordReference.js";
3
3
  import { validateManagedWorkspace } from "../worktree/managedWorkspace.js";
4
- import { createRunInput, createRunInputEnvelope, validateRunInput } from "../context/runInputContract.js";
4
+ import { createRunInputEnvelope, requireRunContextSnapshotRef, validateRunInput } from "../context/runInputContract.js";
5
5
  import { providerRetryProjection } from "../runtime/providerRetry.js";
6
6
  import { boundedRunFailureDiagnostic, MAX_RUN_FAILURE_DIAGNOSTIC_BYTES, MAX_RUN_RESULT_OUTPUT_BYTES } from "../domain/agentResultTransport.js";
7
7
  export { boundedRunFailureDiagnostic, MAX_RUN_FAILURE_DIAGNOSTIC_BYTES, MAX_RUN_RESULT_OUTPUT_BYTES, transportAgentResult } from "../domain/agentResultTransport.js";
@@ -32,8 +32,11 @@ export function createRun(id, taskId, roleName, mode, input, now, context) {
32
32
  }
33
33
  const timestamp = now.toISOString();
34
34
  const normalizedInput = validateRunInput(input);
35
+ const snapshot = requireRunContextSnapshotRef(normalizedInput);
36
+ if (snapshot.taskId !== taskId)
37
+ throw new Error("AgentRun Context Snapshot belongs to another Task.");
35
38
  return {
36
- schemaVersion: 5,
39
+ schemaVersion: 1,
37
40
  id: requireSafeIdentity(id, "AgentRun id"),
38
41
  taskId: requireSafeIdentity(taskId, "Task id"),
39
42
  roleName: requireSafeIdentity(roleName, "Role name"),
@@ -85,22 +88,6 @@ export function runPurposeAdmitsTaskState(purpose, task) {
85
88
  ? task.status === "draft" || task.status === "active"
86
89
  : task.status === "active";
87
90
  }
88
- /** Binds a freshly created, not-yet-persisted Turn to its frozen Context. */
89
- export function withRunContextSnapshot(run, snapshot, deltaRefIds = []) {
90
- const initial = run.inputs[0];
91
- if (run.status !== "active" || initial.input.contextSnapshotRef !== undefined) {
92
- throw new Error(`Cannot replace the AgentRun Context Snapshot: ${run.id}.`);
93
- }
94
- const input = createRunInput({
95
- ...initial.input,
96
- contextSnapshotRef: snapshot,
97
- deltaRefIds
98
- });
99
- return validateRun(Object.freeze({
100
- ...run,
101
- inputs: [runInputRecord(input, 1, initial.submittedAt), ...run.inputs.slice(1)]
102
- }));
103
- }
104
91
  export function appendRunInput(run, input, now) {
105
92
  validateRun(run);
106
93
  if (run.status !== "active")
@@ -118,6 +105,7 @@ export function appendRunInput(run, input, now) {
118
105
  /** Derives Provider-visible identity from the AgentRun, the sole semantic owner. */
119
106
  export function runInputEnvelope(run, sequence = 1) {
120
107
  validateRun(run);
108
+ requireRunContextSnapshotRef(run.inputs[0].input);
121
109
  const record = run.inputs[sequence - 1];
122
110
  if (record === undefined)
123
111
  throw new Error(`AgentRun input does not exist: ${run.id}/${sequence}.`);
@@ -144,8 +132,8 @@ export function validateRun(run) {
144
132
  "createdAt",
145
133
  "updatedAt"
146
134
  ], "AgentRun");
147
- if (run.schemaVersion !== 5)
148
- throw new Error("AgentRun must use schemaVersion 5.");
135
+ if (run.schemaVersion !== 1)
136
+ throw new Error("AgentRun must use schemaVersion 1.");
149
137
  validateTaskRecordReference({ taskId: run.taskId, localId: run.id }, "run");
150
138
  requireSafeIdentity(run.roleName, "Role name");
151
139
  if (run.mode !== "new" && run.mode !== "resume") {
@@ -295,6 +283,8 @@ export function validateRun(run) {
295
283
  throw new Error("Execution AgentRun cannot carry Review effective provenance.");
296
284
  }
297
285
  for (const record of run.inputs) {
286
+ // Validate readable evidence, not readiness to execute. A missing Snapshot
287
+ // must still allow inspection, failure settlement and explicit retirement.
298
288
  createRunInputEnvelope(runEnvelopeContext(run), record.input);
299
289
  }
300
290
  if (!["active", "completed", "failed"].includes(run.status)) {
@@ -345,7 +335,7 @@ function finishRun(run, status, output, now, failureReason, provider, systemEvid
345
335
  ...run,
346
336
  status,
347
337
  result: {
348
- schemaVersion: 2,
338
+ schemaVersion: 1,
349
339
  ...(output === undefined ? {} : { output: requireResultText(output, "AgentRun result output") }),
350
340
  ...(diagnostic === undefined
351
341
  ? {}
@@ -362,8 +352,8 @@ function finishRun(run, status, output, now, failureReason, provider, systemEvid
362
352
  return validateRun(terminal);
363
353
  }
364
354
  function validateRunResult(result) {
365
- if (result === undefined || result.schemaVersion !== 2) {
366
- throw new Error("A terminal AgentRun requires AgentRunResult schemaVersion 2.");
355
+ if (result === undefined || result.schemaVersion !== 1) {
356
+ throw new Error("A terminal AgentRun requires AgentRunResult schemaVersion 1.");
367
357
  }
368
358
  rejectUnknownFields(result, [
369
359
  "schemaVersion",
@@ -1,4 +1,4 @@
1
- import { execFile, execFileSync } from "node:child_process";
1
+ import { execFile } from "node:child_process";
2
2
  import { promisify } from "node:util";
3
3
  const executeFile = promisify(execFile);
4
4
  /**
@@ -259,8 +259,8 @@ function isExternalProgramConfigKey(key) {
259
259
  * list of repo-local keys that can execute an external program. Empty means the
260
260
  * repository's own config is within the managed boundary.
261
261
  *
262
- * PURE: no I/O. Callers (sync migration and async runtime) read the config with
263
- * their own managed runner and pass the bytes here, so the security policy lives
262
+ * PURE: no I/O. Callers read the config with the managed runner and pass the
263
+ * bytes here, so the security policy lives
264
264
  * in exactly one testable place. Reading `--local` deliberately excludes the
265
265
  * command-line `-c` hardening flags (which are safe and not persisted) and the
266
266
  * null-device'd global/system config; it sees only what is written in the repo.
@@ -277,56 +277,3 @@ export function externalProgramConfigViolations(localConfigListZ) {
277
277
  }
278
278
  return [...offending].sort();
279
279
  }
280
- /**
281
- * SYNCHRONOUS managed invocation, used ONLY where an async runner is
282
- * structurally impossible: a storage `migrateData(db)` step runs inside
283
- * `db.transaction(...)`, which better-sqlite3 requires to be synchronous, yet
284
- * the 18->19 migration must build per-Task artifact repositories on disk. This
285
- * shares the SAME hardening as {@link spawnManagedGit} — identical argument
286
- * refusal, identical scrubbed environment, identical prepended flags — so the
287
- * synchronous path never weakens the trust boundary. It is not exported for
288
- * ordinary runtime use; the async runner remains the only production write path.
289
- */
290
- function spawnManagedGitSync(repoPath, args, options) {
291
- assertSafeArguments(args);
292
- const env = managedGitEnvironment();
293
- if (options?.commitDates !== undefined) {
294
- // Deterministic history: fixed author/committer dates make a rebuild of the
295
- // same source data reproduce the same commit ids. This only sets metadata.
296
- env.GIT_AUTHOR_DATE = options.commitDates.author;
297
- env.GIT_COMMITTER_DATE = options.commitDates.committer;
298
- }
299
- try {
300
- const stdout = execFileSync("git", [...HARDENING_FLAGS, "-C", repoPath, ...args], {
301
- encoding: "buffer",
302
- env,
303
- maxBuffer: options?.maxBuffer ?? 16 * 1024 * 1024,
304
- timeout: options?.timeoutMs ?? 30_000,
305
- windowsHide: true
306
- });
307
- return { stdout: stdout, stderr: Buffer.alloc(0) };
308
- }
309
- catch (error) {
310
- throw new ManagedGitError([...args], readErrorStream(error), error);
311
- }
312
- }
313
- /** Synchronous counterpart to {@link managedGit}; returns trimmed UTF-8 stdout. */
314
- export function managedGitSync(repoPath, args, options) {
315
- return spawnManagedGitSync(repoPath, args, options).stdout.toString("utf8");
316
- }
317
- /** Synchronous counterpart to {@link managedGitBuffer}; returns raw stdout bytes. */
318
- export function managedGitSyncBuffer(repoPath, args, options) {
319
- return spawnManagedGitSync(repoPath, args, options).stdout;
320
- }
321
- /** Synchronous counterpart to {@link managedGitSucceeds}; never throws on non-zero exit. */
322
- export function managedGitSyncSucceeds(repoPath, args, options) {
323
- try {
324
- spawnManagedGitSync(repoPath, args, options);
325
- return true;
326
- }
327
- catch (error) {
328
- if (error instanceof ManagedGitError)
329
- return false;
330
- throw error;
331
- }
332
- }
@@ -1,6 +1,6 @@
1
1
  export function createTaskBrief(input, now) {
2
2
  return {
3
- schemaVersion: 2,
3
+ schemaVersion: 1,
4
4
  objective: requireText(input.objective, "Task objective"),
5
5
  boundaries: normalizeBoundaries(input.boundaries),
6
6
  technicalApproach: optionalText(input.technicalApproach, "Task technical approach"),
@@ -22,8 +22,8 @@ export function updateTaskBrief(brief, patch, updatedBy, now) {
22
22
  }, now);
23
23
  }
24
24
  export function validateTaskBrief(brief) {
25
- if (brief.schemaVersion !== 2) {
26
- throw new Error("Task Brief requires schemaVersion 2.");
25
+ if (brief.schemaVersion !== 1) {
26
+ throw new Error("Task Brief requires schemaVersion 1.");
27
27
  }
28
28
  if (!Array.isArray(brief.boundaries) || typeof brief.technicalApproach !== "string"
29
29
  || typeof brief.updatedAt !== "string" || !Number.isFinite(Date.parse(brief.updatedAt))) {
@@ -30,12 +30,11 @@ export async function selectAgentEffort(resolved, io, input) {
30
30
  }
31
31
  /** Select provider-native permission settings in the adapter's canonical shape. */
32
32
  export async function selectAgentPermission(resolved, io, current) {
33
+ renderResolutionNotice(resolved, io);
33
34
  const strategyField = configurationField(resolved.catalog, "permission.strategy");
34
- const strategyChoices = uniqueChoices(strategyField?.choices ?? [
35
- { value: "default", label: "default" },
36
- { value: "bypass", label: "bypass" },
37
- { value: "configured", label: "configured" }
38
- ], current.strategy);
35
+ if (strategyField?.reason !== undefined)
36
+ io.write(`${strategyField.reason}\n`);
37
+ const strategyChoices = uniqueChoices(strategyField?.available === false ? [] : strategyField?.choices ?? [], current.strategy);
39
38
  const strategy = await choose("Select permission strategy", strategyChoices.map(({ value, label, description }) => ({
40
39
  value,
41
40
  label,
@@ -67,6 +66,10 @@ export async function selectAgentPermission(resolved, io, current) {
67
66
  delete permission.approval;
68
67
  else
69
68
  permission.approval = approval.value;
69
+ if (permission.sandbox === undefined && permission.approval === undefined) {
70
+ io.write("Configured permission requires an explicit native option; configuration unchanged.\n");
71
+ return { kind: "cancelled" };
72
+ }
70
73
  return {
71
74
  kind: "selected",
72
75
  permission: permission
@@ -98,6 +101,11 @@ export async function selectAgentPermission(resolved, io, current) {
98
101
  delete permission.mode;
99
102
  else
100
103
  permission.mode = mode.value;
104
+ if (permission.mode === undefined && permission.allowedTools === undefined
105
+ && permission.disallowedTools === undefined) {
106
+ io.write("Configured permission requires an explicit native option; configuration unchanged.\n");
107
+ return { kind: "cancelled" };
108
+ }
101
109
  return {
102
110
  kind: "selected",
103
111
  permission: permission
@@ -107,12 +115,13 @@ export function renderAgentConfigurationResolutionNotice(resolved) {
107
115
  const lines = [];
108
116
  if (resolved.source === "cache") {
109
117
  lines.push((resolved.failure === undefined ? "" : `! Runtime capability request failed (${resolved.failure.message}). `)
110
- + `Showing cached options from ${resolved.fetchedAt ?? "an earlier request"}; they may be stale.`);
118
+ + `Showing identity-matched cached options from ${resolved.fetchedAt ?? "an earlier request"}; they may be stale.`);
111
119
  }
112
120
  else if (resolved.source === "fallback") {
113
121
  lines.push(`! Runtime capability request failed (${resolved.failure?.message ?? "unknown failure"}). `
114
- + "No matching cache is available; only fallback and custom values can be offered.");
122
+ + "No matching cache is available; only declared static adapter contracts and explicit custom values can be offered.");
115
123
  }
124
+ lines.push(`Metadata source: ${resolved.source}; last probe attempted ${resolved.attemptedAt}${resolved.fetchedAt === undefined ? "" : `; fetched ${resolved.fetchedAt}`}. Source describes the query, not native confirmation of every field.`);
116
125
  lines.push(...resolved.catalog.warnings.map((warning) => `! Agent catalog warning: ${warning}`));
117
126
  return lines.length === 0 ? "" : `${lines.join("\n")}\n`;
118
127
  }
@@ -215,29 +224,23 @@ function observedEfforts(models) {
215
224
  }
216
225
  async function selectPermissionField(resolved, io, key, current, defaultValue) {
217
226
  const field = configurationField(resolved.catalog, key);
218
- const fallback = key === "permission.sandbox"
219
- ? ["read-only", "workspace-write", "danger-full-access"]
220
- : key === "permission.approval"
221
- ? ["untrusted", "on-request", "never"]
222
- : ["acceptEdits", "auto", "bypassPermissions", "manual", "dontAsk", "plan"];
223
- const choices = uniqueChoices(field === undefined
224
- ? fallback.map((value) => ({ value, label: value }))
225
- : field.choices, current);
226
- const includeOmit = defaultValue === OMIT || current !== undefined;
227
+ if (field?.reason !== undefined)
228
+ io.write(`${key}: ${field.reason}\n`);
229
+ if (field === undefined)
230
+ io.write(`${key}: no catalog field was reported; no choices inferred.\n`);
231
+ const choices = uniqueChoices(field?.available === false ? [] : field?.choices ?? [], current);
227
232
  const pickerChoices = [
228
- ...(includeOmit
229
- ? [{ value: OMIT, label: "Omit", detail: "Do not pass this provider option" }]
230
- : []),
233
+ { value: OMIT, label: "Omit", detail: "Do not pass this provider option" },
231
234
  ...choices.map(({ value, label, description }) => ({
232
235
  value,
233
236
  label,
234
237
  detail: description ?? value
235
238
  })),
236
239
  ...(field?.allowCustom === true
237
- ? [{ value: CUSTOM, label: "Custom…", detail: "Enter another provider value" }]
240
+ ? [{ value: CUSTOM, label: "Custom…", detail: "Explicit value; native acceptance unverified" }]
238
241
  : [])
239
242
  ];
240
- const selected = await choose(`Select ${key}`, pickerChoices, io, current ?? defaultValue ?? pickerChoices[0]?.value ?? OMIT, key);
243
+ const selected = await choose(`Select ${key}`, pickerChoices, io, current ?? (choices.some(choice => choice.value === defaultValue) ? defaultValue : OMIT), key);
241
244
  if (selected === undefined)
242
245
  return { kind: "cancelled" };
243
246
  if (selected === OMIT)
@@ -344,7 +344,7 @@ const taskChildren = [
344
344
  },
345
345
  {
346
346
  name: "complete",
347
- summary: "Complete an active Task and stop automatic wakeups.",
347
+ summary: "Complete locally, or prepare/dispatch the configured final Review and remain active. --refresh-remote only fetches freshness observations; it never rebases, changes HEAD or starts Integration checks.",
348
348
  usage: "yui task complete <id> (--summary <text>|--summary-file <path|->) [--artifact-ref <artifact-id|turn:id|url> ...] [--refresh-remote] [--accept-published-tree <publication-id>]",
349
349
  options: ["--summary", "--summary-file", "--artifact-ref", "--refresh-remote", "--accept-published-tree"],
350
350
  fileOptions: ["--summary-file"]
@@ -356,7 +356,7 @@ const taskChildren = [
356
356
  children: [
357
357
  {
358
358
  name: "status",
359
- summary: "Classify Task Project bases against local or refreshed remote refs.",
359
+ summary: "Observe Task Project bases against local refs; --refresh fetches remote objects without changing HEAD, starting checks or creating Integration/Review.",
360
360
  usage: "yui task base status <task> [--refresh]",
361
361
  options: ["--refresh"]
362
362
  }
@@ -402,7 +402,7 @@ const taskChildren = [
402
402
  },
403
403
  {
404
404
  name: "next-action",
405
- summary: "Project the durable Task records into one protocol-level next action.",
405
+ summary: "Read Task facts, mechanical prerequisites and legal alternatives; semantic choices remain with the Leader.",
406
406
  usage: "yui task next-action <task> [--json]",
407
407
  options: ["--json"]
408
408
  },
@@ -432,7 +432,7 @@ const taskChildren = [
432
432
  children: [
433
433
  {
434
434
  name: "integrate",
435
- summary: "Rebase Task changes onto the remote development head through Integration.",
435
+ summary: "Explicitly rebase Task changes onto the remote development head, run configured/additional checks (possibly as Jobs), then advance HEAD through Integration CAS. Returns exact attempts and partial results; does not request Review or complete the Task.",
436
436
  usage: "yui task upstream integrate <task> (--latest|--project <project>) [--check <command> ...] [--rerun-checks]",
437
437
  options: ["--latest", "--project", "--check", "--rerun-checks"]
438
438
  }
@@ -893,7 +893,7 @@ const taskChildren = [
893
893
  {
894
894
  name: "expand",
895
895
  summary: "Expand one authorized AgentRun context reference.",
896
- usage: "yui task run context expand <task>/<run> <ref-id> [--store <store>] [--mode full]",
896
+ usage: "yui task run context expand <task>/<run> <ref-id> --store <store> [--mode full]",
897
897
  options: ["--store", "--mode"]
898
898
  },
899
899
  {
@@ -916,7 +916,7 @@ const taskChildren = [
916
916
  name: "retire",
917
917
  summary: "Retire an incorrect historical AgentRun without deleting its audit record.",
918
918
  usage: "yui task run retire <task>/<run> --reason <text> [--expected-progress-at <timestamp>] [--agent-id <id>] [--adapter-id <id>] [--native-session-id <id>]",
919
- options: ["--reason", "--expected-progress-at", "--progress-at", "--agent-id", "--adapter-id", "--native-session-id"]
919
+ options: ["--reason", "--expected-progress-at", "--agent-id", "--adapter-id", "--native-session-id"]
920
920
  }
921
921
  ]
922
922
  },
@@ -1142,7 +1142,12 @@ export const ROOT_COMMAND = buildNode({
1142
1142
  },
1143
1143
  { name: "help", summary: "Show root or scoped command help.", usage: "yui help [command ...]", commandPathArguments: true },
1144
1144
  { name: "version", summary: "Print the installed Yui version." },
1145
- { name: "update", summary: "Install the latest published Yui package globally." },
1145
+ {
1146
+ name: "update",
1147
+ summary: "Install the latest or an exact published Yui version after storage preflight.",
1148
+ usage: "yui update [--version <exact-version>]",
1149
+ options: ["--version"]
1150
+ },
1146
1151
  {
1147
1152
  name: "upgrade",
1148
1153
  summary: "Plan or apply supported storage migrations for this Home.",
@@ -1379,8 +1384,8 @@ export const ROOT_COMMAND = buildNode({
1379
1384
  {
1380
1385
  name: "clone",
1381
1386
  summary: "Clone and bind a Project after user confirmation.",
1382
- usage: "yui project clone <name> <remote> [--alias <name> ...] [--stable <ref>] [--development <ref>]",
1383
- options: ["--alias", "--stable", "--development"]
1387
+ usage: "yui project clone <name> <remote> [--alias <name> ...] [--stable <ref>] [--development <ref>] [--external]",
1388
+ options: ["--alias", "--stable", "--development", "--external"]
1384
1389
  },
1385
1390
  {
1386
1391
  name: "refresh",
@@ -1722,8 +1727,11 @@ export function validateCommandCatalog(root) {
1722
1727
  }
1723
1728
  const options = new Set();
1724
1729
  for (const option of [...node.options, ...node.hiddenOptions]) {
1725
- if (reservedAliases.has(option))
1730
+ // --version is an alias only as the entire root invocation. Scoped
1731
+ // commands may own a version selector; help aliases remain reserved.
1732
+ if (reservedAliases.has(option) && option !== "--version") {
1726
1733
  throw new Error(`Reserved alias token is not allowed: ${[...node.path, option].join(" ")}`);
1734
+ }
1727
1735
  if (options.has(option) || immediate.has(option))
1728
1736
  throw new Error(`Duplicate command token: ${[...node.path, option].join(" ")}`);
1729
1737
  options.add(option);