@zq-silk/yui 0.16.2 → 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 (111) hide show
  1. package/README.md +6 -4
  2. package/dist/agent/agent.js +4 -9
  3. package/dist/agent/executionComponents.js +4 -4
  4. package/dist/agentRun/agentRun.js +8 -8
  5. package/dist/artifacts/managedGit.js +3 -56
  6. package/dist/brief/taskBrief.js +3 -3
  7. package/dist/cli/updateOrchestrator.js +2 -13
  8. package/dist/cli/updatePorts.js +36 -69
  9. package/dist/cli/upgradeCommand.js +4 -8
  10. package/dist/cli.js +4 -7
  11. package/dist/commands/controllerCommands.js +1 -1
  12. package/dist/commands/taskCommands.js +8 -1
  13. package/dist/commands/taskRoleRuntimeStatus.js +1 -1
  14. package/dist/context/runInputContract.js +1 -1
  15. package/dist/controller/agentRuntimeObserver.js +4 -4
  16. package/dist/controller/clientRuntime.js +19 -44
  17. package/dist/controller/controller.js +16 -4
  18. package/dist/controller/fileSchedulerStoreAdapter.js +6 -6
  19. package/dist/controller/globalInputDelivery.js +3 -1
  20. package/dist/controller/jobSupervisor.js +3 -3
  21. package/dist/controller/providerRetryDelivery.js +128 -118
  22. package/dist/controller/runtime.js +1 -1
  23. package/dist/controller/structuredProviderObservation.js +1 -1
  24. package/dist/coordination/workMailbox.js +4 -4
  25. package/dist/core/controllerIdentity.js +25 -0
  26. package/dist/core/controllerProcessIdentity.js +2 -2
  27. package/dist/core/controllerServer.js +4 -2
  28. package/dist/core/protocol.js +1 -1
  29. package/dist/domain/validation.js +6 -0
  30. package/dist/event/taskEvent.js +3 -3
  31. package/dist/execution/workItemExecution.js +2 -2
  32. package/dist/executor/agentExecutor.js +6 -6
  33. package/dist/executor/effectiveLaunch.js +3 -3
  34. package/dist/grant/capabilityGrant.js +2 -2
  35. package/dist/input/inputRequest.js +4 -4
  36. package/dist/integration/changeSet.js +3 -3
  37. package/dist/integration/integrationAttempt.js +3 -3
  38. package/dist/integration/integrationSourceApplication.js +1 -1
  39. package/dist/job/durableJob.js +1 -1
  40. package/dist/job/jobRunner.js +2 -2
  41. package/dist/message/message.js +8 -6
  42. package/dist/milestone/milestone.js +3 -3
  43. package/dist/profile/agentProfile.js +3 -3
  44. package/dist/release/runtimeRelease.js +9 -7
  45. package/dist/repository/project.js +3 -3
  46. package/dist/resources/liveReferences.js +1 -1
  47. package/dist/resources/sqliteResourceRegistry.js +2 -2
  48. package/dist/review/reviewRound.js +5 -5
  49. package/dist/role/role.js +7 -8
  50. package/dist/runtime/acpProtocol.js +2 -3
  51. package/dist/runtime/agentDriverObservation.js +1 -1
  52. package/dist/runtime/agentHost.js +3 -3
  53. package/dist/runtime/agentHostProtocol.js +2 -2
  54. package/dist/runtime/codexInteractiveHost.js +1 -1
  55. package/dist/runtime/launchBroker.js +1 -1
  56. package/dist/runtime/processExitObservation.js +1 -1
  57. package/dist/runtime/providerContinuationReconciliationService.js +84 -75
  58. package/dist/runtime/providerRuntimeIdentity.js +3 -3
  59. package/dist/runtime/runtimeCoherence.js +7 -3
  60. package/dist/runtime/runtimeObservation.js +3 -3
  61. package/dist/runtime/sessionOwnerIdentity.js +1 -1
  62. package/dist/runtime/taskRuntimeIsolation.js +3 -3
  63. package/dist/runtime/tmuxAdapters.js +3 -3
  64. package/dist/scheduler/taskWake.js +1 -1
  65. package/dist/storage/baselineSchema.js +606 -0
  66. package/dist/storage/homeLayout.js +5 -16
  67. package/dist/storage/recordValidation.js +16 -4
  68. package/dist/storage/sqliteSchema.js +106 -1741
  69. package/dist/storage/sqliteStore.js +16 -14
  70. package/dist/storage/storageSchema.js +8 -7
  71. package/dist/storage/storageVersions.js +23 -16
  72. package/dist/storage/taskStore.js +3 -29
  73. package/dist/storage/upgrade/upgradeOrchestrator.js +14 -102
  74. package/dist/task/task.js +15 -7
  75. package/dist/task/taskActivation.js +5 -4
  76. package/dist/telemetry/sqliteTelemetryStore.js +2 -2
  77. package/dist/verification/gateArtifact.js +5 -3
  78. package/dist/verification/verificationPlan.js +6 -7
  79. package/dist/workItem/workItem.js +6 -6
  80. package/dist/workspace/cleanupInspection.js +1 -9
  81. package/dist/worktree/managedWorkspace.js +3 -3
  82. package/docs/managed-turn-and-session-runtime.md +26 -14
  83. package/docs/managed-turn-and-session-runtime.zh-CN.md +18 -10
  84. package/docs/release-workflow.md +52 -300
  85. package/docs/release-workflow.zh-CN.md +41 -234
  86. package/docs/sqlite-control-plane-design.md +48 -289
  87. package/docs/sqlite-control-plane-design.zh-CN.md +37 -53
  88. package/docs/storage-baseline.md +132 -0
  89. package/docs/storage-baseline.zh-CN.md +106 -0
  90. package/docs/task-delivery.md +3 -4
  91. package/docs/task-delivery.zh-CN.md +3 -3
  92. package/docs/testing/verification-levels.md +40 -180
  93. package/docs/testing/verification-levels.zh-CN.md +27 -131
  94. package/i18n/README.zh-CN.md +5 -4
  95. package/package.json +1 -1
  96. package/dist/storage/migrations/agentFailureContext.js +0 -22
  97. package/dist/storage/migrations/agentRunContract.js +0 -159
  98. package/dist/storage/migrations/artifactsToGit.js +0 -338
  99. package/dist/storage/migrations/collapseWorktreeLayout.js +0 -963
  100. package/dist/storage/migrations/currentInputContract.js +0 -86
  101. package/dist/storage/migrations/currentRuntimeContract.js +0 -228
  102. package/dist/storage/migrations/historicalVerificationPlan.js +0 -35
  103. package/dist/storage/migrations/integrationContinuation.js +0 -105
  104. package/dist/storage/migrations/narrowAgentFailureContext.js +0 -65
  105. package/dist/storage/migrations/notificationOnlyWakes.js +0 -74
  106. package/dist/storage/migrations/removeRuntimeGeneration.js +0 -207
  107. package/dist/storage/migrations/submitIntent.js +0 -126
  108. package/dist/storage/migrations/unifyHomeLayout.js +0 -925
  109. package/dist/storage/migrations/verificationPlanV1.js +0 -162
  110. package/dist/storage/migrations/verificationPolicy.js +0 -74
  111. package/dist/storage/migrations/workItemHistory.js +0 -46
