@zq-silk/yui 2.2.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 (206) hide show
  1. package/README.md +19 -3
  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 +25 -11
  7. package/dist/cli/interactionPolicy.js +4 -0
  8. package/dist/cli/invocationAuthority.js +1 -1
  9. package/dist/commands/executionAuditCommands.js +5 -0
  10. package/dist/commands/globalRoleCommands.js +41 -3
  11. package/dist/commands/projectCommands.js +89 -94
  12. package/dist/commands/roleSkillValidation.js +4 -8
  13. package/dist/commands/taskCommands.js +30 -9
  14. package/dist/commands/taskIntegrationCommands.js +5 -16
  15. package/dist/commands/taskUsageCommand.js +38 -0
  16. package/dist/context/roleSessionContext.js +18 -2
  17. package/dist/context/runContextPack.js +5 -1
  18. package/dist/context/sessionBootstrapManifest.js +10 -1
  19. package/dist/context/skillCatalog.js +108 -0
  20. package/dist/context/skillPackage.js +161 -0
  21. package/dist/context/taskContext.js +3 -2
  22. package/dist/context/taskSearch.js +127 -0
  23. package/dist/controlPlaneCli.js +51 -39
  24. package/dist/controller/clientRuntime.js +3 -2
  25. package/dist/controller/fileSchedulerStoreAdapter.js +32 -6
  26. package/dist/controller/jobControl.js +2 -0
  27. package/dist/controller/nativeHostInput.js +37 -0
  28. package/dist/controller/runtime.js +93 -2
  29. package/dist/controller/runtimeEventInbox.js +2 -2
  30. package/dist/controller/runtimeEventProcessor.js +3 -3
  31. package/dist/doctor/doctor.js +10 -0
  32. package/dist/execution/reviewMainRun.js +1 -0
  33. package/dist/execution/workItemMainRun.js +1 -0
  34. package/dist/executor/codexConfigConflict.js +6 -4
  35. package/dist/executor/effectiveLaunch.js +24 -1
  36. package/dist/executor/fileRoleLaunchPlanner.js +13 -5
  37. package/dist/integration/gitIntegrationService.js +15 -79
  38. package/dist/integration/integrationSourceApplication.js +4 -2
  39. package/dist/job/httpPreview.js +61 -0
  40. package/dist/job/jobCleanupInspection.js +67 -0
  41. package/dist/job/jobRunner.js +12 -2
  42. package/dist/kernel/builtinCapabilities.js +3 -1
  43. package/dist/message/message.js +15 -1
  44. package/dist/output/rolePresentation.js +4 -1
  45. package/dist/repository/executionLaneGitSnapshot.js +2 -1
  46. package/dist/repository/gitCompatibility.js +62 -0
  47. package/dist/repository/gitWorkspace.js +86 -80
  48. package/dist/repository/gitWorktreeInventory.js +121 -0
  49. package/dist/repository/project.js +74 -25
  50. package/dist/repository/taskWorkspaceCoordinator.js +72 -145
  51. package/dist/repository/taskWorkspacePreparer.js +39 -43
  52. package/dist/repository/workspaceCleanupInspection.js +88 -7
  53. package/dist/resources/resourceDiscovery.js +2 -2
  54. package/dist/resources/resourceGc.js +7 -4
  55. package/dist/resources/resourceRegistrar.js +18 -11
  56. package/dist/runtime/agentEndpoint.js +8 -0
  57. package/dist/runtime/agentHost.js +170 -3
  58. package/dist/runtime/codexAppServerRuntime.js +1 -1
  59. package/dist/runtime/codexNativeAccess.js +175 -0
  60. package/dist/runtime/controlledCodexTui.js +116 -0
  61. package/dist/runtime/integrationRuntimeIsolation.js +21 -0
  62. package/dist/runtime/publicReply.js +23 -0
  63. package/dist/runtime/runtimeObservation.js +48 -0
  64. package/dist/runtime/structuredProviderHost.js +16 -7
  65. package/dist/runtime/taskCostMetrics.js +133 -0
  66. package/dist/runtime/taskRuntimeIsolation.js +91 -21
  67. package/dist/runtime/taskUsageMetrics.js +11 -2
  68. package/dist/runtime/taskUsageQuery.js +38 -0
  69. package/dist/scheduler/taskExecutionProjection.js +2 -0
  70. package/dist/scheduler/taskObservabilityProjection.js +9 -1
  71. package/dist/storage/homeLayout.js +13 -0
  72. package/dist/storage/sqliteSchema.js +44 -0
  73. package/dist/storage/sqliteStore.js +53 -0
  74. package/dist/storage/storageVersions.js +1 -1
  75. package/dist/storage/storeRpc.js +2 -0
  76. package/dist/storage/taskSearch.js +35 -0
  77. package/dist/storage/upgrade/projectKnowledgeMigration.js +52 -0
  78. package/dist/task/archiveDiagnostics.js +26 -8
  79. package/dist/task/archivePreflight.js +26 -9
  80. package/dist/task/leaderArchive.js +9 -15
  81. package/dist/task/ordinaryArchive.js +42 -0
  82. package/dist/tmux/tmuxManager.js +8 -8
  83. package/dist/web/assets/assetManifest.js +11 -51
  84. package/dist/web/assets/client/app/catalog.js +215 -0
  85. package/dist/web/assets/client/app/main.js +148 -0
  86. package/dist/web/assets/client/app/selection.js +139 -0
  87. package/dist/web/assets/client/app/settings.js +326 -0
  88. package/dist/web/assets/client/app/taskView.js +280 -0
  89. package/dist/web/assets/client/domain/context.js +96 -0
  90. package/dist/web/assets/client/domain/records.js +126 -0
  91. package/dist/web/assets/client/domain/runs.js +119 -0
  92. package/dist/web/assets/client/domain/taskForms.js +197 -0
  93. package/dist/web/assets/client/domain/vocab.js +69 -0
  94. package/dist/web/assets/client/domain/work.js +116 -0
  95. package/dist/web/assets/client/i18n/en.js +900 -0
  96. package/dist/web/assets/client/i18n/zh-CN.js +898 -0
  97. package/dist/web/assets/client/index.js +114 -0
  98. package/dist/web/assets/client/layout/resizer.js +37 -0
  99. package/dist/web/assets/client/layout/router.js +35 -0
  100. package/dist/web/assets/client/layout/shortcuts.js +45 -0
  101. package/dist/web/assets/client/layout/sizing.js +95 -0
  102. package/dist/web/assets/client/layout/workspace.js +247 -0
  103. package/dist/web/assets/client/{api.js → lib/api.js} +28 -4
  104. package/dist/web/assets/client/{dom.js → lib/dom.js} +24 -12
  105. package/dist/web/assets/client/{format.js → lib/format.js} +7 -0
  106. package/dist/web/assets/client/lib/i18n.js +54 -0
  107. package/dist/web/assets/client/lib/markdown.js +167 -0
  108. package/dist/web/assets/client/lib/prefs.js +28 -0
  109. package/dist/web/assets/client/lib/theme.js +68 -0
  110. package/dist/web/assets/client/ui/containers.js +101 -0
  111. package/dist/web/assets/client/ui/controls.js +51 -0
  112. package/dist/web/assets/client/ui/forms.js +48 -0
  113. package/dist/web/assets/client/ui/metrics.js +137 -0
  114. package/dist/web/assets/client/ui/primitives.js +92 -0
  115. package/dist/web/assets/client/ui/text.js +33 -0
  116. package/dist/web/assets/client/ui/toast.js +12 -0
  117. package/dist/web/assets/client/views/bodySearch.js +172 -0
  118. package/dist/web/assets/client/views/createTask.js +85 -0
  119. package/dist/web/assets/client/views/dock/conversation.js +612 -0
  120. package/dist/web/assets/client/views/dock/discussion.js +173 -0
  121. package/dist/web/assets/client/views/dock/preview.js +129 -0
  122. package/dist/web/assets/client/views/dock/terminal.js +199 -0
  123. package/dist/web/assets/client/views/globalInput.js +67 -0
  124. package/dist/web/assets/client/{overview.js → views/overview.js} +62 -56
  125. package/dist/web/assets/client/{sidebar.js → views/sidebar.js} +56 -62
  126. package/dist/web/assets/client/views/skills.js +152 -0
  127. package/dist/web/assets/client/views/task/actions.js +36 -0
  128. package/dist/web/assets/client/views/task/delivery.js +185 -0
  129. package/dist/web/assets/client/views/task/deliveryResults.js +159 -0
  130. package/dist/web/assets/client/views/task/files.js +272 -0
  131. package/dist/web/assets/client/views/task/observation.js +153 -0
  132. package/dist/web/assets/client/views/task/overview.js +161 -0
  133. package/dist/web/assets/client/views/task/page.js +131 -0
  134. package/dist/web/assets/client/views/task/records.js +163 -0
  135. package/dist/web/assets/client/views/task/runtime.js +130 -0
  136. package/dist/web/assets/client/views/task/timeline.js +190 -0
  137. package/dist/web/assets/shared/geometry.js +19 -0
  138. package/dist/web/assets/{icons.js → shared/icons.js} +4 -0
  139. package/dist/web/assets/shared/taskTabs.js +8 -0
  140. package/dist/web/assets/shared/themes.js +93 -0
  141. package/dist/web/assets/shell/dialogs.js +63 -0
  142. package/dist/web/assets/shell/dock.js +40 -0
  143. package/dist/web/assets/shell/index.js +40 -0
  144. package/dist/web/assets/shell/settings.js +34 -0
  145. package/dist/web/assets/shell/sidebar.js +45 -0
  146. package/dist/web/assets/styles/index.js +41 -0
  147. package/dist/web/assets/styles/{responsive.js → layout/responsive.js} +15 -13
  148. package/dist/web/assets/styles/{layout.js → layout/workspace.js} +17 -24
  149. package/dist/web/assets/styles/markdown.js +22 -3
  150. package/dist/web/assets/styles/tokens.js +10 -63
  151. package/dist/web/assets/styles/ui/controls.js +76 -0
  152. package/dist/web/assets/styles/ui/forms.js +46 -0
  153. package/dist/web/assets/styles/ui/surfaces.js +122 -0
  154. package/dist/web/assets/styles/views/delivery.js +29 -0
  155. package/dist/web/assets/styles/views/dock.js +71 -0
  156. package/dist/web/assets/styles/views/page.js +32 -0
  157. package/dist/web/assets/styles/views/records.js +70 -0
  158. package/dist/web/assets/styles/views/settings.js +26 -0
  159. package/dist/web/assets/styles/views/sidebar.js +74 -0
  160. package/dist/web/assets/styles/views/task.js +80 -0
  161. package/dist/web/assets/styles/views/terminal.js +38 -0
  162. package/dist/web/taskPreviews.js +205 -0
  163. package/dist/web/tmuxWebTerminal.js +16 -9
  164. package/dist/web/webConversation.js +373 -0
  165. package/dist/web/webMaterials.js +155 -0
  166. package/dist/web/webServer.js +306 -18
  167. package/dist/web/webSettings.js +331 -0
  168. package/dist/web/webSkills.js +86 -0
  169. package/dist/web/webSnapshot.js +40 -8
  170. package/dist/web/webTaskSurface.js +114 -9
  171. package/dist/workspace/gitChangeSetCapture.js +3 -1
  172. package/docs/managed-turn-and-session-runtime.md +9 -0
  173. package/docs/managed-turn-and-session-runtime.zh-CN.md +7 -0
  174. package/docs/observability/README.md +13 -3
  175. package/docs/observability/README.zh-CN.md +10 -3
  176. package/docs/release-workflow.md +53 -0
  177. package/docs/release-workflow.zh-CN.md +40 -0
  178. package/docs/storage-baseline.md +38 -1
  179. package/docs/storage-baseline.zh-CN.md +22 -0
  180. package/docs/task-delivery.md +36 -8
  181. package/docs/task-delivery.zh-CN.md +24 -7
  182. package/docs/task-discovery.md +28 -0
  183. package/docs/testing/verification-levels.md +2 -2
  184. package/i18n/README.zh-CN.md +4 -3
  185. package/package.json +1 -1
  186. package/skills/yui-leader/references/execution.md +2 -1
  187. package/skills/yui-leader/references/integration.md +20 -0
  188. package/skills/yui-operator/SKILL.md +4 -0
  189. package/skills/yui-reviewer/SKILL.md +3 -0
  190. package/skills/yui-runtime/SKILL.md +4 -0
  191. package/skills/yui-runtime/references/publication.md +20 -4
  192. package/skills/yui-worker/SKILL.md +3 -0
  193. package/dist/web/assets/client/app.js +0 -804
  194. package/dist/web/assets/client/components.js +0 -418
  195. package/dist/web/assets/client/detail.js +0 -333
  196. package/dist/web/assets/client/dock.js +0 -225
  197. package/dist/web/assets/client/evidence.js +0 -172
  198. package/dist/web/assets/client/forms.js +0 -230
  199. package/dist/web/assets/client/i18n.js +0 -1161
  200. package/dist/web/assets/client/markdown.js +0 -114
  201. package/dist/web/assets/client/records.js +0 -63
  202. package/dist/web/assets/client/sections.js +0 -313
  203. package/dist/web/assets/client/theme.js +0 -71
  204. package/dist/web/assets/shell.js +0 -161
  205. package/dist/web/assets/styles/components.js +0 -169
  206. package/dist/web/assets/styles/views.js +0 -292
