@zq-silk/yui 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/README.md +15 -1
  2. package/dist/artifacts/artifactCapability.js +39 -10
  3. package/dist/artifacts/imageMetadata.js +120 -0
  4. package/dist/artifacts/managedGit.js +7 -4
  5. package/dist/artifacts/taskArtifactRepository.js +6 -0
  6. package/dist/cli/commandCatalog.js +17 -8
  7. package/dist/cli/invocationAuthority.js +1 -1
  8. package/dist/commands/executionAuditCommands.js +5 -0
  9. package/dist/commands/globalRoleCommands.js +41 -3
  10. package/dist/commands/projectCommands.js +89 -94
  11. package/dist/commands/roleSkillValidation.js +4 -8
  12. package/dist/commands/taskCommands.js +25 -2
  13. package/dist/commands/taskUsageCommand.js +38 -0
  14. package/dist/context/roleSessionContext.js +18 -2
  15. package/dist/context/runContextPack.js +5 -1
  16. package/dist/context/sessionBootstrapManifest.js +10 -1
  17. package/dist/context/skillCatalog.js +108 -0
  18. package/dist/context/skillPackage.js +161 -0
  19. package/dist/context/taskContext.js +3 -2
  20. package/dist/context/taskSearch.js +127 -0
  21. package/dist/controlPlaneCli.js +25 -20
  22. package/dist/controller/fileSchedulerStoreAdapter.js +32 -6
  23. package/dist/controller/jobControl.js +2 -0
  24. package/dist/controller/nativeHostInput.js +37 -0
  25. package/dist/controller/runtime.js +93 -2
  26. package/dist/controller/runtimeEventInbox.js +2 -2
  27. package/dist/controller/runtimeEventProcessor.js +3 -3
  28. package/dist/doctor/doctor.js +10 -0
  29. package/dist/execution/reviewMainRun.js +1 -0
  30. package/dist/execution/workItemMainRun.js +1 -0
  31. package/dist/executor/codexConfigConflict.js +6 -4
  32. package/dist/executor/effectiveLaunch.js +24 -1
  33. package/dist/executor/fileRoleLaunchPlanner.js +13 -5
  34. package/dist/integration/gitIntegrationService.js +7 -12
  35. package/dist/integration/integrationSourceApplication.js +4 -2
  36. package/dist/job/httpPreview.js +61 -0
  37. package/dist/job/jobRunner.js +12 -2
  38. package/dist/kernel/builtinCapabilities.js +3 -1
  39. package/dist/message/message.js +15 -1
  40. package/dist/output/rolePresentation.js +4 -1
  41. package/dist/repository/executionLaneGitSnapshot.js +2 -1
  42. package/dist/repository/gitCompatibility.js +62 -0
  43. package/dist/repository/gitWorkspace.js +48 -71
  44. package/dist/repository/gitWorktreeInventory.js +121 -0
  45. package/dist/repository/project.js +74 -25
  46. package/dist/resources/resourceDiscovery.js +2 -2
  47. package/dist/resources/resourceGc.js +7 -4
  48. package/dist/resources/resourceRegistrar.js +2 -1
  49. package/dist/runtime/agentEndpoint.js +8 -0
  50. package/dist/runtime/agentHost.js +170 -3
  51. package/dist/runtime/codexAppServerRuntime.js +1 -1
  52. package/dist/runtime/codexNativeAccess.js +175 -0
  53. package/dist/runtime/controlledCodexTui.js +116 -0
  54. package/dist/runtime/publicReply.js +23 -0
  55. package/dist/runtime/runtimeObservation.js +48 -0
  56. package/dist/runtime/structuredProviderHost.js +16 -7
  57. package/dist/runtime/taskCostMetrics.js +133 -0
  58. package/dist/runtime/taskUsageMetrics.js +11 -2
  59. package/dist/runtime/taskUsageQuery.js +38 -0
  60. package/dist/scheduler/taskExecutionProjection.js +2 -0
  61. package/dist/scheduler/taskObservabilityProjection.js +9 -1
  62. package/dist/storage/homeLayout.js +13 -0
  63. package/dist/storage/sqliteSchema.js +44 -0
  64. package/dist/storage/sqliteStore.js +53 -0
  65. package/dist/storage/storageVersions.js +1 -1
  66. package/dist/storage/storeRpc.js +2 -0
  67. package/dist/storage/taskSearch.js +35 -0
  68. package/dist/storage/upgrade/projectKnowledgeMigration.js +52 -0
  69. package/dist/task/ordinaryArchive.js +42 -0
  70. package/dist/tmux/tmuxManager.js +8 -8
  71. package/dist/web/assets/assetManifest.js +11 -51
  72. package/dist/web/assets/client/app/catalog.js +215 -0
  73. package/dist/web/assets/client/app/main.js +148 -0
  74. package/dist/web/assets/client/app/selection.js +139 -0
  75. package/dist/web/assets/client/app/settings.js +326 -0
  76. package/dist/web/assets/client/app/taskView.js +280 -0
  77. package/dist/web/assets/client/domain/context.js +96 -0
  78. package/dist/web/assets/client/domain/records.js +126 -0
  79. package/dist/web/assets/client/domain/runs.js +119 -0
  80. package/dist/web/assets/client/domain/taskForms.js +197 -0
  81. package/dist/web/assets/client/domain/vocab.js +69 -0
  82. package/dist/web/assets/client/domain/work.js +116 -0
  83. package/dist/web/assets/client/i18n/en.js +900 -0
  84. package/dist/web/assets/client/i18n/zh-CN.js +898 -0
  85. package/dist/web/assets/client/index.js +114 -0
  86. package/dist/web/assets/client/layout/resizer.js +37 -0
  87. package/dist/web/assets/client/layout/router.js +35 -0
  88. package/dist/web/assets/client/layout/shortcuts.js +45 -0
  89. package/dist/web/assets/client/layout/sizing.js +95 -0
  90. package/dist/web/assets/client/layout/workspace.js +247 -0
  91. package/dist/web/assets/client/{api.js → lib/api.js} +20 -4
  92. package/dist/web/assets/client/{dom.js → lib/dom.js} +24 -12
  93. package/dist/web/assets/client/{format.js → lib/format.js} +7 -0
  94. package/dist/web/assets/client/lib/i18n.js +54 -0
  95. package/dist/web/assets/client/lib/markdown.js +167 -0
  96. package/dist/web/assets/client/lib/prefs.js +28 -0
  97. package/dist/web/assets/client/lib/theme.js +68 -0
  98. package/dist/web/assets/client/ui/containers.js +101 -0
  99. package/dist/web/assets/client/ui/controls.js +51 -0
  100. package/dist/web/assets/client/ui/forms.js +48 -0
  101. package/dist/web/assets/client/ui/metrics.js +137 -0
  102. package/dist/web/assets/client/ui/primitives.js +92 -0
  103. package/dist/web/assets/client/ui/text.js +33 -0
  104. package/dist/web/assets/client/ui/toast.js +12 -0
  105. package/dist/web/assets/client/views/bodySearch.js +172 -0
  106. package/dist/web/assets/client/views/createTask.js +85 -0
  107. package/dist/web/assets/client/views/dock/conversation.js +612 -0
  108. package/dist/web/assets/client/views/dock/discussion.js +173 -0
  109. package/dist/web/assets/client/views/dock/preview.js +129 -0
  110. package/dist/web/assets/client/views/dock/terminal.js +199 -0
  111. package/dist/web/assets/client/views/globalInput.js +67 -0
  112. package/dist/web/assets/client/{overview.js → views/overview.js} +61 -51
  113. package/dist/web/assets/client/{sidebar.js → views/sidebar.js} +56 -62
  114. package/dist/web/assets/client/views/skills.js +152 -0
  115. package/dist/web/assets/client/views/task/actions.js +36 -0
  116. package/dist/web/assets/client/views/task/delivery.js +185 -0
  117. package/dist/web/assets/client/views/task/deliveryResults.js +159 -0
  118. package/dist/web/assets/client/views/task/files.js +272 -0
  119. package/dist/web/assets/client/views/task/observation.js +153 -0
  120. package/dist/web/assets/client/views/task/overview.js +161 -0
  121. package/dist/web/assets/client/views/task/page.js +131 -0
  122. package/dist/web/assets/client/views/task/records.js +163 -0
  123. package/dist/web/assets/client/views/task/runtime.js +130 -0
  124. package/dist/web/assets/client/views/task/timeline.js +190 -0
  125. package/dist/web/assets/shared/geometry.js +19 -0
  126. package/dist/web/assets/shared/taskTabs.js +8 -0
  127. package/dist/web/assets/shared/themes.js +93 -0
  128. package/dist/web/assets/shell/dialogs.js +63 -0
  129. package/dist/web/assets/shell/dock.js +40 -0
  130. package/dist/web/assets/shell/index.js +40 -0
  131. package/dist/web/assets/shell/settings.js +34 -0
  132. package/dist/web/assets/shell/sidebar.js +45 -0
  133. package/dist/web/assets/styles/index.js +41 -0
  134. package/dist/web/assets/styles/{responsive.js → layout/responsive.js} +10 -10
  135. package/dist/web/assets/styles/{layout.js → layout/workspace.js} +17 -24
  136. package/dist/web/assets/styles/markdown.js +22 -3
  137. package/dist/web/assets/styles/tokens.js +10 -63
  138. package/dist/web/assets/styles/ui/controls.js +76 -0
  139. package/dist/web/assets/styles/ui/forms.js +46 -0
  140. package/dist/web/assets/styles/ui/surfaces.js +122 -0
  141. package/dist/web/assets/styles/views/delivery.js +29 -0
  142. package/dist/web/assets/styles/views/dock.js +71 -0
  143. package/dist/web/assets/styles/views/page.js +32 -0
  144. package/dist/web/assets/styles/views/records.js +70 -0
  145. package/dist/web/assets/styles/views/settings.js +26 -0
  146. package/dist/web/assets/styles/views/sidebar.js +74 -0
  147. package/dist/web/assets/styles/views/task.js +80 -0
  148. package/dist/web/assets/styles/views/terminal.js +38 -0
  149. package/dist/web/taskPreviews.js +205 -0
  150. package/dist/web/tmuxWebTerminal.js +16 -9
  151. package/dist/web/webConversation.js +373 -0
  152. package/dist/web/webMaterials.js +155 -0
  153. package/dist/web/webServer.js +295 -18
  154. package/dist/web/webSettings.js +331 -0
  155. package/dist/web/webSkills.js +86 -0
  156. package/dist/web/webSnapshot.js +40 -8
  157. package/dist/web/webTaskSurface.js +106 -8
  158. package/dist/workspace/gitChangeSetCapture.js +3 -1
  159. package/docs/managed-turn-and-session-runtime.md +9 -0
  160. package/docs/managed-turn-and-session-runtime.zh-CN.md +7 -0
  161. package/docs/release-workflow.md +28 -0
  162. package/docs/release-workflow.zh-CN.md +21 -0
  163. package/docs/storage-baseline.md +38 -1
  164. package/docs/storage-baseline.zh-CN.md +22 -0
  165. package/docs/task-discovery.md +28 -0
  166. package/docs/testing/verification-levels.md +2 -2
  167. package/i18n/README.zh-CN.md +1 -1
  168. package/package.json +1 -1
  169. package/dist/web/assets/client/app.js +0 -808
  170. package/dist/web/assets/client/components.js +0 -477
  171. package/dist/web/assets/client/detail.js +0 -379
  172. package/dist/web/assets/client/dock.js +0 -309
  173. package/dist/web/assets/client/evidence.js +0 -364
  174. package/dist/web/assets/client/forms.js +0 -230
  175. package/dist/web/assets/client/i18n.js +0 -1277
  176. package/dist/web/assets/client/markdown.js +0 -114
  177. package/dist/web/assets/client/records.js +0 -198
  178. package/dist/web/assets/client/sections.js +0 -349
  179. package/dist/web/assets/client/theme.js +0 -71
  180. package/dist/web/assets/shell.js +0 -161
  181. package/dist/web/assets/styles/components.js +0 -216
  182. package/dist/web/assets/styles/views.js +0 -309
  183. /package/dist/web/assets/{icons.js → shared/icons.js} +0 -0