@@ -1,4 +1,4 @@
1
- export const RUNTIME_PROCESS_EXIT_SCHEMA_VERSION = 2;
1
+ export const RUNTIME_PROCESS_EXIT_SCHEMA_VERSION = 1;
2
2
  export const RUNTIME_PROCESS_EXIT_TASK_EVENT = "runtime.process-exit-observed";
3
3
  export function validateRuntimeProcessExitObservation(observation) {
4
4
  if (observation.schemaVersion !== RUNTIME_PROCESS_EXIT_SCHEMA_VERSION) {
@@ -13,91 +13,100 @@ export class ProviderContinuationReconciliationService {
13
13
  store;
14
14
  sink;
15
15
  metadata;
16
+ onError;
16
17
  #schedules = new Map();
17
- constructor(store, sink, metadata) {
18
+ constructor(store, sink, metadata, onError = error => { throw error; }) {
18
19
  this.store = store;
19
20
  this.sink = sink;
20
21
  this.metadata = metadata;
22
+ this.onError = onError;
21
23
  }
22
24
  async reconcile(now) {
23
25
  const changedTaskIds = new Set();
24
26
  for (const task of this.store.listTasks().filter((entry) => (entry.status === "active" && entry.executionGate.state === "enabled"))) {
25
- const events = this.store.listEvents(task.id);
26
- const groups = groupDetachedContinuations(projectProviderContinuations(events), events.map(runtimeObservationFromTaskEvent)
27
- .filter((entry) => entry !== null));
28
- for (const [groupKey, candidates] of groups) {
29
- const group = candidates.map(({ continuation }) => continuation);
30
- const previous = this.#schedules.get(groupKey);
31
- if (previous !== undefined && Date.parse(previous.nextReconcileAt) > now.getTime()) {
32
- continue;
33
- }
34
- let result;
35
- try {
36
- result = await reconcileKnownDetachedContinuations({
37
- port: this.metadata,
38
- continuations: group,
39
- ...(previous === undefined ? {} : { previous }),
40
- now
41
- });
42
- }
43
- catch (error) {
44
- // One malformed identity group must not restart or block the
45
- // Controller. Keep it writer-owned and retry through the same
46
- // bounded, metadata-only schedule.
47
- result = {
48
- continuations: group, quality: "unavailable", changed: false,
49
- schedule: failureSchedule(groupKey, previous, now),
50
- failure: standardAgentError({
51
- source: "yui", phase: "turn-reconcile",
52
- message: error instanceof Error ? error.message : String(error),
53
- raw: serializeAgentErrorRaw(error)
54
- })
55
- };
56
- }
57
- if (result.schedule === null)
58
- this.#schedules.delete(groupKey);
59
- else
60
- this.#schedules.set(groupKey, result.schedule);
61
- if (result.failure !== undefined) {
62
- const failure = result.failure;
63
- // One original failure and one circuit-limit notice, not one wake per
64
- // poll. Existing observations deduplicate across Controller restarts.
65
- const digest = createHash("sha256").update(JSON.stringify([
66
- task.id, candidates.map(entry => entry.fence), failure.raw,
67
- result.schedule?.circuitOpenUntil === undefined ? "unavailable" : "circuit-open"
68
- ])).digest("hex");
69
- const eventId = `continuation-reconcile-error:${digest}`;
70
- if (!events.some(event => event.payload.eventId === eventId
71
- || event.type === "runtime.agent-error" && event.payload.sourceEventId === eventId)) {
72
- const observation = createRuntimeObservation({
73
- schemaVersion: 4, eventId, semanticKey: eventId,
74
- kind: "observer.health", authority: "controller",
75
- receivedAt: now.toISOString(), observedAt: now.toISOString(),
76
- fence: candidates[0].fence,
77
- payload: {
78
- sourceId: "continuation-metadata", observerStatus: "unavailable",
79
- observerDetail: failure.message,
80
- failure: { error: { ...failure, raw: serializeAgentErrorRaw({
81
- failure, targets: group.map(entry => entry.identity),
82
- schedule: result.schedule,
83
- confirmed: "Metadata query did not prove quiescence; existing writer ownership is preserved.",
84
- unknown: "Continuation execution, result and external effects."
85
- }) } }
86
- }
27
+ try {
28
+ const events = this.store.listEvents(task.id);
29
+ const groups = groupDetachedContinuations(projectProviderContinuations(events), events.map(runtimeObservationFromTaskEvent)
30
+ .filter((entry) => entry !== null));
31
+ for (const [groupKey, candidates] of groups) {
32
+ const group = candidates.map(({ continuation }) => continuation);
33
+ const previous = this.#schedules.get(groupKey);
34
+ if (previous !== undefined && Date.parse(previous.nextReconcileAt) > now.getTime()) {
35
+ continue;
36
+ }
37
+ let result;
38
+ try {
39
+ result = await reconcileKnownDetachedContinuations({
40
+ port: this.metadata,
41
+ continuations: group,
42
+ ...(previous === undefined ? {} : { previous }),
43
+ now
87
44
  });
88
- if (this.sink.observeRuntimeObservation(observation, now) === "applied")
89
- changedTaskIds.add(task.id);
45
+ }
46
+ catch (error) {
47
+ // One malformed identity group must not restart or block the
48
+ // Controller. Keep it writer-owned and retry through the same
49
+ // bounded, metadata-only schedule.
50
+ result = {
51
+ continuations: group, quality: "unavailable", changed: false,
52
+ schedule: failureSchedule(groupKey, previous, now),
53
+ failure: standardAgentError({
54
+ source: "yui", phase: "turn-reconcile",
55
+ message: error instanceof Error ? error.message : String(error),
56
+ raw: serializeAgentErrorRaw(error)
57
+ })
58
+ };
59
+ }
60
+ if (result.schedule === null)
61
+ this.#schedules.delete(groupKey);
62
+ else
63
+ this.#schedules.set(groupKey, result.schedule);
64
+ if (result.failure !== undefined) {
65
+ const failure = result.failure;
66
+ // One original failure and one circuit-limit notice, not one wake per
67
+ // poll. Existing observations deduplicate across Controller restarts.
68
+ const digest = createHash("sha256").update(JSON.stringify([
69
+ task.id, candidates.map(entry => entry.fence), failure.raw,
70
+ result.schedule?.circuitOpenUntil === undefined ? "unavailable" : "circuit-open"
71
+ ])).digest("hex");
72
+ const eventId = `continuation-reconcile-error:${digest}`;
73
+ if (!events.some(event => event.payload.eventId === eventId
74
+ || event.type === "runtime.agent-error" && event.payload.sourceEventId === eventId)) {
75
+ const observation = createRuntimeObservation({
76
+ schemaVersion: 1, eventId, semanticKey: eventId,
77
+ kind: "observer.health", authority: "controller",
78
+ receivedAt: now.toISOString(), observedAt: now.toISOString(),
79
+ fence: candidates[0].fence,
80
+ payload: {
81
+ sourceId: "continuation-metadata", observerStatus: "unavailable",
82
+ observerDetail: failure.message,
83
+ failure: { error: { ...failure, raw: serializeAgentErrorRaw({
84
+ failure, targets: group.map(entry => entry.identity),
85
+ schedule: result.schedule,
86
+ confirmed: "Metadata query did not prove quiescence; existing writer ownership is preserved.",
87
+ unknown: "Continuation execution, result and external effects."
88
+ }) } }
89
+ }
90
+ });
91
+ if (this.sink.observeRuntimeObservation(observation, now) === "applied")
92
+ changedTaskIds.add(task.id);
93
+ }
94
+ }
95
+ for (let index = 0; index < group.length; index += 1) {
96
+ const before = group[index];
97
+ const after = result.continuations[index];
98
+ if (sameContinuationState(before, after))
99
+ continue;
100
+ const disposition = this.sink.observeRuntimeObservation(reconciliationObservation(after, candidates[index].fence, now), now);
101
+ if (disposition === "applied")
102
+ changedTaskIds.add(after.taskId);
90
103
  }
91
104
  }
92
- for (let index = 0; index < group.length; index += 1) {
93
- const before = group[index];
94
- const after = result.continuations[index];
95
- if (sameContinuationState(before, after))
96
- continue;
97
- const disposition = this.sink.observeRuntimeObservation(reconciliationObservation(after, candidates[index].fence, now), now);
98
- if (disposition === "applied")
99
- changedTaskIds.add(after.taskId);
100
- }
105
+ }
106
+ catch (error) {
107
+ this.onError(new Error(`Continuation reconciliation failed for ${task.id}: `
108
+ + `${error instanceof Error ? error.message : String(error)}. `
109
+ + "Unconfirmed continuation state and writer ownership are retained.", { cause: error }));
101
110
  }
102
111
  }
103
112
  return Object.freeze([...changedTaskIds].sort());
@@ -167,7 +176,7 @@ function reconciliationObservation(continuation, sourceFence, now) {
167
176
  const settled = continuation.execution === "quiescent"
168
177
  && continuation.observation === "exact";
169
178
  return createRuntimeObservation({
170
- schemaVersion: 4,
179
+ schemaVersion: 1,
171
180
  eventId: `continuation-reconcile:${digest}`,
172
181
  semanticKey: `continuation-reconcile:${digest}`,
173
182
  kind: settled ? "continuation.settled" : "continuation.started",
@@ -3,7 +3,7 @@ import { isStandardAgentError } from "./agentError.js";
3
3
  export function createProviderRuntimeBinding(input) {
4
4
  const startedAt = timestamp(input.startedAt, "Provider Conversation startedAt");
5
5
  return validateProviderRuntimeBinding({
6
- schemaVersion: 5,
6
+ schemaVersion: 1,
7
7
  providerNamespace: identity(input.providerNamespace, "Provider namespace"),
8
8
  accountScope: identity(input.accountScope, "Provider account scope"),
9
9
  currentConversationEpoch: 1,
@@ -308,8 +308,8 @@ export function supersedeProviderConversation(raw, input) {
308
308
  });
309
309
  }
310
310
  export function validateProviderRuntimeBinding(value) {
311
- if (value.schemaVersion !== 5)
312
- throw new Error("Provider Runtime Binding schemaVersion must be 5.");
311
+ if (value.schemaVersion !== 1)
312
+ throw new Error("Provider Runtime Binding schemaVersion must be 1.");
313
313
  identity(value.providerNamespace, "Provider namespace");
314
314
  identity(value.accountScope, "Provider account scope");
315
315
  integer(value.currentConversationEpoch, 1, "Current Provider Conversation epoch");
@@ -1,4 +1,5 @@
1
1
  import { resolve } from "node:path";
2
+ import { isStorageVersion, compareStorageVersions } from "../storage/storageVersions.js";
2
3
  import { callController as defaultCallController } from "../core/controllerClient.js";
3
4
  import { inspectStorageSchema } from "../storage/storageSchema.js";
4
5
  import { yuiVersionIdentity } from "../version.js";
@@ -41,9 +42,12 @@ function validateVersionIdentity(value) {
41
42
  throw new Error("Yui version identity is invalid.");
42
43
  const version = requireText(value.version, "Yui version");
43
44
  const controllerProtocolVersion = requireVersion(value.controllerProtocolVersion, "Controller protocol version");
44
- const storageVersion = requireVersion(value.storageVersion, "Storage version");
45
- const minimumStorageVersion = requireVersion(value.minimumStorageVersion, "Minimum storage migration version");
46
- if (minimumStorageVersion > storageVersion) {
45
+ const storageVersion = value.storageVersion;
46
+ const minimumStorageVersion = value.minimumStorageVersion;
47
+ if (!isStorageVersion(storageVersion) || !isStorageVersion(minimumStorageVersion)) {
48
+ throw new Error("Storage version must be a major.minor identity.");
49
+ }
50
+ if (compareStorageVersions(minimumStorageVersion, storageVersion) > 0) {
47
51
  throw new Error("Minimum storage migration version cannot exceed the current storage version.");
48
52
  }
49
53
  return {
@@ -84,8 +84,8 @@ const PROVIDER_STATE = new Set([
84
84
  "operation.failed"
85
85
  ]);
86
86
  export function createRuntimeObservation(input) {
87
- if (input.schemaVersion !== 4)
88
- throw new Error("Runtime observation schemaVersion must be 4.");
87
+ if (input.schemaVersion !== 1)
88
+ throw new Error("Runtime observation schemaVersion must be 1.");
89
89
  if (!KINDS.includes(input.kind))
90
90
  throw new Error("Runtime observation kind is invalid.");
91
91
  if (!AUTHORITIES.includes(input.authority))
@@ -126,7 +126,7 @@ export function createRuntimeObservation(input) {
126
126
  throw new Error("Runtime observation ordinal must be a non-negative safe integer.");
127
127
  }
128
128
  return Object.freeze({
129
- schemaVersion: 4,
129
+ schemaVersion: 1,
130
130
  eventId: requireIdentity(input.eventId, "Runtime observation event id"),
131
131
  semanticKey: requireIdentity(input.semanticKey, "Runtime observation semantic key"),
132
132
  kind: input.kind,
@@ -36,7 +36,7 @@ export function createSessionOwnerIdentity(input) {
36
36
  }
37
37
  const tmux = input.tmux;
38
38
  return Object.freeze({
39
- schemaVersion: 2,
39
+ schemaVersion: 1,
40
40
  kind: "yui-session-owner",
41
41
  owner: Object.freeze({
42
42
  scope: owner.scope,
@@ -154,7 +154,7 @@ export function createTaskRuntimeIsolationDescriptor(input) {
154
154
  const portPreference = ports(input.policy?.portPreference ?? [], "Port preference");
155
155
  const portAllocations = allocations(input.policy?.portAllocations ?? []);
156
156
  return Object.freeze({
157
- schemaVersion: 2,
157
+ schemaVersion: 1,
158
158
  kind: "yui-task-runtime-isolation",
159
159
  taskId,
160
160
  workspace: Object.freeze({ owner, root: canonicalPath(workspace.root, "Workspace root") }),
@@ -181,7 +181,7 @@ export function parseTaskRuntimeIsolationDescriptor(serialized) {
181
181
  if (!isRecord(value) || value.kind !== "yui-task-runtime-isolation") {
182
182
  throw new Error(`Expected yui-task-runtime-isolation descriptor; found ${isRecord(value) && typeof value.kind === "string" ? value.kind : "unknown"}.`);
183
183
  }
184
- if (value.schemaVersion !== 2) {
184
+ if (value.schemaVersion !== 1) {
185
185
  throw new Error("Task runtime isolation descriptor schema version is invalid.");
186
186
  }
187
187
  const workspace = requireRecord(value.workspace, "Task runtime workspace");
@@ -189,7 +189,7 @@ export function parseTaskRuntimeIsolationDescriptor(serialized) {
189
189
  const external = requireRecord(value.externalCapabilities, "Task runtime external capabilities");
190
190
  const owner = taskRuntimeWorkspaceOwner(requireRecord(workspace.owner, "Task runtime workspace owner"));
191
191
  const descriptor = {
192
- schemaVersion: 2,
192
+ schemaVersion: 1,
193
193
  kind: "yui-task-runtime-isolation",
194
194
  taskId: requireIdentity(value.taskId, "Task id"),
195
195
  workspace: {
@@ -249,8 +249,8 @@ export class TmuxSessionHost {
249
249
  const yuiHome = planned.launch.env.YUI_HOME;
250
250
  const childLifecycle = planned.launch.childLifecycle;
251
251
  // Global Codex retains the native TUI inside a thin Host that acknowledges
252
- // its own App Server startup response. Existing live TUIs (including
253
- // 0.15.0 Sessions) remain directly attachable without replacing them.
252
+ // its own App Server startup response. Current live TUIs remain directly
253
+ // attachable without replacing their native conversation.
254
254
  if (reuseInteractivePane
255
255
  || (!interactiveCodex && (yuiHome === undefined
256
256
  || childLifecycle === undefined
@@ -310,7 +310,7 @@ export class TmuxSessionHost {
310
310
  throw new Error("Managed Task Agent Host launch is missing its Session Manifest.");
311
311
  }
312
312
  const reservation = broker.reserve(Object.freeze({
313
- schemaVersion: 2,
313
+ schemaVersion: 1,
314
314
  ...(request.runId === undefined ? {} : { startupRunId: request.runId }),
315
315
  command: planned.launch.command,
316
316
  args: [...planned.launch.args],
@@ -1,7 +1,7 @@
1
1
  import { requireIdentity, requirePositiveInteger, requireText, requireTimestamp } from "../domain/validation.js";
2
2
  import { TASK_RECORD_ID_PREFIXES } from "../task/taskRecordReference.js";
3
3
  import { copyRef } from "../coordination/workMailbox.js";
4
- export const CURRENT_TASK_WAKE_SCHEMA_VERSION = 2;
4
+ export const CURRENT_TASK_WAKE_SCHEMA_VERSION = 1;
5
5
  export function createTaskWake(input) {
6
6
  if (Object.hasOwn(input, "runId"))
7
7
  throw new Error("A notification wake cannot dispatch an AgentRun.");