@@ -1,172 +0,0 @@
1
- export const EVIDENCE_SCRIPT = String.raw `
2
- // Results and evidence. Files are read on request at a fixed revision; the
3
- // selected revision survives refreshes. Reading never accepts, publishes or
4
- // executes a result.
5
- import { h, icon, clear } from "/assets/js/dom.js";
6
- import { formatBytes } from "/assets/js/format.js";
7
- import { card, button, note, mono, emptyState, richText, badge, observabilityMetricCard } from "/assets/js/components.js";
8
-
9
- export function renderEvidence(container, data, t, locale, actions) {
10
- const state = data.viewState;
11
- const files = card({ title: t("evidence.files"), icon: "file", hint: t("evidence.filesHint") });
12
- const list = h("div.file-list");
13
- const viewer = h("div.file-viewer");
14
- const load = button(state.artifactList ? t("evidence.reload") : t("evidence.load"), { icon: "refresh", variant: "ghost" });
15
- files.querySelector(".card-head").append(h("div.card-actions", null, load));
16
- let readSequence = 0;
17
- async function read(path, commit) {
18
- const sequence = ++readSequence;
19
- viewer.dataset.reading = "true";
20
- clear(viewer);
21
- viewer.append(h("p.faint", null, t("evidence.reading")));
22
- try {
23
- const result = await actions.readArtifact(data.task.id, path, commit);
24
- if (sequence !== readSequence) return;
25
- state.artifact = result;
26
- drawViewer();
27
- } catch (error) {
28
- if (sequence === readSequence) { clear(viewer); viewer.append(note(t("evidence.unavailable") + " " + error.message, "bad")); }
29
- } finally { if (sequence === readSequence) viewer.dataset.reading = "false"; }
30
- }
31
- function drawViewer() {
32
- clear(viewer);
33
- const value = state.artifact;
34
- if (!value) return;
35
- const ref = "git:" + value.commit + ":" + value.relativePath;
36
- const copy = button(t("evidence.copy"), { icon: "copy", variant: "ghost" });
37
- copy.addEventListener("click", async function () {
38
- try { await navigator.clipboard.writeText(data.task.id + " " + ref); copy.lastChild.textContent = t("evidence.copied"); }
39
- catch { copy.lastChild.textContent = t("evidence.copyManual"); }
40
- });
41
- viewer.append(h("header.viewer-head", null, icon("file"), h("strong", null, value.relativePath), h("span.spacer"), copy));
42
- viewer.append(h("p.viewer-ref", null, mono(ref)));
43
- viewer.append(h("p.faint.small", null, t("evidence.fixedNote")));
44
- const content = h("pre.code-block.artifact-text", { tabIndex: 0, "aria-label": t("evidence.fixedText") }, value.content);
45
- viewer.append(content);
46
- }
47
- function drawList() {
48
- clear(list);
49
- const current = state.artifactList;
50
- if (!current) return;
51
- if (state.artifact && current.commit !== state.artifact.commit) list.append(note(t("evidence.differentRevision")));
52
- if (!current.entries.length) { list.append(emptyState(t("evidence.noFiles"), "file")); return; }
53
- current.entries.forEach(function (entry) {
54
- list.append(h("button.file-row", {
55
- type: "button",
56
- "aria-current": String(!!state.artifact && state.artifact.relativePath === entry.relativePath && state.artifact.commit === current.commit),
57
- onclick: function () { read(entry.relativePath, current.commit); }
58
- }, icon("file", "icon-sm"), h("span.file-name", null, entry.relativePath), h("span.faint.small", null, formatBytes(entry.size))));
59
- });
60
- }
61
- load.addEventListener("click", async function () {
62
- load.disabled = true;
63
- list.dataset.reading = "true";
64
- try {
65
- state.artifactList = await actions.artifacts(data.task.id);
66
- drawList();
67
- } catch (error) {
68
- clear(list);
69
- list.append(note(t("evidence.listUnavailable") + " " + error.message, "bad"));
70
- } finally { load.disabled = false; list.dataset.reading = "false"; }
71
- });
72
- // Explicit frozen references stay attached to their original revision.
73
- const sources = [data.task.completionArtifactRefs || [],
74
- data.core.records.filter(function (entry) { return !entry.omitted && ["task-brief", "task-decision"].includes(entry.ref.store); })
75
- .map(function (entry) { return JSON.stringify(entry.value); })].flat().join(" ");
76
- const refs = Array.from(sources.matchAll(/git:([0-9a-f]{40}):([^\s"\\]+?)(?=[\s"\\]|$)/g));
77
- const seen = new Set();
78
- const referenced = h("div.file-list");
79
- refs.forEach(function (match) {
80
- if (seen.has(match[0])) return;
81
- seen.add(match[0]);
82
- referenced.append(h("button.file-row", { type: "button", onclick: function () { read(match[2], match[1]); } },
83
- icon("flag", "icon-sm"), h("span.file-name", null, match[2]), badge(t("evidence.referenced"), "accent")));
84
- });
85
- if (!state.artifactList && !seen.size) files.body.append(emptyState(t("evidence.notLoaded"), "file"));
86
- files.body.append(referenced, list, viewer);
87
- drawList();
88
- drawViewer();
89
- container.append(files);
90
-
91
- const delivery = card({ title: t("evidence.delivery"), icon: "layers", hint: t("evidence.deliveryHint") });
92
- const output = h("div.stack");
93
- const open = button(t("evidence.readDelivery"), { icon: "eye", variant: "ghost" });
94
- delivery.querySelector(".card-head").append(h("div.card-actions", null, open));
95
- delivery.body.append(output);
96
- open.addEventListener("click", function () {
97
- open.disabled = true;
98
- drawDelivery(output, data, t, actions).finally(function () { open.disabled = false; });
99
- });
100
- container.append(delivery);
101
- }
102
-
103
- async function drawDelivery(output, data, t, actions) {
104
- clear(output);
105
- const runtime = data.runtimeStatus === "available" ? data.runtime : null;
106
- if (!runtime) output.append(note(t("evidence.observationUnavailable")));
107
- const remote = runtime && runtime.remoteDelivery;
108
- if (remote) {
109
- output.append(h("h4.sub-head", null, t("evidence.remote"), badge(t("remoteDelivery." + remote.status, remote.status), remote.status === "merged" ? "ok" : "idle")));
110
- remote.projects.forEach(function (project) {
111
- output.append(h("article.record", null,
112
- h("header.record-head", null, h("strong", null, project.directory), h("span.faint.small", null, project.coverage)),
113
- h("p.small", null, project.reason),
114
- h("p.faint.small", null, t("evidence.expectedCommit") + " ", mono(project.expectedLocalCommit || t("common.unknown"))),
115
- h("p.faint.small", null, "PR/MR · " + (project.state || "none") + " · " + t("evidence.verification") + " " + (project.verification || "unverified")),
116
- project.adoption ? h("p.faint.small", null, t("evidence.adoption") + " ", mono(project.adoption.id)) : null));
117
- });
118
- }
119
- const original = h("div.stack", null, h("p.faint", null, t("evidence.readingOriginal")));
120
- output.append(original);
121
- try {
122
- const evidence = await actions.evidence(data.task.id);
123
- clear(original);
124
- original.append(h("h4.sub-head", null, t("evidence.integrations")));
125
- if (!evidence.integrations.length) original.append(note(t("evidence.noIntegrations")));
126
- evidence.integrations.forEach(function (attempt) {
127
- const element = h("article.record", null,
128
- h("header.record-head", null, mono(attempt.id), h("span.spacer"), badge(attempt.status, attempt.status === "succeeded" ? "ok" : "idle")),
129
- h("p.faint.small", null, t("evidence.candidate") + " ", mono(attempt.candidateCommit || t("evidence.noCandidate"))));
130
- if (!attempt.checks || !attempt.checks.length) element.append(h("p.faint.small", null, t("evidence.noChecks")));
131
- (attempt.checks || []).forEach(function (check) {
132
- element.append(h("p.small", null, check.name + " · " + check.outcome));
133
- if (check.details) element.append(h("p.faint.small", null, check.details));
134
- });
135
- original.append(element);
136
- });
137
- original.append(h("h4.sub-head", null, t("evidence.reviews")));
138
- if (!evidence.reviews.length) original.append(note(t("evidence.noReviews")));
139
- evidence.reviews.forEach(function (round) {
140
- const element = h("article.record", null,
141
- h("header.record-head", null, mono(round.id), h("span.spacer"), badge(round.status, round.status === "completed" ? "ok" : "idle")),
142
- h("p.faint.small.mono-line", null, round.taskCandidate
143
- ? round.taskCandidate.projects.map(function (p) { return p.projectId + " · " + p.commit; }).join(" ")
144
- : [round.workItemId, round.candidateId, round.reviewBaseCommit].filter(Boolean).join(" · ")));
145
- if (round.reviewerRunId) {
146
- const report = button(t("evidence.readReport"), { icon: "eye", variant: "link" });
147
- report.addEventListener("click", async function () {
148
- report.disabled = true;
149
- try {
150
- const source = await actions.inspect(data.task.id, { store: "run", refId: round.reviewerRunId });
151
- element.append(richText(round.reviewerRunId, (source.value.result && source.value.result.output) || t("evidence.noReport"), t));
152
- report.remove();
153
- } catch (error) { element.append(note(error.message, "bad")); report.disabled = false; }
154
- });
155
- element.append(report);
156
- }
157
- original.append(element);
158
- });
159
- original.append(h("h4.sub-head", null, t("evidence.workspaces")));
160
- if (!evidence.workspaces.length) original.append(note(t("evidence.noWorkspaces")));
161
- evidence.workspaces.forEach(function (workspace) {
162
- original.append(h("p.small.mono-line", null, workspace.owner.type + " · " + workspace.root));
163
- });
164
- original.append(note(t("evidence.cleanupNote")), h("pre.code-block", null, "yui task archive-preflight " + data.task.id + " --integrated"));
165
- } catch (error) {
166
- clear(original);
167
- original.append(note(t("evidence.originalUnavailable") + " " + error.message, "bad"));
168
- }
169
- const metrics = runtime && observabilityMetricCard(runtime.observability, t);
170
- if (metrics) output.append(h("h4.sub-head", null, t("evidence.usage")), metrics);
171
- }
172
- `;
@@ -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
- `;