@zq-silk/yui 0.15.8 → 0.15.11

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 (151) hide show
  1. package/ARCHITECTURE.md +2 -0
  2. package/ARCHITECTURE.zh-CN.md +151 -0
  3. package/README.md +211 -14
  4. package/dist/agent/launchEnvironment.js +7 -0
  5. package/dist/artifacts/artifactCapability.js +74 -0
  6. package/dist/artifacts/artifactCommitLock.js +249 -0
  7. package/dist/artifacts/artifactPaths.js +151 -0
  8. package/dist/artifacts/gitArtifactRef.js +146 -0
  9. package/dist/artifacts/managedGit.js +332 -0
  10. package/dist/artifacts/taskArtifactRepository.js +277 -0
  11. package/dist/cli/commandCatalog.js +40 -16
  12. package/dist/cli/interactionPolicy.js +3 -3
  13. package/dist/cli/updateOrchestrator.js +24 -1
  14. package/dist/cli/updatePorts.js +7 -3
  15. package/dist/cli/upgradeCommand.js +42 -2
  16. package/dist/cli.js +403 -93
  17. package/dist/commands/globalRoleCommands.js +314 -4
  18. package/dist/commands/operatorCommands.js +33 -2
  19. package/dist/commands/projectCommands.js +6 -7
  20. package/dist/commands/releaseCommands.js +18 -0
  21. package/dist/commands/taskActivationCommands.js +22 -0
  22. package/dist/commands/taskActor.js +25 -0
  23. package/dist/commands/taskCommands.js +846 -155
  24. package/dist/commands/taskIntegrationCommands.js +16 -38
  25. package/dist/commands/taskIntegrationQueueCommands.js +1 -1
  26. package/dist/commands/taskRemoteDeliveryCommand.js +6 -6
  27. package/dist/commands/taskRoleRuntimeStatus.js +35 -0
  28. package/dist/context/runContextPack.js +28 -16
  29. package/dist/context/taskContext.js +64 -5
  30. package/dist/controller/agentHostObservation.js +155 -0
  31. package/dist/controller/clientRuntime.js +17 -2
  32. package/dist/controller/controller.js +11 -2
  33. package/dist/controller/fileSchedulerStoreAdapter.js +446 -13
  34. package/dist/controller/globalInputDelivery.js +119 -0
  35. package/dist/controller/jobControl.js +6 -2
  36. package/dist/controller/resourceInventory.js +14 -4
  37. package/dist/controller/resourceInventoryLinux.js +2 -6
  38. package/dist/controller/runtime.js +81 -6
  39. package/dist/controller/runtimeEventInbox.js +32 -3
  40. package/dist/controller/runtimeEventProcessor.js +26 -6
  41. package/dist/controller/runtimeHookRunFence.js +75 -19
  42. package/dist/controller/structuredProviderObservation.js +133 -70
  43. package/dist/coordination/workMailboxQueue.js +5 -0
  44. package/dist/execution/workItemExecutionProjection.js +1 -1
  45. package/dist/executor/agentExecutor.js +64 -4
  46. package/dist/executor/executorRegistry.js +3 -0
  47. package/dist/executor/fileRoleLaunchPlanner.js +78 -118
  48. package/dist/integration/deliveryObligation.js +2 -1
  49. package/dist/integration/gitIntegrationService.js +312 -382
  50. package/dist/integration/integrationAttempt.js +30 -4
  51. package/dist/integration/integrationQueueService.js +7 -7
  52. package/dist/integration/integrationSourceApplication.js +323 -0
  53. package/dist/kernel/builtinCapabilities.js +32 -24
  54. package/dist/message/globalInterrupt.js +33 -0
  55. package/dist/message/inputControlResolution.js +106 -0
  56. package/dist/message/message.js +423 -0
  57. package/dist/message/messageContinuation.js +126 -3
  58. package/dist/message/taskInterrupt.js +34 -0
  59. package/dist/observability/orchestrationMetrics.js +1 -1
  60. package/dist/plugins/pluginService.js +11 -3
  61. package/dist/release/releaseHandover.js +22 -0
  62. package/dist/release/releaseWorkflowPorts.js +15 -7
  63. package/dist/repository/gitWorkspace.js +72 -15
  64. package/dist/repository/taskWorkspaceCoordinator.js +134 -0
  65. package/dist/repository/taskWorkspacePreparer.js +120 -49
  66. package/dist/repository/workItemCandidateSnapshot.js +34 -0
  67. package/dist/resources/projectResource.js +0 -48
  68. package/dist/resources/projectResourceService.js +3 -81
  69. package/dist/resources/resourceDiscovery.js +3 -2
  70. package/dist/runtime/agentHost.js +152 -72
  71. package/dist/runtime/agentHostCompatibility.js +127 -0
  72. package/dist/runtime/agentHostProtocol.js +53 -0
  73. package/dist/runtime/executionEnvironment.js +0 -19
  74. package/dist/runtime/launchBroker.js +6 -0
  75. package/dist/runtime/sessionReconciliation.js +4 -4
  76. package/dist/runtime/taskRuntimeIsolation.js +30 -6
  77. package/dist/runtime/tmuxAdapters.js +5 -3
  78. package/dist/scheduler/operatorEvent.js +4 -0
  79. package/dist/scheduler/taskExecutionProjection.js +12 -1
  80. package/dist/scheduler/wakeReason.js +7 -1
  81. package/dist/scheduler/wakeupQueue.js +2 -0
  82. package/dist/setup/setupCommand.js +29 -16
  83. package/dist/storage/homeLayout.js +130 -0
  84. package/dist/storage/migrations/artifactsToGit.js +338 -0
  85. package/dist/storage/migrations/collapseWorktreeLayout.js +963 -0
  86. package/dist/storage/migrations/integrationContinuation.js +104 -0
  87. package/dist/storage/migrations/submitIntent.js +126 -0
  88. package/dist/storage/migrations/unifyHomeLayout.js +925 -0
  89. package/dist/storage/sqliteSchema.js +173 -7
  90. package/dist/storage/sqliteStore.js +41 -22
  91. package/dist/storage/storageVersions.js +1 -1
  92. package/dist/storage/storeRpc.js +2 -1
  93. package/dist/storage/upgrade/upgradeOrchestrator.js +95 -2
  94. package/dist/task/archiveDiagnostics.js +128 -0
  95. package/dist/task/nextAction.js +44 -11
  96. package/dist/task/taskActivation.js +26 -0
  97. package/dist/task/taskActivationService.js +85 -69
  98. package/dist/task/taskSubmission.js +236 -0
  99. package/dist/web/assets/client/app.js +58 -2
  100. package/dist/web/assets/client/components.js +1 -0
  101. package/dist/web/assets/client/i18n.js +6 -0
  102. package/dist/web/assets/client/taskSurface.js +202 -7
  103. package/dist/web/assets/client/view.js +7 -4
  104. package/dist/web/assets/shell.js +23 -0
  105. package/dist/web/assets/styles/layout.js +1 -1
  106. package/dist/web/assets/styles/widgets.js +12 -0
  107. package/dist/web/webServer.js +135 -4
  108. package/dist/web/webSnapshot.js +4 -3
  109. package/dist/web/webTaskSurface.js +225 -8
  110. package/dist/workItem/workItem.js +14 -10
  111. package/dist/workspace/workItemChangeSetManager.js +18 -2
  112. package/docs/agent-result-consumption.md +2 -0
  113. package/docs/agent-result-consumption.zh-CN.md +81 -0
  114. package/docs/agent-runtime-drivers.md +2 -0
  115. package/docs/agent-runtime-drivers.zh-CN.md +77 -0
  116. package/docs/architecture/README.md +44 -32
  117. package/docs/architecture/README.zh-CN.md +43 -0
  118. package/docs/architecture/capabilities-and-resources.md +118 -79
  119. package/docs/architecture/capabilities-and-resources.zh-CN.md +83 -0
  120. package/docs/managed-turn-and-session-runtime.md +2 -0
  121. package/docs/managed-turn-and-session-runtime.zh-CN.md +180 -0
  122. package/docs/observability/README.md +2 -0
  123. package/docs/observability/README.zh-CN.md +71 -0
  124. package/docs/plugin-sdk.md +320 -217
  125. package/docs/plugin-sdk.zh-CN.md +293 -0
  126. package/docs/provider-runtime.md +2 -0
  127. package/docs/provider-runtime.zh-CN.md +132 -0
  128. package/docs/release-workflow.md +41 -0
  129. package/docs/release-workflow.zh-CN.md +266 -0
  130. package/docs/roles-and-configuration.md +2 -0
  131. package/docs/roles-and-configuration.zh-CN.md +96 -0
  132. package/docs/sqlite-control-plane-design.md +225 -1
  133. package/docs/sqlite-control-plane-design.zh-CN.md +62 -0
  134. package/docs/task-dag-semantics.md +80 -57
  135. package/docs/task-dag-semantics.zh-CN.md +59 -0
  136. package/docs/task-delivery.md +2 -0
  137. package/docs/task-delivery.zh-CN.md +82 -0
  138. package/docs/task-local-identity.md +2 -0
  139. package/docs/task-local-identity.zh-CN.md +58 -0
  140. package/docs/testing/verification-levels.md +26 -0
  141. package/docs/testing/verification-levels.zh-CN.md +80 -0
  142. package/i18n/README.zh-CN.md +199 -10
  143. package/package.json +2 -1
  144. package/skills/yui-leader/SKILL.md +88 -331
  145. package/skills/yui-leader/references/execution.md +405 -0
  146. package/skills/yui-leader/references/integration.md +52 -2
  147. package/skills/yui-leader/references/planning.md +109 -0
  148. package/skills/yui-leader/references/task-plugins.md +8 -4
  149. package/skills/yui-operator/SKILL.md +22 -4
  150. package/skills/yui-runtime/SKILL.md +27 -0
  151. package/skills/yui-runtime/references/publication.md +20 -0