@@ -1,364 +0,0 @@
1
- export const EVIDENCE_SCRIPT = String.raw `
2
- // The Delivery tab: work items, reviews, integration and remote delivery,
3
- // saved files and retained workspaces. Opening the tab reads the original
4
- // evidence once per Context cursor; reading never accepts, publishes,
5
- // executes or cleans anything.
6
- import { h, icon, clear } from "/assets/js/dom.js";
7
- import { formatBytes, formatClock } from "/assets/js/format.js";
8
- import {
9
- card, listCard, setCardCount, button, note, mono, chip, emptyState, richText, badge, statusBadge, label, tone, dot,
10
- timeTag, disclosure, workItemCard, workItemBody, reviewCard
11
- } from "/assets/js/components.js";
12
- import { entriesOf, valuesOf, totalOf, summaryFields, readExact, exactRow, lazyRow, familyState, loadFamily } from "/assets/js/records.js";
13
-
14
- const DELIVERY_TONES = { merged: "ok", partial: "warn", unverified: "warn", uncovered: "warn", pending: "info", none: "idle", unavailable: "idle" };
15
-
16
- function newest(left, right) {
17
- return Date.parse(right.createdAt || 0) - Date.parse(left.createdAt || 0);
18
- }
19
-
20
- // Only http(s) links without credentials leave the page.
21
- function safeUrl(value) {
22
- try {
23
- const url = new URL(value);
24
- return ["http:", "https:"].includes(url.protocol) && !url.username && !url.password ? url.href : null;
25
- } catch { return null; }
26
- }
27
-
28
- export function renderDelivery(panel, data, t, locale, ctx) {
29
- const view = data.viewState;
30
- const core = data.core;
31
- const task = data.task;
32
- view.exact = view.exact || {};
33
- view.openRows = view.openRows || {};
34
- view.reports = view.reports || {};
35
- view.panels = view.panels || {};
36
- view.panels.delivery = panel;
37
-
38
- // --- Work items ------------------------------------------------------------
39
- const work = listCard({ id: "detail-work", title: t("work.title"), icon: "layers", count: totalOf(core, "work-item") || null, hint: t("work.openHint") });
40
- function drawWork() {
41
- clear(work.list);
42
- const family = familyState(view, "work-item");
43
- const entries = entriesOf(core, "work-item");
44
- const titles = {};
45
- family.items.forEach(function (item) { const fields = summaryFields(item.summary); if (fields.title) titles[item.ref.refId] = fields.title; });
46
- valuesOf(core, "work-item").forEach(function (item) { titles[item.id] = item.title; });
47
- const shown = new Set(entries.map(function (entry) { return entry.ref.refId; }));
48
- const extraOpen = family.items.filter(function (item) { return item.status === "open" && !shown.has(item.ref.refId); });
49
- const finished = family.items.filter(function (item) { return item.status !== "open"; });
50
- entries.forEach(function (entry) {
51
- work.list.append(exactRow(entry, task.id, t, ctx, view.exact, function (value) { return workItemCard(value, t, locale, titles); }));
52
- });
53
- extraOpen.forEach(function (item) { work.list.append(workRow(item, titles)); });
54
- const loaded = family.key && family.pages;
55
- if (loaded) setCardCount(work, family.total || null);
56
- if (!entries.length && !extraOpen.length) {
57
- work.list.append(emptyState(loaded && family.total === 0 ? t("work.none") : t("work.noneOpen"), "layers"));
58
- }
59
- if (family.error) work.list.append(note(t("records.unavailable") + " " + family.error, "bad"));
60
- if (!loaded) {
61
- if (family.pending) work.list.append(h("p.row-label", null, t("work.reading")));
62
- return;
63
- }
64
- const finishedTotal = Math.max(finished.length, (family.total || 0) - totalOf(core, "work-item"));
65
- if (!finishedTotal) return;
66
- const group = h("div.row-stack.is-finished", null, h("p.row-label", null, t("work.finished") + " · " + finishedTotal));
67
- finished.forEach(function (item) { group.append(workRow(item, titles)); });
68
- work.list.append(group);
69
- if (family.nextCursor) work.list.append(listFoot(family, function () {
70
- return loadFamily(view, task.id, "work-item", family.key, ctx, { more: true, limit: 40 });
71
- }));
72
- }
73
- function workRow(item, titles) {
74
- const fields = summaryFields(item.summary);
75
- return lazyRow(item, task.id, t, ctx, {
76
- cache: view.exact, openRows: view.openRows,
77
- head: [dot(tone("work", item.status)), h("span.lazy-title", null, fields.title || item.ref.refId),
78
- item.assignee ? h("span.faint.small.lazy-meta", null, item.assignee) : null,
79
- statusBadge(t, "work", "work", item.status)],
80
- render: function (value) { return workItemBody(value, t, locale, titles); }
81
- });
82
- }
83
- function listFoot(family, more) {
84
- const next = button(t("history.more"), { icon: "chevron", variant: "ghost" });
85
- next.addEventListener("click", function () {
86
- next.disabled = true;
87
- more().then(refresh);
88
- });
89
- return h("div.list-foot", null,
90
- h("span.faint.small", null, t("history.loaded").replace("{shown}", String(family.items.length)).replace("{total}", String(family.total))),
91
- next);
92
- }
93
-
94
- // --- Reviews ---------------------------------------------------------------
95
- const reviews = listCard({ id: "detail-reviews", title: t("reviews.title"), icon: "eye", hint: t("reviews.hint") });
96
- function drawReviews() {
97
- clear(reviews.list);
98
- const evidence = view.evidence && view.evidence.key && view.evidence.value;
99
- if (evidence) {
100
- const rounds = evidence.reviews.slice().sort(newest);
101
- setCardCount(reviews, rounds.length || null);
102
- if (!rounds.length) reviews.list.append(emptyState(t("reviews.none"), "eye"));
103
- rounds.forEach(function (round) { reviews.list.append(reviewRow(round)); });
104
- return;
105
- }
106
- const entries = entriesOf(core, "review-round");
107
- setCardCount(reviews, entries.length || null);
108
- entries.forEach(function (entry) {
109
- reviews.list.append(exactRow(entry, task.id, t, ctx, view.exact, function (value) { return reviewRow(value); }));
110
- });
111
- if (view.evidence && view.evidence.error) reviews.list.append(note(t("records.unavailable") + " " + view.evidence.error, "bad"));
112
- else reviews.list.append(h("p.row-label", null, t("evidence.loading")));
113
- }
114
- function reviewRow(round) {
115
- const element = reviewCard(round, t, locale);
116
- if (!round.reviewerRunId) return element;
117
- const holder = h("div.stack");
118
- const cached = view.reports[round.id];
119
- if (cached) { holder.append(richText(t("evidence.report"), cached, t, { threshold: 480 })); element.append(holder); return element; }
120
- const report = button(t("evidence.readReport"), { icon: "eye", variant: "link" });
121
- report.addEventListener("click", async function () {
122
- report.disabled = true;
123
- try {
124
- const source = await ctx.inspect(task.id, { store: "run", refId: round.reviewerRunId });
125
- const output = (source.result && source.result.output) || (source.value && source.value.result && source.value.result.output) || t("evidence.noReport");
126
- view.reports[round.id] = output;
127
- holder.append(richText(t("evidence.report"), output, t, { threshold: 480 }));
128
- report.remove();
129
- } catch (error) { holder.append(note(error.message, "bad")); report.disabled = false; }
130
- });
131
- element.append(h("div.record-actions", null, report), holder);
132
- return element;
133
- }
134
-
135
- // --- Integration and remote delivery ------------------------------------------
136
- const delivery = card({ id: "detail-results", title: t("delivery.title"), icon: "merge", hint: t("delivery.hint") });
137
- const deliveryBody = h("div.stack.delivery-stack");
138
- delivery.body.append(deliveryBody);
139
- function remoteDelivery() {
140
- const entry = entriesOf(core, "remote-delivery")[0];
141
- if (entry && !entry.omitted) return entry.value;
142
- const cached = entry && view.exact["remote-delivery/" + entry.ref.refId];
143
- if (cached && cached.digest === entry.ref.digest && cached.result) return cached.result.value;
144
- return (data.runtime && data.runtime.remoteDelivery) || null;
145
- }
146
- function drawDelivery() {
147
- clear(deliveryBody);
148
- const remote = remoteDelivery();
149
- if (remote) {
150
- deliveryBody.append(h("h4.sub-head", null, icon("package", "icon-sm"), h("span", null, t("evidence.remote")),
151
- badge(t("remoteDelivery." + remote.status, remote.status), DELIVERY_TONES[remote.status] || "idle", { dot: true })));
152
- if (remote.codeProjectCount) {
153
- deliveryBody.append(h("p.faint.small", null, t("delivery.counts")
154
- .replace("{merged}", String(remote.mergedProjectCount)).replace("{verified}", String(remote.verifiedProjectCount))
155
- .split("{total}").join(String(remote.codeProjectCount))));
156
- }
157
- (remote.projects || []).forEach(function (project) { deliveryBody.append(projectRow(project)); });
158
- if (!(remote.projects || []).length) deliveryBody.append(note(t("delivery.noProjects")));
159
- } else deliveryBody.append(note(t("evidence.observationUnavailable")));
160
-
161
- const state = view.evidence || {};
162
- const evidence = state.key && state.value;
163
- deliveryBody.append(h("h4.sub-head", null, icon("merge", "icon-sm"), h("span", null, t("evidence.integrations")),
164
- evidence ? h("span.count", null, String(evidence.integrations.length)) : null));
165
- if (!evidence) {
166
- deliveryBody.append(state.error ? note(t("evidence.originalUnavailable") + " " + state.error, "bad") : h("p.faint.small", null, t("evidence.loading")));
167
- return;
168
- }
169
- if (!evidence.integrations.length) deliveryBody.append(note(t("evidence.noIntegrations")));
170
- const rows = h("div.row-stack.boxed");
171
- evidence.integrations.slice().sort(newest).forEach(function (attempt) { rows.append(integrationRow(attempt)); });
172
- if (rows.childNodes.length) deliveryBody.append(rows);
173
- deliveryBody.append(h("p.faint.small", null, t("delivery.readAt") + " " + formatClock(state.readAt, locale)
174
- + (state.pending ? " · " + t("evidence.loading") : "")));
175
- }
176
- function projectRow(project) {
177
- const publication = project.publication;
178
- const href = publication && publication.externalUrl && safeUrl(publication.externalUrl);
179
- const element = h("article.record.delivery-project");
180
- element.append(h("header.record-head", null, icon("folder", "icon-sm"), h("strong", null, project.directory || project.projectId),
181
- project.coverage ? chip(label(t, "coverage", project.coverage)) : null,
182
- h("span.spacer"),
183
- publication ? (href
184
- ? h("a.link", { href: href, rel: "noopener noreferrer", target: "_blank" }, label(t, "publication", publication.externalKind) + " #" + publication.externalId)
185
- : mono(publication.externalKind + " " + publication.externalId)) : null));
186
- if (publication && publication.title) element.append(h("p.small", null, publication.title));
187
- if (project.reason) element.append(h("p.faint.small", null, project.reason));
188
- element.append(h("div.meta-line", null,
189
- h("span", null, t("evidence.expectedCommit") + " "), mono(project.expectedLocalCommit ? project.expectedLocalCommit.slice(0, 12) : t("common.unknown")),
190
- project.state ? chip(label(t, "publicationState", project.state)) : null,
191
- project.verification ? chip(t("evidence.verification") + " · " + label(t, "verification", project.verification)) : null,
192
- project.adoption ? h("span", null, t("evidence.adoption") + " ", mono(project.adoption.id)) : null));
193
- return element;
194
- }
195
- function integrationRow(attempt) {
196
- const source = attempt.source || {};
197
- const element = h("article.record.integration-row");
198
- element.dataset.status = attempt.status;
199
- element.append(h("header.record-head", null, dot(tone("integration", attempt.status)), mono(attempt.id),
200
- chip(label(t, "integration.source", source.kind) + (source.workItemId ? " · " + source.workItemId : "")),
201
- source.strategy ? chip(source.strategy) : null,
202
- h("span.spacer"),
203
- statusBadge(t, "integration", "integration", attempt.status)));
204
- if (attempt.summary) element.append(h("p.small", null, attempt.summary));
205
- element.append(h("div.meta-line", null,
206
- attempt.projectId ? h("span", null, attempt.projectId) : null,
207
- attempt.targetRef ? mono(attempt.targetRef) : null,
208
- h("span", null, t("evidence.candidate") + " "), mono(attempt.candidateCommit ? attempt.candidateCommit.slice(0, 12) : t("evidence.noCandidate")),
209
- timeTag(attempt.createdAt, locale, t)));
210
- if (attempt.checks && attempt.checks.length) {
211
- element.append(h("ul.check-list", null, attempt.checks.map(function (check) {
212
- return h("li", null, dot(check.outcome === "passed" ? "ok" : check.outcome === "failed" ? "bad" : "idle"),
213
- h("span.mono-line", null, check.name), h("span.faint", null, label(t, "check", check.outcome)),
214
- check.details ? h("span.faint.small.check-details", null, check.details) : null);
215
- })));
216
- } else element.append(h("p.faint.small", null, t("evidence.noChecks")));
217
- return element;
218
- }
219
-
220
- // --- Workspaces and cleanup --------------------------------------------------
221
- const workspaces = disclosure(t("workspaces.title"), "workspaces", { className: "card-disclosure", meta: String(totalOf(core, "managed-workspace")) });
222
- workspaces.id = "detail-workspaces";
223
- function drawWorkspaces() {
224
- clear(workspaces.body);
225
- const evidence = view.evidence && view.evidence.key && view.evidence.value;
226
- const list = evidence ? evidence.workspaces : valuesOf(core, "managed-workspace");
227
- if (!list.length) workspaces.body.append(note(t("evidence.noWorkspaces")));
228
- const rows = h("div.row-stack.boxed");
229
- list.forEach(function (workspace) {
230
- const owner = workspace.owner || {};
231
- const ownerId = owner.workItemId || owner.reviewRoundId || owner.integrationAttemptId
232
- || (owner.executionGroupId ? owner.executionGroupId + (owner.executionLaneId ? "/" + owner.executionLaneId : "") : "") || owner.taskId || "";
233
- rows.append(h("article.record.is-compact", null,
234
- h("header.record-head", null, chip(label(t, "workspace.owner", owner.type)), mono(ownerId), h("span.spacer"), timeTag(workspace.updatedAt, locale, t)),
235
- h("p.small.mono-line", null, workspace.root),
236
- (workspace.entries || []).length ? h("div.meta-line", null, workspace.entries.map(function (entry) {
237
- return h("span", null, entry.directory + " · ", mono(entry.branch || entry.baseRef || ""));
238
- })) : null));
239
- });
240
- if (rows.childNodes.length) workspaces.body.append(rows);
241
- workspaces.body.append(note(t("evidence.cleanupNote")), h("pre.code-block", null, "yui task archive-preflight " + task.id + " --integrated"));
242
- }
243
-
244
- panel.append(work, reviews, delivery, filesCard(data, t, locale, ctx), workspaces);
245
- panel.redraw = function () { drawWork(); drawReviews(); drawDelivery(); drawWorkspaces(); };
246
- panel.redraw();
247
-
248
- // Reads outlive one render: they redraw whichever Delivery panel is current
249
- // and re-read when the Context cursor moved while they were in flight.
250
- function refresh() {
251
- const current = view.panels.delivery;
252
- if (!current || !current.isConnected) return;
253
- current.redraw();
254
- if (!current.hidden) current.onShow();
255
- }
256
- panel.onShow = function () {
257
- const key = core.coreCursor;
258
- const previous = view.evidence || {};
259
- if (previous.key !== key && previous.errorKey !== key && !previous.pending) {
260
- view.evidence = { key: previous.key, value: previous.value, readAt: previous.readAt, error: null, pending: true };
261
- ctx.evidence(task.id).then(function (value) {
262
- view.evidence = { key: key, value: value, readAt: new Date().toISOString(), error: null, pending: false };
263
- }, function (error) {
264
- view.evidence = { key: previous.key, value: previous.value, readAt: previous.readAt, error: error.message, errorKey: key, pending: false };
265
- }).then(refresh);
266
- }
267
- const entry = entriesOf(core, "remote-delivery")[0];
268
- if (entry && entry.omitted && !(data.runtime && data.runtime.remoteDelivery)) {
269
- const hit = view.exact["remote-delivery/" + entry.ref.refId];
270
- if (!(hit && hit.digest === entry.ref.digest && hit.result)) {
271
- readExact(entry, task.id, ctx, view.exact).then(refresh, function () {});
272
- }
273
- }
274
- const family = familyState(view, "work-item");
275
- if (family.key !== key && family.errorKey !== key && !family.pending) loadFamily(view, task.id, "work-item", key, ctx, { limit: 40 }).then(refresh);
276
- };
277
- }
278
-
279
- // --- Saved files ------------------------------------------------------------------
280
- // Files are read on request at a fixed revision; the selected revision
281
- // survives refreshes.
282
- function filesCard(data, t, locale, actions) {
283
- const state = data.viewState;
284
- const load = button(state.artifactList ? t("evidence.reload") : t("evidence.load"), { icon: "refresh", variant: "ghost" });
285
- const files = card({ id: "detail-files", title: t("evidence.files"), icon: "file", hint: t("evidence.filesHint"), actions: load });
286
- const list = h("div.file-list");
287
- const viewer = h("div.file-viewer");
288
- let readSequence = 0;
289
- async function read(path, commit) {
290
- const sequence = ++readSequence;
291
- viewer.dataset.reading = "true";
292
- clear(viewer);
293
- viewer.append(h("p.faint", null, t("evidence.reading")));
294
- try {
295
- const result = await actions.readArtifact(data.task.id, path, commit);
296
- if (sequence !== readSequence) return;
297
- state.artifact = result;
298
- drawViewer();
299
- } catch (error) {
300
- if (sequence === readSequence) { clear(viewer); viewer.append(note(t("evidence.unavailable") + " " + error.message, "bad")); }
301
- } finally { if (sequence === readSequence) viewer.dataset.reading = "false"; }
302
- }
303
- function drawViewer() {
304
- clear(viewer);
305
- const value = state.artifact;
306
- if (!value) return;
307
- const ref = "git:" + value.commit + ":" + value.relativePath;
308
- const copy = button(t("evidence.copy"), { icon: "copy", variant: "ghost" });
309
- copy.addEventListener("click", async function () {
310
- try { await navigator.clipboard.writeText(data.task.id + " " + ref); copy.lastChild.textContent = t("evidence.copied"); }
311
- catch { copy.lastChild.textContent = t("evidence.copyManual"); }
312
- });
313
- viewer.append(h("header.viewer-head", null, icon("file"), h("strong", null, value.relativePath), h("span.spacer"), copy));
314
- viewer.append(h("p.viewer-ref", null, mono(ref)));
315
- viewer.append(h("p.faint.small", null, t("evidence.fixedNote")));
316
- viewer.append(h("pre.code-block.artifact-text", { tabIndex: 0, "aria-label": t("evidence.fixedText") }, value.content));
317
- }
318
- function drawList() {
319
- clear(list);
320
- const current = state.artifactList;
321
- if (!current) return;
322
- if (state.artifact && current.commit !== state.artifact.commit) list.append(note(t("evidence.differentRevision")));
323
- if (!current.entries.length) { list.append(emptyState(t("evidence.noFiles"), "file")); return; }
324
- current.entries.forEach(function (entry) {
325
- list.append(h("button.file-row", {
326
- type: "button",
327
- "aria-current": String(!!state.artifact && state.artifact.relativePath === entry.relativePath && state.artifact.commit === current.commit),
328
- onclick: function () { read(entry.relativePath, current.commit); }
329
- }, icon("file", "icon-sm"), h("span.file-name", null, entry.relativePath), h("span.faint.small", null, formatBytes(entry.size))));
330
- });
331
- }
332
- load.addEventListener("click", async function () {
333
- load.disabled = true;
334
- list.dataset.reading = "true";
335
- try {
336
- state.artifactList = await actions.artifacts(data.task.id);
337
- if (placeholder) { placeholder.remove(); placeholder = null; }
338
- drawList();
339
- } catch (error) {
340
- clear(list);
341
- list.append(note(t("evidence.listUnavailable") + " " + error.message, "bad"));
342
- } finally { load.disabled = false; list.dataset.reading = "false"; }
343
- });
344
- // Explicit frozen references stay attached to their original revision.
345
- const sources = [data.task.completionArtifactRefs || [],
346
- data.core.records.filter(function (entry) { return !entry.omitted && ["task-brief", "task-decision"].includes(entry.ref.store); })
347
- .map(function (entry) { return JSON.stringify(entry.value); })].flat().join(" ");
348
- const refs = Array.from(sources.matchAll(/git:([0-9a-f]{40}):([^\s"\\]+?)(?=[\s"\\]|$)/g));
349
- const seen = new Set();
350
- const referenced = h("div.file-list");
351
- refs.forEach(function (match) {
352
- if (seen.has(match[0])) return;
353
- seen.add(match[0]);
354
- referenced.append(h("button.file-row", { type: "button", onclick: function () { read(match[2], match[1]); } },
355
- icon("flag", "icon-sm"), h("span.file-name", null, match[2]), badge(t("evidence.referenced"), "accent")));
356
- });
357
- let placeholder = !state.artifactList && !seen.size ? emptyState(t("evidence.notLoaded"), "file") : null;
358
- if (placeholder) files.body.append(placeholder);
359
- files.body.append(referenced, list, viewer);
360
- drawList();
361
- drawViewer();
362
- return files;
363
- }
364
- `;
@@ -1,230 +0,0 @@
1
- export const FORMS_SCRIPT = String.raw `
2
- // Write forms. Each submission carries a fresh requestId, marks itself unsent
3
- // until a receipt settles, and reports an unknown outcome as unknown: nothing
4
- // here ever replays a write automatically.
5
- import { h, icon, clear } from "/assets/js/dom.js";
6
- import { button } from "/assets/js/components.js";
7
-
8
- function receiptLine(text, state) {
9
- const line = h("p.receipt", { role: "status" }, text);
10
- if (state) line.dataset.state = state;
11
- return line;
12
- }
13
- function setReceipt(line, text, state) {
14
- line.textContent = text;
15
- line.dataset.state = state || "";
16
- }
17
-
18
- function segmented(name, options, value, onChange) {
19
- const group = h("div.seg.seg-sm", { role: "radiogroup" });
20
- options.forEach(function (option) {
21
- const item = h("button.seg-btn", {
22
- type: "button", role: "radio", title: option.title || null,
23
- "aria-checked": String(option.value === value),
24
- dataset: { value: option.value },
25
- onclick: function () {
26
- group.querySelectorAll(".seg-btn").forEach(function (other) { other.setAttribute("aria-checked", String(other === item)); });
27
- onChange(option.value);
28
- }
29
- }, option.label);
30
- group.append(item);
31
- });
32
- group.dataset.name = name;
33
- return group;
34
- }
35
-
36
- export function messageComposer(task, t, actions) {
37
- let intent = "discuss";
38
- const form = h("form.composer");
39
- const message = h("textarea.composer-input", {
40
- required: true, maxLength: 8000, rows: 3, placeholder: t("composer.placeholder"),
41
- "aria-label": t("composer.label")
42
- });
43
- const open = ["active", "draft"].includes(task.status);
44
- const send = h("button.btn.btn-primary.composer-send", { type: "submit", disabled: !open, title: t("composer.sendHint") },
45
- icon("send"), h("span", null, t("composer.send")));
46
- const intents = segmented("intent", [
47
- { value: "discuss", label: t("intent.discuss"), title: t("intent.discuss.hint") },
48
- { value: "record", label: t("intent.record"), title: t("intent.record.hint") },
49
- { value: "develop", label: t("intent.develop"), title: t("intent.develop.hint") }
50
- ], intent, function (value) { intent = value; });
51
- const receipt = receiptLine(open ? t("receipt.notSubmitted") : t("composer.closed"));
52
- const facets = h("div.facets");
53
- form.append(h("div.composer-box", null, message, h("div.composer-bar", null, intents, h("span.spacer"), send)), receipt, facets);
54
- form.addEventListener("input", function () { form.dataset.unsent = message.value ? "true" : "false"; });
55
- message.addEventListener("keydown", function (event) {
56
- if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) { event.preventDefault(); form.requestSubmit(); }
57
- });
58
- form.addEventListener("submit", async function (event) {
59
- event.preventDefault();
60
- if (send.disabled || !message.value.trim()) return;
61
- send.disabled = true;
62
- form.dataset.unsent = "true";
63
- const requestId = crypto.randomUUID();
64
- clear(facets);
65
- setReceipt(receipt, t("receipt.waiting") + " · " + requestId, "pending");
66
- try {
67
- // requestId is the submission key: the same key retried returns the
68
- // original Message and routing, never a second submission.
69
- const result = await actions.sendMessage(task.id, message.value, requestId, intent);
70
- setReceipt(receipt, t("receipt.saved") + " · " + result.record.id, "ok");
71
- renderSubmissionFacets(facets, result.submission, t);
72
- message.value = "";
73
- form.dataset.unsent = "false";
74
- send.disabled = false;
75
- if (actions.afterWrite) actions.afterWrite();
76
- } catch (error) {
77
- if (error.disposition === "not-submitted") {
78
- setReceipt(receipt, t("receipt.notSubmittedBecause") + " " + error.message, "bad");
79
- send.disabled = false;
80
- return;
81
- }
82
- setReceipt(receipt, t("receipt.unknownMessage") + " · " + requestId, "warn");
83
- }
84
- });
85
- return form;
86
- }
87
-
88
- // Each submission facet is reported on its own line, never collapsed into a
89
- // single "started". A missing facet block is a contract violation and is
90
- // reported as such rather than reinterpreted.
91
- export function renderSubmissionFacets(container, submission, t) {
92
- clear(container);
93
- if (!submission) { container.append(h("p.faint.small", null, t("facet.missing"))); return; }
94
- const rows = [
95
- ["facet.phase", "phase." + submission.phase, submission.phase],
96
- ["facet.planning", "planningFacet." + submission.planning, submission.planning],
97
- ["facet.activation", "activation." + submission.activation, submission.activation],
98
- ["facet.delivery", "deliveryFacet." + submission.delivery, submission.delivery]
99
- ];
100
- container.append(h("dl.kv.kv-compact", null, rows.map(function (row) {
101
- return [h("dt", null, t(row[0])), h("dd", null, t(row[1], row[2]))];
102
- })));
103
- const step = submission.nextStep;
104
- if (!step) return;
105
- const text = step.kind === "activate-manually" ? t("next.activateManually").replace("{task}", step.taskId)
106
- : step.kind === "start-execution" ? t("next.startExecution").replace("{task}", step.taskId)
107
- : step.kind === "await-pending-activation" ? t("next.awaitActivation").replace("{ref}", step.activationRef)
108
- : step.kind === "resolve-failed-activation" ? t("next.resolveFailed").replace("{failure}", step.failure).replace("{ref}", step.activationRef)
109
- : "";
110
- if (text) container.append(h("p.next-step", { dataset: { nextStep: step.kind } }, icon("flag", "icon-sm"), h("span", null, text)));
111
- }
112
-
113
- // Queue / steer / interrupt — the same three application-layer actions the
114
- // CLI drives. Steer and interrupt name an exact current Turn; a mismatch is a
115
- // visible failure receipt, never a silent downgrade to a queue.
116
- export function controlForm(task, t, actions, roleNames) {
117
- let kind = "queue";
118
- const form = h("form.stack");
119
- const role = h("input", { list: "control-roles-" + task.id, placeholder: t("control.rolePlaceholder") });
120
- const roles = h("datalist", { id: "control-roles-" + task.id }, (roleNames || []).map(function (name) { return h("option", { value: name }); }));
121
- const body = h("textarea", { maxLength: 8000, rows: 3 });
122
- const expected = h("input.mono", { placeholder: t("control.expectedPlaceholder") });
123
- const workItem = h("input.mono");
124
- const then = h("input.mono", { placeholder: t("control.thenPlaceholder") });
125
- const field = function (text, control, hint) {
126
- return h("label.field", null, h("span", null, text), control, hint ? h("small.faint", null, hint) : null);
127
- };
128
- const roleField = field(t("control.role"), role);
129
- const bodyField = field(t("control.message"), body);
130
- const expectedField = field(t("control.expectedTurn"), expected, t("control.expectedHint"));
131
- const workItemField = field(t("control.workItem"), workItem);
132
- const thenField = field(t("control.then"), then);
133
- const open = ["active", "draft"].includes(task.status);
134
- const submit = button(t("control.submit"), { type: "submit", variant: "primary", icon: "send", disabled: !open });
135
- const receipt = receiptLine(t("receipt.notSubmitted"));
136
- function apply() {
137
- bodyField.hidden = kind === "interrupt";
138
- expectedField.hidden = kind === "queue";
139
- thenField.hidden = kind !== "interrupt";
140
- workItemField.hidden = kind === "interrupt";
141
- role.required = kind !== "queue";
142
- body.required = kind !== "interrupt";
143
- expected.required = kind !== "queue";
144
- }
145
- const actionsSeg = segmented("action", [
146
- { value: "queue", label: t("control.queue"), title: t("control.queue.hint") },
147
- { value: "steer", label: t("control.steer"), title: t("control.steer.hint") },
148
- { value: "interrupt", label: t("control.interrupt"), title: t("control.interrupt.hint") }
149
- ], kind, function (value) { kind = value; apply(); });
150
- form.append(h("div.field", null, h("span", null, t("control.action")), actionsSeg),
151
- h("div.field-row", null, roleField, workItemField), roles, bodyField, expectedField, thenField,
152
- h("div.form-actions", null, submit), receipt);
153
- apply();
154
- form.addEventListener("input", function () { form.dataset.unsent = "true"; });
155
- form.addEventListener("submit", async function (event) {
156
- event.preventDefault();
157
- if (submit.disabled) return;
158
- submit.disabled = true;
159
- form.dataset.unsent = "true";
160
- const requestId = crypto.randomUUID();
161
- const payload = { action: kind, requestId };
162
- if (kind === "interrupt") {
163
- payload.role = role.value.trim();
164
- payload.expectedTarget = expected.value.trim();
165
- if (then.value.trim()) payload.thenMessage = then.value.trim();
166
- } else {
167
- payload.body = body.value;
168
- if (kind === "steer") { payload.to = role.value.trim(); payload.expectedTarget = expected.value.trim(); }
169
- else if (role.value.trim()) payload.to = role.value.trim();
170
- if (workItem.value.trim()) payload.workItem = workItem.value.trim();
171
- }
172
- setReceipt(receipt, t("receipt.waiting") + " · " + requestId, "pending");
173
- try {
174
- // The receipt states exactly what settled; none of these states implies
175
- // the Provider executed the input.
176
- const result = await actions.control(task.id, payload);
177
- const settled = result.steer || result.interrupt || result.delivery || { state: result.disposition };
178
- setReceipt(receipt, t("receipt.receipt") + " " + result.action + " · " + settled.state
179
- + (settled.outcome ? " · " + settled.outcome : "") + (settled.detail ? " · " + settled.detail : "")
180
- + (result.record ? " · " + result.record.id : ""), "ok");
181
- form.dataset.unsent = "false";
182
- submit.disabled = false;
183
- if (actions.afterWrite) actions.afterWrite();
184
- } catch (error) {
185
- if (error.disposition === "not-submitted") {
186
- setReceipt(receipt, t("receipt.notSubmittedBecause") + " " + error.message, "bad");
187
- submit.disabled = false;
188
- return;
189
- }
190
- setReceipt(receipt, t("receipt.unknownControl") + " · " + requestId, "warn");
191
- }
192
- });
193
- return form;
194
- }
195
-
196
- export function titleForm(task, t, actions) {
197
- const form = h("form.inline-form");
198
- const archived = task.status === "archived";
199
- const input = h("input", { value: task.title, required: true, maxLength: 500, disabled: archived, "aria-label": t("details.title") });
200
- const save = button(t("actions.save"), { type: "submit", variant: "primary", disabled: archived });
201
- const receipt = receiptLine(t("receipt.notSubmitted"));
202
- form.append(h("div.inline-row", null, input, save), receipt);
203
- form.addEventListener("input", function () { form.dataset.unsent = input.value !== task.title ? "true" : "false"; });
204
- form.addEventListener("submit", async function (event) {
205
- event.preventDefault();
206
- if (save.disabled) return;
207
- save.disabled = true;
208
- form.dataset.unsent = "true";
209
- const requestId = crypto.randomUUID();
210
- setReceipt(receipt, t("receipt.waiting") + " · " + requestId, "pending");
211
- try {
212
- const result = await actions.updateTask(task.id, { title: input.value }, requestId);
213
- setReceipt(receipt, t("receipt.savedRevision") + " " + result.revision, "ok");
214
- input.value = result.record.title;
215
- form.dataset.unsent = "false";
216
- save.disabled = false;
217
- if (actions.afterWrite) actions.afterWrite();
218
- } catch (error) {
219
- if (error.disposition === "not-submitted") {
220
- setReceipt(receipt, t("receipt.notSavedBecause") + " " + error.message, "bad");
221
- save.disabled = false;
222
- return;
223
- }
224
- // A lost response must never automatically replay a write.
225
- setReceipt(receipt, t("receipt.unknownSave") + " · " + requestId, "warn");
226
- }
227
- });
228
- return form;
229
- }
230
- `;