@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
@@ -0,0 +1,120 @@
1
+ // These are Yui's accepted configuration values, not a native capability probe.
2
+ // Keep existing explicit configuration legal; current native choices come from
3
+ // help and requirements, and may be a smaller set.
4
+ export const CODEX_SANDBOXES = ["read-only", "workspace-write", "danger-full-access"];
5
+ export const CODEX_APPROVALS = ["untrusted", "on-request", "never"];
6
+ export const STATIC_CONFIGURATION_NOTICE = "Static adapter configuration contracts are not native enumeration or proof of Provider acceptance; see field reasons.";
7
+ export function staticAgentConfigurationFields(id) {
8
+ const fields = [
9
+ staticField("model", [], true, "Model values require native metadata; custom IDs remain explicit input."),
10
+ staticField("effort", [], true, "Effort values depend on the selected native model."),
11
+ staticField("permission.strategy", ["default", "bypass", "configured"], false, "These are Yui strategies, not Provider modes.")
12
+ ];
13
+ if (id === "codex")
14
+ return [
15
+ ...fields,
16
+ staticField("permission.sandbox", CODEX_SANDBOXES, false),
17
+ staticField("permission.approval", CODEX_APPROVALS, false, "Native versions may retire values accepted by the adapter."),
18
+ staticField("search", ["true"], false),
19
+ staticField("profile", [], true),
20
+ staticField("additionalDirectories", [], true)
21
+ ];
22
+ if (id === "acp")
23
+ return [
24
+ ...fields,
25
+ staticField("permission.mode", [], true, "Mode IDs are enumerated per Session and checked at launch."),
26
+ staticField("additionalDirectories", [], true, "Delivery requires the Agent's initialize capability; it is unverified offline.")
27
+ ];
28
+ return [
29
+ ...fields,
30
+ staticField("permission.mode", [], true, "No native modes were enumerated."),
31
+ staticField("permission.allowedTools", [], true),
32
+ staticField("permission.disallowedTools", [], true),
33
+ staticField("settingsSources", ["user", "project", "local"], false),
34
+ staticField("settingsFile", [], true),
35
+ staticField("additionalDirectories", [], true)
36
+ ];
37
+ }
38
+ function staticField(key, values, allowCustom, detail = "") {
39
+ return {
40
+ key, choices: values.map(value => ({ value, label: value })), allowCustom,
41
+ reason: `Static adapter configuration contract; native support is unverified.${detail ? ` ${detail}` : ""}`
42
+ };
43
+ }
44
+ /** One help interpretation shared by installation inspection and live probes. */
45
+ export function configurationFieldsFromHelp(id, help) {
46
+ const fields = staticAgentConfigurationFields(id);
47
+ if (id === "acp")
48
+ return fields;
49
+ const bypassFlag = id === "codex"
50
+ ? "--dangerously-bypass-approvals-and-sandbox" : "--dangerously-skip-permissions";
51
+ const replacements = [
52
+ {
53
+ ...staticField("permission.strategy", [
54
+ "default", ...(configurationFlagAvailable(help, bypassFlag) ? ["bypass"] : []), "configured"
55
+ ], false),
56
+ reason: `Static Yui strategies; ${bypassFlag} ${configurationFlagAvailable(help, bypassFlag) ? "reported" : "not reported"} by native --help. This does not confirm account policy.`
57
+ },
58
+ ...(id === "codex"
59
+ ? [
60
+ helpChoiceField("permission.sandbox", help, "--sandbox", false, CODEX_SANDBOXES),
61
+ helpChoiceField("permission.approval", help, "--ask-for-approval", false, CODEX_APPROVALS)
62
+ ]
63
+ : [
64
+ helpChoiceField("permission.mode", help, "--permission-mode", true),
65
+ helpChoiceField("effort", help, "--effort", true),
66
+ // The CLI's description often names settings sources without an enum.
67
+ // Retain the explicit static contract, never relabel it as discovery.
68
+ ...(configurationHelpChoices(help, "--setting-sources").length === 0 ? []
69
+ : [helpChoiceField("settingsSources", help, "--setting-sources", false)])
70
+ ])
71
+ ];
72
+ const byKey = new Map(replacements.map(value => [value.key, value]));
73
+ return fields.map(value => byKey.get(value.key) ?? value);
74
+ }
75
+ function helpChoiceField(key, help, flag, allowCustom, supported) {
76
+ const reported = configurationHelpChoices(help, flag);
77
+ const values = supported === undefined ? reported : reported.filter(value => supported.includes(value));
78
+ return {
79
+ key, choices: values.map(value => ({ value, label: value })), allowCustom,
80
+ available: values.length > 0,
81
+ reason: values.length > 0
82
+ ? `Native --help ${flag} enumeration${supported === undefined ? "" : ", limited to adapter-supported values"}.`
83
+ : `Native enumeration unavailable: ${flag} values were not reported or are not supported by this adapter.`
84
+ };
85
+ }
86
+ export function configurationFieldWarnings(fields) {
87
+ return [
88
+ STATIC_CONFIGURATION_NOTICE,
89
+ ...fields.filter(field => field.available === false)
90
+ .map(field => `${field.key}: ${field.reason ?? "Native capability unavailable."}`)
91
+ ];
92
+ }
93
+ /** Read only an explicit native enum. Prose examples and missing fields are not choices. */
94
+ export function configurationHelpChoices(help, flag) {
95
+ const section = helpSection(help, flag);
96
+ if (section === undefined)
97
+ return [];
98
+ const inline = /(?:\[possible values:\s*([^\]]+)\]|\(choices:\s*([^)]*)\))/i.exec(section);
99
+ const declared = inline?.[1] ?? inline?.[2];
100
+ const bullets = declared === undefined && /Possible values:/i.test(section)
101
+ ? [...section.matchAll(/^\s*-\s*([\w.+-]+)\s*:/gm)].map(match => match[1] ?? "")
102
+ : [];
103
+ return [...new Set((declared ?? bullets.join(",")).replace(/["']/g, "").split(",")
104
+ .map(value => value.trim().replace(/\.$/, "")).filter(value => /^[\w.+-]+$/.test(value)))];
105
+ }
106
+ export function configurationFlagAvailable(help, flag) {
107
+ return helpSection(help, flag) !== undefined;
108
+ }
109
+ function helpSection(help, flag) {
110
+ const lines = help.replace(/\r\n/g, "\n").split("\n");
111
+ const escaped = flag.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
112
+ const declaration = new RegExp(`^\\s*(?:-[A-Za-z],?\\s+)?${escaped}(?=[\\s=,<\\[]|$)`);
113
+ const start = lines.findIndex(line => declaration.test(line));
114
+ if (start < 0)
115
+ return undefined;
116
+ let end = start + 1;
117
+ while (end < lines.length && !/^\s*(?:-[A-Za-z],?\s+|--)[\w-]/.test(lines[end]))
118
+ end++;
119
+ return lines.slice(start, end).join("\n");
120
+ }
@@ -9,6 +9,7 @@ import { codexClientInitialization } from "../runtime/codexAppServerRuntime.js";
9
9
  import { acpInitializeRequest, readAcpInitializeResult } from "../runtime/acpProtocol.js";
10
10
  import { handshakeObservationFrom } from "../runtime/agentRunConfiguration.js";
11
11
  import { YUI_VERSION } from "../version.js";
12
+ import { configurationFieldsFromHelp, configurationFieldWarnings, STATIC_CONFIGURATION_NOTICE } from "./agentConfigurationFields.js";
12
13
  /**
13
14
  * Codex and Claude Code are configured by flags and their own files; neither
14
15
  * plan exchanges capabilities on connect. Saying so explicitly keeps a caller
@@ -20,8 +21,6 @@ const NO_HANDSHAKE = Object.freeze({
20
21
  });
21
22
  const MAX_OUTPUT_BYTES = 1024 * 1024;
22
23
  const PROCESS_TERMINATION_GRACE_MS = 100;
23
- const CODEX_SANDBOXES = ["read-only", "workspace-write", "danger-full-access"];
24
- const CODEX_APPROVALS = ["untrusted", "on-request", "never"];
25
24
  const ACP_PROBE_REQUEST_ID = 1;
26
25
  export async function discoverCodexConfiguration(input) {
27
26
  const environment = configuredAgentLaunchEnvironment(input.agent, input.environment);
@@ -43,17 +42,35 @@ export async function discoverCodexConfiguration(input) {
43
42
  client.request("configRequirements/read", {}),
44
43
  client.request("modelProvider/capabilities/read", {})
45
44
  ]);
46
- const requirements = object(requirementsResult)?.requirements;
47
- const requirementRecord = object(requirements);
45
+ const requirements = requiredObject(requirementsResult, "Codex configuration requirements response").requirements;
46
+ const requirementRecord = requirements === null ? undefined
47
+ : requiredObject(requirements, "Codex configuration requirements");
48
48
  const allowedSandboxes = optionalStrings(requirementRecord?.allowedSandboxModes);
49
- const allowedApprovals = optionalStrings(requirementRecord?.allowedApprovalPolicies);
49
+ const allowedApprovals = optionalApprovalChoices(requirementRecord?.allowedApprovalPolicies);
50
50
  const allowedWebSearchModes = optionalStrings(requirementRecord?.allowedWebSearchModes);
51
- const capabilityRecord = object(providerCapabilities);
52
- const webSearch = capabilityRecord?.webSearch === true
51
+ const capabilityRecord = requiredObject(providerCapabilities, "Codex Provider capabilities");
52
+ if (typeof capabilityRecord.webSearch !== "boolean") {
53
+ throw new Error("Codex Provider capabilities did not report webSearch.");
54
+ }
55
+ const webSearch = capabilityRecord.webSearch
53
56
  && (allowedWebSearchModes === undefined || allowedWebSearchModes.includes("live"));
54
- const bypass = configurationFlagAvailable(help, "--dangerously-bypass-approvals-and-sandbox");
55
- const sandboxChoices = intersectChoices(configurationHelpChoices(help, "--sandbox", CODEX_SANDBOXES), allowedSandboxes);
56
- const approvalChoices = intersectChoices(configurationHelpChoices(help, "--ask-for-approval", CODEX_APPROVALS), allowedApprovals);
57
+ const fields = configurationFieldsFromHelp("codex", help).map(candidate => {
58
+ const allowed = candidate.key === "permission.sandbox" ? allowedSandboxes
59
+ : candidate.key === "permission.approval" ? allowedApprovals : undefined;
60
+ if (allowed !== undefined) {
61
+ const choices = candidate.choices.filter(choice => allowed.includes(choice.value));
62
+ return {
63
+ ...candidate, choices, available: choices.length > 0,
64
+ reason: `${candidate.reason} Native configuration requirements applied.${choices.length === 0 ? " No usable values were confirmed." : ""}`
65
+ };
66
+ }
67
+ if (candidate.key === "search")
68
+ return field("search", webSearch ? [choice("true")] : [], false, webSearch, webSearch ? "Native Provider capability and configuration requirements permit live web search."
69
+ : "Live web search is unavailable or disallowed.");
70
+ if (candidate.key === "profile")
71
+ return codexProfileField(environment);
72
+ return candidate;
73
+ });
57
74
  return {
58
75
  schemaVersion: 1,
59
76
  agentId: input.agent.id,
@@ -61,21 +78,8 @@ export async function discoverCodexConfiguration(input) {
61
78
  ...(semanticVersion(version) === undefined ? {} : { cliVersion: semanticVersion(version) }),
62
79
  handshake: NO_HANDSHAKE,
63
80
  models,
64
- fields: [
65
- field("model", [], true),
66
- field("effort", [], true),
67
- field("permission.strategy", [
68
- choice("default"),
69
- ...(bypass ? [choice("bypass")] : []),
70
- choice("configured")
71
- ], false, true, bypass ? undefined : "Codex bypass strategy is unavailable."),
72
- field("permission.sandbox", sandboxChoices.map(choice), false),
73
- field("permission.approval", approvalChoices.map(choice), false),
74
- field("search", webSearch ? [choice("true")] : [], false, webSearch, webSearch ? undefined : "Live web search is unavailable or disallowed."),
75
- field("profile", codexProfileChoices(environment).map(choice), true),
76
- field("additionalDirectories", [], true)
77
- ],
78
- warnings: client.warnings()
81
+ fields,
82
+ warnings: [...client.warnings(), ...configurationFieldWarnings(fields)]
79
83
  };
80
84
  }
81
85
  finally {
@@ -105,9 +109,7 @@ export async function discoverClaudeConfiguration(input) {
105
109
  ]);
106
110
  const initialized = object(initialization);
107
111
  const models = array(initialized?.models, "Claude model catalog").map(claudeModel);
108
- const permissionModes = configurationHelpChoices(help, "--permission-mode", []);
109
- const bypass = configurationFlagAvailable(help, "--dangerously-skip-permissions");
110
- const settingsSources = configurationHelpChoices(help, "--setting-sources", ["user", "project", "local"]);
112
+ const fields = configurationFieldsFromHelp("claude", help);
111
113
  return {
112
114
  schemaVersion: 1,
113
115
  agentId: input.agent.id,
@@ -115,22 +117,8 @@ export async function discoverClaudeConfiguration(input) {
115
117
  ...(semanticVersion(version) === undefined ? {} : { cliVersion: semanticVersion(version) }),
116
118
  handshake: NO_HANDSHAKE,
117
119
  models,
118
- fields: [
119
- field("model", [], true),
120
- field("effort", [], true),
121
- field("permission.strategy", [
122
- choice("default"),
123
- ...(bypass ? [choice("bypass")] : []),
124
- choice("configured")
125
- ], false, true, bypass ? undefined : "Claude bypass strategy is unavailable."),
126
- field("permission.mode", permissionModes.map(choice), true),
127
- field("permission.allowedTools", [], true),
128
- field("permission.disallowedTools", [], true),
129
- field("settingsSources", settingsSources.map(choice), false),
130
- field("settingsFile", [], true),
131
- field("additionalDirectories", [], true)
132
- ],
133
- warnings: []
120
+ fields,
121
+ warnings: configurationFieldWarnings(fields)
134
122
  };
135
123
  }
136
124
  async function listCodexModels(client) {
@@ -283,7 +271,7 @@ async function requestClaudeInitialization(command, args, cwd, environment, sign
283
271
  export async function discoverAcpConfiguration(input) {
284
272
  const environment = configuredAgentLaunchEnvironment(input.agent, input.environment);
285
273
  const negotiated = await requestAcpInitialization(input.agent.command, [...input.agent.baseArgs], input.cwd, environment, input.signal);
286
- const warnings = [];
274
+ const warnings = [STATIC_CONFIGURATION_NOTICE];
287
275
  if (!negotiated.capabilities.loadSession) {
288
276
  warnings.push("This ACP Agent does not support `session/load`, so a managed Yui Turn "
289
277
  + "cannot survive a Provider restart.");
@@ -331,7 +319,7 @@ export async function discoverAcpConfiguration(input) {
331
319
  field("effort", [], true, true, "ACP selects reasoning effort with session/set_config_option, under the "
332
320
  + "`thought_level` category. As with the model, the accepted values are "
333
321
  + "negotiated per Session and verified at launch rather than listed here."),
334
- field("permission.strategy", [choice("default"), choice("bypass"), choice("configured")], false, true, "`default` sends no mode, so the Agent's own default stands. `configured` "
322
+ field("permission.strategy", [choice("default"), choice("bypass"), choice("configured")], false, true, "Static Yui strategies: `default` sends no mode, so the Agent's own default stands. `configured` "
335
323
  + "selects one exact mode the Agent offers. `bypass` applies the mode that "
336
324
  + "grants unattended action, and only for an execution component Yui can "
337
325
  + "identify — it is never guessed from a mode's name. None of these change "
@@ -573,47 +561,34 @@ function terminateProcess(child) {
573
561
  child.once("exit", () => { clearTimeout(force); });
574
562
  child.kill("SIGTERM");
575
563
  }
576
- export function codexProfileChoices(environment) {
564
+ function codexProfileField(environment) {
577
565
  const root = environment.CODEX_HOME
578
566
  ?? join(environment.HOME ?? homedir(), ".codex");
579
567
  try {
580
568
  const profiles = object(parse(readFileSync(join(root, "config.toml"), "utf8")).profiles);
581
- return Object.keys(profiles ?? {}).filter((name) => name.trim().length > 0 && !name.includes("\0")).sort();
582
- }
583
- catch {
584
- return [];
569
+ const names = Object.keys(profiles ?? {}).filter((name) => name.trim().length > 0 && !name.includes("\0")).sort();
570
+ return field("profile", names.map(choice), true, undefined, "Local config.toml profile names, not a Provider enumeration; custom names remain explicit input.");
585
571
  }
586
- }
587
- export function configurationHelpChoices(help, flag, fallback) {
588
- const lines = help.replace(/\r\n/g, "\n").split("\n");
589
- const start = lines.findIndex((line) => line.includes(flag));
590
- if (start < 0)
591
- return [...fallback];
592
- let end = start + 1;
593
- while (end < lines.length && !/^\s{2,}(?:-[A-Za-z](?:,\s*)?|--)[\w-]/.test(lines[end] ?? "")) {
594
- end += 1;
572
+ catch (error) {
573
+ const absent = error instanceof Error && "code" in error && error.code === "ENOENT";
574
+ return field("profile", [], true, absent ? undefined : false, absent
575
+ ? "No local config.toml; no profile names observed. Custom names remain explicit input."
576
+ : "Local config.toml could not be read or parsed; profile enumeration unavailable.");
595
577
  }
596
- const section = lines.slice(start, end).join("\n");
597
- const inline = /(?:\[possible values:\s*([^\]]+)\]|\(choices:\s*([^)]*)\))/i
598
- .exec(section);
599
- const declared = inline?.[1] ?? inline?.[2];
600
- const bulletValues = declared === undefined && /Possible values:/i.test(section)
601
- ? [...section.matchAll(/^\s*-\s*([\w.+-]+)\s*:/gm)].map((match) => match[1] ?? "")
602
- : [];
603
- const parsed = [...new Set((declared ?? bulletValues.join(","))
604
- .replace(/["']/g, "")
605
- .split(",")
606
- .map((value) => value.trim().replace(/\.$/, ""))
607
- .filter((value) => /^[\w.+-]+$/.test(value)))];
608
- return parsed.length === 0 ? [...fallback] : parsed;
609
- }
610
- function configurationFlagAvailable(help, flag) {
611
- return help.replace(/\r\n/g, "\n").split("\n").some((line) => line.includes(flag));
612
578
  }
613
- function intersectChoices(choices, allowed) {
614
- return allowed === undefined
615
- ? [...choices]
616
- : choices.filter((candidate) => allowed.includes(candidate));
579
+ function optionalApprovalChoices(value) {
580
+ if (value === null || value === undefined)
581
+ return undefined;
582
+ // Current Codex also reports structured granular policies. They constrain
583
+ // configuration but cannot be selected by Yui's scalar approval input; do not
584
+ // reject the whole legitimate response or expand them into guessed aliases.
585
+ return array(value, "configuration approval requirements").flatMap(entry => {
586
+ if (typeof entry === "string")
587
+ return [requiredString(entry, "approval requirement")];
588
+ if (object(object(entry)?.granular) !== undefined)
589
+ return [];
590
+ throw new Error("Codex configuration approval requirement is invalid.");
591
+ });
617
592
  }
618
593
  function optionalStrings(value) {
619
594
  if (value === null || value === undefined)
@@ -7,7 +7,7 @@ import { builtinAgentEndpointImplementation, validateAgentEndpointImplementation
7
7
  /** Recovery addresses retained execution identity, not a live Session grant.
8
8
  * A released Session cache can be absent while its native binding still needs
9
9
  * to be stopped. No active Session record is fabricated by this projection. */
10
- export function taskRoleControlTarget(set) {
10
+ export function roleSessionControlTarget(set) {
11
11
  if (set == null)
12
12
  return undefined;
13
13
  const current = set.sessions[set.activeAgentId];
@@ -19,7 +19,10 @@ export function taskRoleControlTarget(set) {
19
19
  const agentId = fromBinding ? binding.accountScope : current?.agentId;
20
20
  if (nativeSessionId === undefined || agentId === undefined)
21
21
  return undefined;
22
- const session = [...Object.values(set.sessions), ...(set.history ?? [])]
22
+ const history = set.owner.scope === "global"
23
+ ? Object.values(set.history ?? {})
24
+ : set.history ?? [];
25
+ const session = [...Object.values(set.sessions), ...history]
23
26
  .find(entry => entry.nativeSessionId === nativeSessionId && entry.agentId === agentId);
24
27
  const adapterId = session?.adapterId ?? (binding === null ? undefined : builtinAgentDriverRegistry().find(binding.providerNamespace)?.adapterId);
25
28
  return { nativeSessionId, agentId, adapterId, status: session?.status,
@@ -33,10 +36,10 @@ export function createRoleSessionSet(owner, activeAgentId, now) {
33
36
  updatedAt: now.toISOString()
34
37
  };
35
38
  return owner.scope === "global"
36
- ? { ...base, schemaVersion: 5, providerBinding: null }
39
+ ? { ...base, schemaVersion: 1, providerBinding: null }
37
40
  : {
38
41
  ...base,
39
- schemaVersion: 12,
42
+ schemaVersion: 1,
40
43
  providerBinding: null
41
44
  };
42
45
  }
@@ -103,7 +106,7 @@ export function recordRoleAgentSession(set, input, now) {
103
106
  throw new Error("A native Session cannot change its Endpoint implementation in place.");
104
107
  }
105
108
  const session = {
106
- schemaVersion: 6,
109
+ schemaVersion: 1,
107
110
  agentId,
108
111
  adapterId,
109
112
  nativeSessionId,
@@ -461,7 +464,7 @@ export function validateRoleSessionSet(set) {
461
464
  validateRoleAgentSession(session, agentId);
462
465
  }
463
466
  if (set.owner.scope === "global") {
464
- if (set.schemaVersion !== 5) {
467
+ if (set.schemaVersion !== 1) {
465
468
  throw new Error("Global Role session set schema version is invalid.");
466
469
  }
467
470
  const globalSet = set;
@@ -500,7 +503,7 @@ export function validateRoleSessionSet(set) {
500
503
  }
501
504
  }
502
505
  else {
503
- if (set.schemaVersion !== 12) {
506
+ if (set.schemaVersion !== 1) {
504
507
  throw new Error("Task Role session set schema version is invalid.");
505
508
  }
506
509
  if (!Object.hasOwn(set, "providerBinding")) {
@@ -547,7 +550,7 @@ export function validateRoleSessionSet(set) {
547
550
  return set;
548
551
  }
549
552
  export function validateRoleAgentSession(session, expectedAgentId = session.agentId) {
550
- if (session.schemaVersion !== 6) {
553
+ if (session.schemaVersion !== 1) {
551
554
  throw new Error(`Role Agent session schema version is invalid: ${expectedAgentId}.`);
552
555
  }
553
556
  const agentId = requireSafeIdentity(session.agentId, "Agent id");
@@ -172,8 +172,8 @@ function sessionContinuitySnapshot(snapshot) {
172
172
  };
173
173
  }
174
174
  export function validateEffectiveLaunchSnapshot(snapshot) {
175
- if (snapshot.schemaVersion !== 4) {
176
- throw new Error("Effective launch snapshot must use schemaVersion 4.");
175
+ if (snapshot.schemaVersion !== 1) {
176
+ throw new Error("Effective launch snapshot must use schemaVersion 1.");
177
177
  }
178
178
  if (snapshot.executionAuthority !== "planning" && snapshot.executionAuthority !== "delivery") {
179
179
  throw new Error("Effective launch requires its captured execution authority.");
@@ -278,7 +278,7 @@ function snapshotFromConfig(input) {
278
278
  reviewBaseCommit: commit(input.reviewBaseCommit ?? "", "Review base commit")
279
279
  };
280
280
  const common = {
281
- schemaVersion: 4,
281
+ schemaVersion: 1,
282
282
  executionAuthority: input.executionAuthority,
283
283
  sourceDesiredRevision: positiveInteger(input.sourceDesiredRevision, "Source desired revision"),
284
284
  agentId: identity(input.agentId, "Effective Agent id"),
@@ -176,15 +176,6 @@ export class ExecutorRegistry {
176
176
  });
177
177
  return deliveryReport(outcome);
178
178
  }
179
- async notifyOperatorInputOnce(input) {
180
- if (this.runtimePorts?.notifyOperatorInputOnce !== undefined) {
181
- return this.runtimePorts.notifyOperatorInputOnce(input);
182
- }
183
- const probe = this.readiness(input.adapterId, "operator");
184
- return this.tmux.sendRoleInputOnceIfReadyAsync === undefined
185
- ? this.tmux.sendRoleInputOnceIfReady("operator", input.roleName, input.receiptId, input.text, probe)
186
- : this.tmux.sendRoleInputOnceIfReadyAsync("operator", input.roleName, input.receiptId, input.text, probe);
187
- }
188
179
  forgetPrepared(input) {
189
180
  for (const [deliveryId, prepared] of this.#prepared) {
190
181
  const delivery = prepared.delivery;
@@ -21,7 +21,7 @@ import { resolveTaskRoleSessionTitle } from "../runtime/sessionTitle.js";
21
21
  import { parseTaskRuntimeIsolationDescriptor, taskRuntimeIsolationEnvironment } from "../runtime/taskRuntimeIsolation.js";
22
22
  import { planningRuntimeCwd } from "../storage/homeLayout.js";
23
23
  import { resolveAgentAdapter } from "./agentAdapter.js";
24
- import { activeLiveRoleAgentSession, taskRoleControlTarget } from "./agentExecutor.js";
24
+ import { activeLiveRoleAgentSession, roleSessionControlTarget } from "./agentExecutor.js";
25
25
  import { assertCodexLaunchOverridesAvailable, inspectCodexLaunchConfig } from "./codexConfigConflict.js";
26
26
  import { effectiveRoleForLaunch, resolveEffectiveLaunch, roleSessionMayContinue } from "./effectiveLaunch.js";
27
27
  import { classifyWorkspacePreflight, formatWorkspacePreflightError } from "./workspacePreflightClassification.js";
@@ -69,9 +69,11 @@ export class FileRoleLaunchPlanner {
69
69
  }
70
70
  /** Recovery addresses the recorded Agent/Session, independent of delivery
71
71
  * admission, a missing worktree, or the old Endpoint code generation. */
72
- planNativeControl(taskId, roleName) {
73
- const set = this.store.getTaskRoleSessionSet(taskId, roleName);
74
- const session = taskRoleControlTarget(set);
72
+ planNativeControl(owner) {
73
+ const set = owner.scope === "task"
74
+ ? this.store.getTaskRoleSessionSet(owner.taskId, owner.roleName)
75
+ : this.store.getGlobalRoleSessionSet(owner.roleName);
76
+ const session = roleSessionControlTarget(set);
75
77
  if (session?.adapterId !== "codex")
76
78
  throw new Error("Native metadata control requires a recorded Codex Session.");
77
79
  const configured = this.store.getConfiguredAgent(session.agentId);
@@ -79,9 +81,11 @@ export class FileRoleLaunchPlanner {
79
81
  throw new Error("The recorded native Agent connection is unavailable.");
80
82
  }
81
83
  const agent = configuredAgentToDefinition(configured);
82
- const connection = this.store.listEvents(taskId).find(event => event.type === "runtime.native-connection-bound"
83
- && event.payload.roleName === roleName && event.payload.agentId === session.agentId
84
- && event.payload.nativeSessionId === session.nativeSessionId)?.payload;
84
+ const connection = owner.scope === "task"
85
+ ? this.store.listEvents(owner.taskId).find(event => event.type === "runtime.native-connection-bound"
86
+ && event.payload.roleName === owner.roleName && event.payload.agentId === session.agentId
87
+ && event.payload.nativeSessionId === session.nativeSessionId)?.payload
88
+ : undefined;
85
89
  return {
86
90
  command: configured.command, args: [...agent.baseArgs, "app-server", "proxy"], cwd: this.home,
87
91
  expectedAccountHome: connection?.nativeAccountHome,
@@ -758,10 +762,7 @@ function managedClaudeControlPlaneConfig(config, taskId, workItemId, runId) {
758
762
  }
759
763
  function isManagedYuiBashRule(rule) {
760
764
  const normalized = rule.trim();
761
- return /^Bash\(yui(?:\s|:\*|\*|\))/u.test(normalized)
762
- // Yui no longer writes a control-plane digest into a managed rule; this
763
- // shape only clears one an earlier release left in a Provider config.
764
- || /^Bash\(.*\s--yui-control\s/u.test(normalized);
765
+ return /^Bash\(yui(?:\s|:\*|\*|\))/u.test(normalized);
765
766
  }
766
767
  function canonicalPath(path) {
767
768
  const absolute = resolve(path);
@@ -1,6 +1,6 @@
1
1
  import { requireIdentity, requireText, requireTimestamp, requirePositiveInteger } from "../domain/validation.js";
2
2
  import { validateTaskRecordReference } from "../task/taskRecordReference.js";
3
- export const CAPABILITY_GRANT_SCHEMA_VERSION = 2;
3
+ export const CAPABILITY_GRANT_SCHEMA_VERSION = 1;
4
4
  const IRREVERSIBILITY_RANK = {
5
5
  none: 0,
6
6
  reversible: 1,
@@ -105,7 +105,7 @@ export function revokeGrant(grant, revokedBy, now) {
105
105
  }
106
106
  export function validateCapabilityGrant(grant) {
107
107
  if (grant.schemaVersion !== CAPABILITY_GRANT_SCHEMA_VERSION) {
108
- throw new Error("Capability grant must use schemaVersion 2.");
108
+ throw new Error("Capability grant must use schemaVersion 1.");
109
109
  }
110
110
  validateTaskRecordReference({ taskId: grant.taskId, localId: grant.id }, "capabilityGrant");
111
111
  requireIdentity(grant.taskId, "Task id");
@@ -14,7 +14,7 @@ export function createInputRequest(id, taskId, requester, input, now) {
14
14
  const timestamp = requireDate(now, "Input request creation time");
15
15
  const choices = normalizeChoices(input.choices);
16
16
  return validateInputRequest({
17
- schemaVersion: 3,
17
+ schemaVersion: 1,
18
18
  id: requireIdentity(id, "Input request id"),
19
19
  taskId: requireIdentity(taskId, "Input request Task id"),
20
20
  requester: normalizeRequester(requester),
@@ -72,12 +72,12 @@ export function validateInputRequest(value) {
72
72
  "schemaVersion", "id", "taskId", "requester", "question", "choices",
73
73
  "blockedRefs", "policy", "status", "createdAt", "updatedAt", ...terminalField
74
74
  ], "Input request");
75
- if (request.schemaVersion !== 3)
76
- throw new Error("Input request must use schemaVersion 3.");
75
+ if (request.schemaVersion !== 1)
76
+ throw new Error("Input request must use schemaVersion 1.");
77
77
  const choices = validateChoices(request.choices);
78
78
  const createdAt = requireTimestamp(request.createdAt, "Input request createdAt");
79
79
  const base = {
80
- schemaVersion: 3,
80
+ schemaVersion: 1,
81
81
  id: requireIdentity(request.id, "Input request id"),
82
82
  taskId: requireIdentity(request.taskId, "Input request Task id"),
83
83
  requester: normalizeRequester(request.requester),
@@ -3,7 +3,7 @@ import { validateTaskRecordReference } from "../task/taskRecordReference.js";
3
3
  import { validateChangeSetManifest } from "./changeSetManifest.js";
4
4
  export function createWorkItemChangeSet(input, now) {
5
5
  return validateChangeSet({
6
- schemaVersion: 4,
6
+ schemaVersion: 1,
7
7
  ...input,
8
8
  changedPaths: [...input.changedPaths],
9
9
  manifest: validateChangeSetManifest(input.manifest),
@@ -11,8 +11,8 @@ export function createWorkItemChangeSet(input, now) {
11
11
  });
12
12
  }
13
13
  export function validateChangeSet(changeSet) {
14
- if (changeSet.schemaVersion !== 4)
15
- throw new Error("ChangeSet must use schemaVersion 4.");
14
+ if (changeSet.schemaVersion !== 1)
15
+ throw new Error("ChangeSet must use schemaVersion 1.");
16
16
  validateTaskRecordReference({ taskId: changeSet.taskId, localId: changeSet.id }, "changeSet");
17
17
  validateTaskRecordReference({
18
18
  taskId: changeSet.taskId,
@@ -4,7 +4,7 @@ import { normalizeCheckResult } from "./checkResult.js";
4
4
  export function createIntegrationAttempt(input, now) {
5
5
  const timestamp = now.toISOString();
6
6
  return validateIntegrationAttempt({
7
- schemaVersion: 6,
7
+ schemaVersion: 1,
8
8
  id: input.id,
9
9
  taskId: input.taskId,
10
10
  projectId: input.projectId,
@@ -132,8 +132,8 @@ export function supersedeIntegration(attempt, reason, now) {
132
132
  });
133
133
  }
134
134
  export function validateIntegrationAttempt(attempt) {
135
- if (attempt.schemaVersion !== 6) {
136
- throw new Error("IntegrationAttempt must use schemaVersion 6.");
135
+ if (attempt.schemaVersion !== 1) {
136
+ throw new Error("IntegrationAttempt must use schemaVersion 1.");
137
137
  }
138
138
  validateTaskRecordReference({
139
139
  taskId: attempt.taskId,
@@ -233,7 +233,7 @@ async function assertOperation(path, kind, commit, before, branch, source) {
233
233
  throw new Error(`Integration expected ${kind}, found ${active ?? "no active Git operation"}.`);
234
234
  if (kind === "rebase") {
235
235
  const directory = await gitPath(path, "rebase-merge");
236
- // Yui invokes the merge backend explicitly. A legacy apply-backend
236
+ // Yui invokes the merge backend explicitly. An apply-backend
237
237
  // operation cannot be silently treated as the same execution.
238
238
  const [onto, original, headName] = await Promise.all(["onto", "orig-head", "head-name"].map(name => readFile(resolve(directory, name), "utf8")));
239
239
  if (source.kind !== "upstream" || onto.trim() !== commit
@@ -1,5 +1,5 @@
1
1
  /**
2
- * One mailbox batch becomes one short synthetic user message. The durable
2
+ * One mailbox batch becomes one short system notification. The durable
3
3
  * records remain the context authority; this wake text carries only stable
4
4
  * identities and exact CLI reads, never copied Task or Provider narrative.
5
5
  */
@@ -11,6 +11,7 @@ export function createOperatorBatchPresentation(batchId, items) {
11
11
  text: [
12
12
  "[Yui updates]",
13
13
  "Yui recorded the following durable updates. Inspect the referenced records and present only information that changes the user's understanding, authorization, or next action.",
14
+ "This notification is not a new execution assignment or authorization to replay prior operations.",
14
15
  ...items.flatMap(renderItem)
15
16
  ].join("\n")
16
17
  };
@@ -2,7 +2,7 @@ import { createHash } from "node:crypto";
2
2
  import { requireIdentity, requirePositiveInteger, requireText, requireTimestamp } from "../domain/validation.js";
3
3
  import { validateTaskRecordReference } from "../task/taskRecordReference.js";
4
4
  import { recordOperationEvidence, validateOperationFacts } from "../kernel/operationFacts.js";
5
- export const CURRENT_DURABLE_JOB_SCHEMA_VERSION = 2;
5
+ export const CURRENT_DURABLE_JOB_SCHEMA_VERSION = 1;
6
6
  export const JOB_RUNNER_IMPLEMENTATION = Object.freeze({ id: "yui:job-runner", generation: "1" });
7
7
  export const DURABLE_JOB_TERMINAL_STATUSES = [
8
8
  "succeeded",
@@ -128,8 +128,8 @@ export async function runDurableJobRunner(specPath) {
128
128
  let child;
129
129
  try {
130
130
  // Issue 08: a structured argv step executes without a shell so its
131
- // tokens can never be reinterpreted; a legacy command step keeps the
132
- // shell form. A per-step cwd/env override applies to either form.
131
+ // tokens can never be reinterpreted; an explicit command step uses
132
+ // the shell. A per-step cwd/env override applies to either form.
133
133
  const stepCwd = jobStepDirectory(spec.workspace, step.cwd);
134
134
  const stepEnv = step.env === undefined
135
135
  ? spec.env