@@ -0,0 +1,104 @@
1
+ import { createHash } from "node:crypto";
2
+ import { resolve } from "node:path";
3
+ import { durableJobIdempotencyKey } from "../../job/durableJob.js";
4
+ import { resolveProjectVerificationPlan, verificationPlanDigest, planBootstrapJobSteps, planL2JobSteps } from "../../verification/verificationPlan.js";
5
+ /** Classify only known v19 Git conflicts. Manual strategy and CAS blockers
6
+ * keep their meaning. Never synthesize candidate/Job success or edit history. */
7
+ export function migrateIntegrationContinuation(db) {
8
+ const rows = db.prepare("SELECT task_id, integration_id, payload FROM integration_attempts").all();
9
+ const update = db.prepare("UPDATE integration_attempts SET status = ?, payload = ? WHERE task_id = ? AND integration_id = ?");
10
+ for (const row of rows) {
11
+ const attempt = JSON.parse(row.payload);
12
+ if (attempt.schemaVersion !== 6)
13
+ continue;
14
+ const proven = migrateBoundFastForward(db, attempt);
15
+ if (proven !== undefined) {
16
+ update.run(proven.status, JSON.stringify(proven), row.task_id, row.integration_id);
17
+ continue;
18
+ }
19
+ if (attempt.status !== "blocked")
20
+ continue;
21
+ const source = attempt.source;
22
+ const summary = attempt.conflict?.summary;
23
+ if (typeof summary !== "string")
24
+ continue;
25
+ const ordinary = (source?.kind === "upstream" && source.strategy === "rebase"
26
+ && summary.startsWith("Upstream rebase conflicts"))
27
+ || (source?.kind === "work-item" && source.strategy === "merge"
28
+ && summary.startsWith("WorkItem merge conflicts"))
29
+ || (source?.kind === "work-item" && source.strategy === "cherry-pick"
30
+ && summary.startsWith(`WorkItem ${source.workItemId} commit `)
31
+ && summary.includes(" conflicts with "));
32
+ if (!ordinary)
33
+ continue;
34
+ update.run("conflicted", JSON.stringify({ ...attempt, status: "conflicted" }), row.task_id, row.integration_id);
35
+ }
36
+ }
37
+ /** v19 bound a Job only after successful source application. For FF, its
38
+ * exact checked head IS the immutable source result, so the existing records
39
+ * prove application without inventing a reflog action or a successful result.
40
+ * Other old source strategies need evidence not available in these DB records.
41
+ * Keep this interpretation at the migration boundary, never in runtime reads. */
42
+ function migrateBoundFastForward(db, attempt) {
43
+ if (!["running", "validating"].includes(attempt.status) || attempt.jobId === undefined
44
+ || attempt.source.kind !== "work-item" || attempt.source.strategy !== "ff")
45
+ return;
46
+ const read = (sql, ...keys) => {
47
+ const row = db.prepare(sql).get(...keys);
48
+ return row === undefined ? undefined : JSON.parse(row.payload);
49
+ };
50
+ const task = read("SELECT payload FROM task_records WHERE task_id = ?", attempt.taskId);
51
+ const project = read("SELECT payload FROM projects WHERE id = ?", attempt.projectId);
52
+ const job = read("SELECT payload FROM durable_jobs WHERE task_id = ? AND job_id = ?", attempt.taskId, attempt.jobId);
53
+ const workspaces = db.prepare("SELECT payload FROM managed_workspaces WHERE task_id = ?").all(attempt.taskId)
54
+ .map(row => JSON.parse(row.payload));
55
+ const workspace = workspaces.find(w => w.owner.type === "integration-attempt"
56
+ && w.owner.taskId === attempt.taskId && w.owner.integrationAttemptId === attempt.id);
57
+ const main = workspaces.find(w => w.owner.type === "task" && w.owner.taskId === attempt.taskId);
58
+ const entry = workspace?.entries.find(e => e.projectId === attempt.projectId && e.access === "write");
59
+ const mainEntry = main?.entries.find(e => e.projectId === attempt.projectId && e.access === "write");
60
+ const binding = task?.projectBindings.find(b => b.projectId === attempt.projectId);
61
+ if (task?.id !== attempt.taskId || project?.id !== attempt.projectId || binding === undefined
62
+ || workspace === undefined || entry === undefined || mainEntry === undefined
63
+ || workspace.entries.length !== 1 || entry.path !== workspace.root
64
+ || entry.baseCommit !== attempt.beforeCommit
65
+ || job?.id !== attempt.jobId || job.taskId !== attempt.taskId
66
+ || job.owner.kind !== "integration-attempt" || job.owner.integrationAttemptId !== attempt.id
67
+ || job.projectId !== attempt.projectId || job.workspace !== workspace.root
68
+ || job.operation.targetId !== job.workspace
69
+ || job.head !== attempt.source.resultCommit
70
+ || (attempt.candidateCommit !== undefined && attempt.candidateCommit !== job.head)
71
+ || job.operation.inputDigest !== durableJobIdempotencyKey(job))
72
+ return;
73
+ let steps = attempt.checkCommands.map((command, index) => ({
74
+ name: `check-${index + 1}`, command, timeoutMs: 30 * 60_000
75
+ }));
76
+ if (attempt.gatePlanDigest !== undefined) {
77
+ const plan = resolveProjectVerificationPlan(project);
78
+ if (plan === undefined || verificationPlanDigest(plan) !== attempt.gatePlanDigest)
79
+ return;
80
+ steps = [...planBootstrapJobSteps(plan), ...planL2JobSteps(plan)].map(step => ({
81
+ ...step, timeoutMs: 30 * 60_000
82
+ }));
83
+ }
84
+ const inputDigest = durableJobIdempotencyKey(job);
85
+ if (inputDigest !== durableJobIdempotencyKey({ ...job, steps }))
86
+ return;
87
+ const branch = entry.branch;
88
+ return {
89
+ ...attempt,
90
+ candidateCommit: job.head,
91
+ checkInputDigest: inputDigest,
92
+ sourceProgress: {
93
+ workspace: resolve(workspace.root), branch: fullRef(branch), head: job.head,
94
+ completedSteps: 1,
95
+ sourceDigest: createHash("sha256").update(JSON.stringify([
96
+ attempt.taskId, attempt.id, attempt.projectId, attempt.targetRef,
97
+ attempt.beforeCommit, attempt.source, resolve(workspace.root), branch
98
+ ])).digest("hex")
99
+ }
100
+ };
101
+ }
102
+ function fullRef(branch) {
103
+ return branch.startsWith("refs/") ? branch : `refs/heads/${branch}`;
104
+ }
@@ -0,0 +1,126 @@
1
+ import { createTaskEvent } from "../../event/taskEvent.js";
2
+ /**
3
+ * Storage 18 -> 19 data step for task-32 Requirement A (submit intent & Draft
4
+ * auto-routing).
5
+ *
6
+ * This helper is INDEPENDENT, deterministic and idempotent. The unified 18 -> 19
7
+ * migration owned by the artifacts WorkItem REGISTERS it (as its `migrateData`)
8
+ * and bumps `CURRENT_STORAGE_VERSION`; this module neither registers a second
9
+ * migration nor changes any schema.
10
+ *
11
+ * Requirement A adds three optional fields inside `messages.payload`, all part of
12
+ * this same 18 -> 19 contract even though each is optional — "optional" governs a
13
+ * single record's shape, not the Home compatibility line, so the version
14
+ * transition is still declared here and carried by the unified migration:
15
+ *
16
+ * - `intent` (record | discuss | develop): an absent value already reads as
17
+ * `discuss` (never `develop`), so historical Messages need no rewrite.
18
+ * - `submissionKey`: the client-chosen idempotency key. Only ever set going
19
+ * forward; NO historical key is fabricated (task-32 §2.3, message review), so
20
+ * old Messages stay keyless and non-idempotent exactly as before.
21
+ * - `submissionReceipt`: the frozen disposition a keyed submission replays from.
22
+ * Written only alongside a new `submissionKey`, so it too never appears on
23
+ * historical data.
24
+ *
25
+ * Because none of the three needs a value backfilled onto old rows, the only data
26
+ * step this migration performs is the planning-entered reconstruction below.
27
+ *
28
+ * The one fact old data cannot express is "this Draft already entered planning".
29
+ * Before Requirement A a Leader-waking user/operator submission on a Draft WAS
30
+ * the planning discussion, but it left no `task.planning-entered` fact because
31
+ * that event type did not exist. After the upgrade `develop` auto-activates an
32
+ * *unplanned* Draft; without this step a Draft that was mid-discussion would be
33
+ * mis-read as unplanned and snatched into auto-activation (task-32 §2.2, §4).
34
+ *
35
+ * So for every Draft that received at least one legitimate historical planning
36
+ * submission this appends exactly one `task.planning-entered` event, which makes
37
+ * {@link draftHasEnteredPlanning} derive `true` and routes a later develop to
38
+ * manual activation. A qualifying submission is an *unaddressed* user/operator
39
+ * Message that was not save-only (`wakePolicy !== "none"`) — byte-for-byte the
40
+ * same shape the new discuss path routes through the shared submission service.
41
+ *
42
+ * This is deliberately the conservative direction: it can only ever make develop
43
+ * MORE cautious, never activate a Draft it should not. Save-only Messages (old
44
+ * `wakePolicy === "none"`, the shape `record` now names) are excluded, so a Draft
45
+ * that only ever recorded context stays legitimately unplanned and its first
46
+ * develop may still auto-activate. Non-Draft Tasks are skipped because
47
+ * {@link draftHasEnteredPlanning} answers only about Drafts, and Activation
48
+ * requests are left untouched — a legacy request's absent `origin` is the
49
+ * truthful marker that it stays behind explicit activation.
50
+ */
51
+ export function migrateSubmitIntent(db) {
52
+ const drafts = db.prepare("SELECT task_id FROM tasks_catalog WHERE status = 'draft'").all();
53
+ if (drafts.length === 0)
54
+ return;
55
+ const listMessages = db.prepare("SELECT payload FROM messages WHERE task_id = ? ORDER BY seq ASC");
56
+ const listEventRows = db.prepare("SELECT event_id, type FROM events WHERE task_id = ?");
57
+ const readHighWater = db.prepare("SELECT high_water FROM id_sequences WHERE task_id = ? AND kind = 'event'");
58
+ // Advance the per-Task event high-water to exactly the id we just consumed, so
59
+ // the runtime keeps allocating strictly above every migrated event (mirrors
60
+ // sqliteStore's id_sequences bookkeeping).
61
+ const upsertHighWater = db.prepare(`INSERT INTO id_sequences (task_id, kind, high_water) VALUES (?, 'event', ?)
62
+ ON CONFLICT(task_id, kind) DO UPDATE SET high_water = ?`);
63
+ const insertEvent = db.prepare("INSERT INTO events (task_id, event_id, type, occurred_at, payload) VALUES (?, ?, ?, ?, ?)");
64
+ for (const { task_id: taskId } of drafts) {
65
+ const eventRows = listEventRows.all(taskId);
66
+ // Idempotent: a Draft that already carries the fact (from a prior run of this
67
+ // migration, or from a real runtime planning entry) is left untouched.
68
+ if (eventRows.some((row) => row.type === PLANNING_ENTERED_EVENT_TYPE))
69
+ continue;
70
+ const entry = firstPlanningSubmission(listMessages.all(taskId));
71
+ if (entry === undefined)
72
+ continue;
73
+ // Allocate the next event id from the greater of the recorded high-water and
74
+ // the largest event id actually present, so a fixture or historical database
75
+ // whose id_sequences lags the events table can never produce a colliding id.
76
+ const highWater = readHighWater.get(taskId)?.high_water ?? 0;
77
+ const maxEventSeq = eventRows.reduce((max, row) => Math.max(max, eventSequence(row.event_id)), 0);
78
+ const seq = Math.max(highWater, maxEventSeq) + 1;
79
+ // Build through the shared constructor so a migrated event is byte-identical
80
+ // in shape to one the shared submission service writes at runtime, and dated
81
+ // to the historical submission rather than the wall-clock upgrade moment.
82
+ const event = createTaskEvent(`event-${seq}`, taskId, PLANNING_ENTERED_EVENT_TYPE, { messageId: entry.id, intent: "discuss", derivedBy: MIGRATION_PROVENANCE }, new Date(entry.createdAt));
83
+ insertEvent.run(taskId, event.id, event.type, event.createdAt, JSON.stringify(event));
84
+ upsertHighWater.run(taskId, seq, seq);
85
+ }
86
+ }
87
+ /**
88
+ * The never-compacted event type recording a Draft entered planning. Inlined as a
89
+ * literal rather than imported so this released migration stays frozen against a
90
+ * future runtime rename of the constant; `TASK_PLANNING_ENTERED_EVENT` is the
91
+ * runtime owner, and a tripwire test asserts the two never diverge.
92
+ */
93
+ const PLANNING_ENTERED_EVENT_TYPE = "task.planning-entered";
94
+ /** Marks the event as reconstructed by this migration, for later audit. */
95
+ const MIGRATION_PROVENANCE = "submit-intent-migration";
96
+ /**
97
+ * The earliest Message on a Draft that represents a historical planning
98
+ * submission, or `undefined` if the Draft only ever recorded save-only context.
99
+ *
100
+ * A qualifying Message is an unaddressed (`recipient === undefined`) user or
101
+ * operator Message whose wake policy was not `none`. An absent wake policy
102
+ * qualifies: before Requirement A that was the default Leader-waking submission,
103
+ * exactly the shape an omitted intent normalizes to `discuss` today.
104
+ */
105
+ function firstPlanningSubmission(rows) {
106
+ for (const row of rows) {
107
+ const message = JSON.parse(row.payload);
108
+ if (message.kind !== "user" && message.kind !== "operator")
109
+ continue;
110
+ if (message.recipient !== undefined)
111
+ continue; // an addressed continuation, not a submission
112
+ if (message.wakePolicy === "none")
113
+ continue; // old save-only == record, never planning
114
+ if (typeof message.id !== "string")
115
+ continue;
116
+ if (typeof message.createdAt !== "string")
117
+ continue;
118
+ return { id: message.id, createdAt: message.createdAt };
119
+ }
120
+ return undefined;
121
+ }
122
+ /** The numeric suffix of an `event-<n>` id, or 0 for any unexpected shape. */
123
+ function eventSequence(eventId) {
124
+ const match = /^event-(\d+)$/.exec(eventId);
125
+ return match === null ? 0 : Number.parseInt(match[1], 10);
126
+ }