@zq-silk/yui 2.3.0 → 2.5.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 (197) 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 +18 -9
  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 +65 -14
  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 +18 -3
  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 +39 -8
  23. package/dist/controller/globalInputDelivery.js +2 -4
  24. package/dist/controller/jobControl.js +2 -0
  25. package/dist/controller/nativeHostInput.js +37 -0
  26. package/dist/controller/providerRetryDelivery.js +4 -2
  27. package/dist/controller/runtime.js +93 -2
  28. package/dist/controller/runtimeEventInbox.js +2 -2
  29. package/dist/controller/runtimeEventProcessor.js +3 -3
  30. package/dist/doctor/doctor.js +10 -0
  31. package/dist/execution/reviewMainRun.js +1 -0
  32. package/dist/execution/workItemMainRun.js +1 -0
  33. package/dist/executor/agentAdapter.js +3 -5
  34. package/dist/executor/codexConfigConflict.js +6 -4
  35. package/dist/executor/effectiveLaunch.js +24 -1
  36. package/dist/executor/fileRoleLaunchPlanner.js +15 -7
  37. package/dist/integration/gitIntegrationService.js +7 -12
  38. package/dist/integration/integrationSourceApplication.js +4 -2
  39. package/dist/interaction/notificationPresentation.js +85 -0
  40. package/dist/interaction/operatorPresentation.js +1 -2
  41. package/dist/job/httpPreview.js +61 -0
  42. package/dist/job/jobRunner.js +12 -2
  43. package/dist/kernel/builtinCapabilities.js +3 -1
  44. package/dist/message/message.js +15 -1
  45. package/dist/output/rolePresentation.js +4 -1
  46. package/dist/repository/executionLaneGitSnapshot.js +2 -1
  47. package/dist/repository/gitCompatibility.js +62 -0
  48. package/dist/repository/gitWorkspace.js +48 -71
  49. package/dist/repository/gitWorktreeInventory.js +121 -0
  50. package/dist/repository/project.js +74 -25
  51. package/dist/resources/resourceDiscovery.js +2 -2
  52. package/dist/resources/resourceGc.js +7 -4
  53. package/dist/resources/resourceRegistrar.js +2 -1
  54. package/dist/runtime/agentEndpoint.js +8 -0
  55. package/dist/runtime/agentHost.js +170 -3
  56. package/dist/runtime/codexAppServerRuntime.js +1 -1
  57. package/dist/runtime/codexNativeAccess.js +175 -0
  58. package/dist/runtime/controlledCodexTui.js +116 -0
  59. package/dist/runtime/publicReply.js +23 -0
  60. package/dist/runtime/runtimeObservation.js +48 -0
  61. package/dist/runtime/structuredProviderHost.js +16 -7
  62. package/dist/runtime/taskCostMetrics.js +133 -0
  63. package/dist/runtime/taskUsageMetrics.js +11 -2
  64. package/dist/runtime/taskUsageQuery.js +38 -0
  65. package/dist/scheduler/leaderWakeupProcessor.js +1 -9
  66. package/dist/scheduler/taskExecutionProjection.js +2 -0
  67. package/dist/scheduler/taskObservabilityProjection.js +9 -1
  68. package/dist/storage/homeLayout.js +13 -0
  69. package/dist/storage/sqliteSchema.js +44 -0
  70. package/dist/storage/sqliteStore.js +53 -0
  71. package/dist/storage/storageVersions.js +1 -1
  72. package/dist/storage/storeRpc.js +2 -0
  73. package/dist/storage/taskSearch.js +35 -0
  74. package/dist/storage/upgrade/projectKnowledgeMigration.js +52 -0
  75. package/dist/task/ordinaryArchive.js +42 -0
  76. package/dist/tmux/tmuxManager.js +8 -8
  77. package/dist/web/assets/assetManifest.js +11 -51
  78. package/dist/web/assets/client/app/catalog.js +215 -0
  79. package/dist/web/assets/client/app/main.js +148 -0
  80. package/dist/web/assets/client/app/selection.js +139 -0
  81. package/dist/web/assets/client/app/settings.js +326 -0
  82. package/dist/web/assets/client/app/taskView.js +280 -0
  83. package/dist/web/assets/client/domain/context.js +96 -0
  84. package/dist/web/assets/client/domain/records.js +126 -0
  85. package/dist/web/assets/client/domain/runs.js +119 -0
  86. package/dist/web/assets/client/domain/taskForms.js +197 -0
  87. package/dist/web/assets/client/domain/vocab.js +69 -0
  88. package/dist/web/assets/client/domain/work.js +116 -0
  89. package/dist/web/assets/client/i18n/en.js +900 -0
  90. package/dist/web/assets/client/i18n/zh-CN.js +898 -0
  91. package/dist/web/assets/client/index.js +114 -0
  92. package/dist/web/assets/client/layout/resizer.js +37 -0
  93. package/dist/web/assets/client/layout/router.js +35 -0
  94. package/dist/web/assets/client/layout/shortcuts.js +45 -0
  95. package/dist/web/assets/client/layout/sizing.js +95 -0
  96. package/dist/web/assets/client/layout/workspace.js +247 -0
  97. package/dist/web/assets/client/{api.js → lib/api.js} +20 -4
  98. package/dist/web/assets/client/{dom.js → lib/dom.js} +24 -12
  99. package/dist/web/assets/client/{format.js → lib/format.js} +7 -0
  100. package/dist/web/assets/client/lib/i18n.js +54 -0
  101. package/dist/web/assets/client/lib/markdown.js +167 -0
  102. package/dist/web/assets/client/lib/prefs.js +28 -0
  103. package/dist/web/assets/client/lib/theme.js +68 -0
  104. package/dist/web/assets/client/ui/containers.js +101 -0
  105. package/dist/web/assets/client/ui/controls.js +51 -0
  106. package/dist/web/assets/client/ui/forms.js +48 -0
  107. package/dist/web/assets/client/ui/metrics.js +137 -0
  108. package/dist/web/assets/client/ui/primitives.js +92 -0
  109. package/dist/web/assets/client/ui/text.js +33 -0
  110. package/dist/web/assets/client/ui/toast.js +12 -0
  111. package/dist/web/assets/client/views/bodySearch.js +172 -0
  112. package/dist/web/assets/client/views/createTask.js +85 -0
  113. package/dist/web/assets/client/views/dock/conversation.js +612 -0
  114. package/dist/web/assets/client/views/dock/discussion.js +173 -0
  115. package/dist/web/assets/client/views/dock/preview.js +129 -0
  116. package/dist/web/assets/client/views/dock/terminal.js +199 -0
  117. package/dist/web/assets/client/views/globalInput.js +67 -0
  118. package/dist/web/assets/client/{overview.js → views/overview.js} +61 -51
  119. package/dist/web/assets/client/{sidebar.js → views/sidebar.js} +56 -62
  120. package/dist/web/assets/client/views/skills.js +152 -0
  121. package/dist/web/assets/client/views/task/actions.js +36 -0
  122. package/dist/web/assets/client/views/task/delivery.js +185 -0
  123. package/dist/web/assets/client/views/task/deliveryResults.js +159 -0
  124. package/dist/web/assets/client/views/task/files.js +272 -0
  125. package/dist/web/assets/client/views/task/observation.js +153 -0
  126. package/dist/web/assets/client/views/task/overview.js +161 -0
  127. package/dist/web/assets/client/views/task/page.js +131 -0
  128. package/dist/web/assets/client/views/task/records.js +163 -0
  129. package/dist/web/assets/client/views/task/runtime.js +130 -0
  130. package/dist/web/assets/client/views/task/timeline.js +190 -0
  131. package/dist/web/assets/shared/geometry.js +19 -0
  132. package/dist/web/assets/shared/taskTabs.js +8 -0
  133. package/dist/web/assets/shared/themes.js +93 -0
  134. package/dist/web/assets/shell/dialogs.js +63 -0
  135. package/dist/web/assets/shell/dock.js +40 -0
  136. package/dist/web/assets/shell/index.js +40 -0
  137. package/dist/web/assets/shell/settings.js +34 -0
  138. package/dist/web/assets/shell/sidebar.js +45 -0
  139. package/dist/web/assets/styles/index.js +41 -0
  140. package/dist/web/assets/styles/{responsive.js → layout/responsive.js} +10 -10
  141. package/dist/web/assets/styles/{layout.js → layout/workspace.js} +17 -24
  142. package/dist/web/assets/styles/markdown.js +22 -3
  143. package/dist/web/assets/styles/tokens.js +10 -63
  144. package/dist/web/assets/styles/ui/controls.js +76 -0
  145. package/dist/web/assets/styles/ui/forms.js +46 -0
  146. package/dist/web/assets/styles/ui/surfaces.js +122 -0
  147. package/dist/web/assets/styles/views/delivery.js +29 -0
  148. package/dist/web/assets/styles/views/dock.js +71 -0
  149. package/dist/web/assets/styles/views/page.js +32 -0
  150. package/dist/web/assets/styles/views/records.js +70 -0
  151. package/dist/web/assets/styles/views/settings.js +26 -0
  152. package/dist/web/assets/styles/views/sidebar.js +74 -0
  153. package/dist/web/assets/styles/views/task.js +80 -0
  154. package/dist/web/assets/styles/views/terminal.js +38 -0
  155. package/dist/web/taskPreviews.js +205 -0
  156. package/dist/web/tmuxWebTerminal.js +16 -9
  157. package/dist/web/webConversation.js +373 -0
  158. package/dist/web/webMaterials.js +155 -0
  159. package/dist/web/webServer.js +295 -18
  160. package/dist/web/webSettings.js +331 -0
  161. package/dist/web/webSkills.js +86 -0
  162. package/dist/web/webSnapshot.js +40 -8
  163. package/dist/web/webTaskSurface.js +106 -8
  164. package/dist/workspace/gitChangeSetCapture.js +3 -1
  165. package/docs/cli-information-contract.md +1 -1
  166. package/docs/cli-information-contract.zh-CN.md +1 -1
  167. package/docs/managed-turn-and-session-runtime.md +31 -0
  168. package/docs/managed-turn-and-session-runtime.zh-CN.md +22 -0
  169. package/docs/release-workflow.md +54 -0
  170. package/docs/release-workflow.zh-CN.md +39 -0
  171. package/docs/storage-baseline.md +38 -1
  172. package/docs/storage-baseline.zh-CN.md +22 -0
  173. package/docs/task-discovery.md +28 -0
  174. package/docs/testing/verification-levels.md +2 -2
  175. package/i18n/README.zh-CN.md +1 -1
  176. package/package.json +1 -1
  177. package/skills/yui-leader/SKILL.md +5 -4
  178. package/skills/yui-leader/references/execution.md +2 -1
  179. package/skills/yui-operator/SKILL.md +3 -0
  180. package/skills/yui-reviewer/SKILL.md +4 -2
  181. package/skills/yui-runtime/SKILL.md +43 -2
  182. package/skills/yui-worker/SKILL.md +3 -2
  183. package/dist/web/assets/client/app.js +0 -808
  184. package/dist/web/assets/client/components.js +0 -477
  185. package/dist/web/assets/client/detail.js +0 -379
  186. package/dist/web/assets/client/dock.js +0 -309
  187. package/dist/web/assets/client/evidence.js +0 -364
  188. package/dist/web/assets/client/forms.js +0 -230
  189. package/dist/web/assets/client/i18n.js +0 -1277
  190. package/dist/web/assets/client/markdown.js +0 -114
  191. package/dist/web/assets/client/records.js +0 -198
  192. package/dist/web/assets/client/sections.js +0 -349
  193. package/dist/web/assets/client/theme.js +0 -71
  194. package/dist/web/assets/shell.js +0 -161
  195. package/dist/web/assets/styles/components.js +0 -216
  196. package/dist/web/assets/styles/views.js +0 -309
  197. /package/dist/web/assets/{icons.js → shared/icons.js} +0 -0
@@ -0,0 +1,114 @@
1
+ // Client module registry. Each module is an ES module served at
2
+ // /assets/js/<path>.js; the entry script is served at /assets/app.js.
3
+ // Layers import only downward:
4
+ // lib/ browser utilities (DOM, formatting, preferences, i18n, theme, API)
5
+ // ui/ domain-free components (primitives, containers, controls, forms)
6
+ // domain/ Yui vocabulary and record rendering (Context reads, work, runs)
7
+ // views/ page regions (sidebar, overview, Task page, dock, dialogs)
8
+ // layout/ workspace columns, sizing, URL state, keyboard shortcuts
9
+ // app/ the composition root (main) and the controllers that own view
10
+ // state; each controller takes one explicit deps object and only
11
+ // main wires controllers to each other
12
+ // See ../README.md for the module map.
13
+ // In-module imports are single-line `import { … } from "/assets/js/…"`.
14
+ import { API_SCRIPT } from "./lib/api.js";
15
+ import { DOM_SCRIPT } from "./lib/dom.js";
16
+ import { FORMAT_SCRIPT } from "./lib/format.js";
17
+ import { I18N_SCRIPT } from "./lib/i18n.js";
18
+ import { MARKDOWN_SCRIPT } from "./lib/markdown.js";
19
+ import { PREFS_SCRIPT } from "./lib/prefs.js";
20
+ import { THEME_SCRIPT } from "./lib/theme.js";
21
+ import { CONTAINERS_SCRIPT } from "./ui/containers.js";
22
+ import { CONTROLS_SCRIPT } from "./ui/controls.js";
23
+ import { FORMS_SCRIPT } from "./ui/forms.js";
24
+ import { METRICS_SCRIPT } from "./ui/metrics.js";
25
+ import { PRIMITIVES_SCRIPT } from "./ui/primitives.js";
26
+ import { TEXT_SCRIPT } from "./ui/text.js";
27
+ import { TOAST_SCRIPT } from "./ui/toast.js";
28
+ import { CONTEXT_SCRIPT } from "./domain/context.js";
29
+ import { RECORDS_SCRIPT } from "./domain/records.js";
30
+ import { RUNS_SCRIPT } from "./domain/runs.js";
31
+ import { TASK_FORMS_SCRIPT } from "./domain/taskForms.js";
32
+ import { VOCAB_SCRIPT } from "./domain/vocab.js";
33
+ import { WORK_SCRIPT } from "./domain/work.js";
34
+ import { DISCUSSION_SCRIPT } from "./views/dock/discussion.js";
35
+ import { CONVERSATION_SCRIPT } from "./views/dock/conversation.js";
36
+ import { TERMINAL_SCRIPT } from "./views/dock/terminal.js";
37
+ import { PREVIEW_SCRIPT } from "./views/dock/preview.js";
38
+ import { GLOBAL_INPUT_SCRIPT } from "./views/globalInput.js";
39
+ import { CREATE_TASK_SCRIPT } from "./views/createTask.js";
40
+ import { BODY_SEARCH_SCRIPT } from "./views/bodySearch.js";
41
+ import { OVERVIEW_SCRIPT } from "./views/overview.js";
42
+ import { SIDEBAR_SCRIPT } from "./views/sidebar.js";
43
+ import { TASK_DELIVERY_SCRIPT } from "./views/task/delivery.js";
44
+ import { TASK_DELIVERY_RESULTS_SCRIPT } from "./views/task/deliveryResults.js";
45
+ import { TASK_FILES_SCRIPT } from "./views/task/files.js";
46
+ import { TASK_OBSERVATION_SCRIPT } from "./views/task/observation.js";
47
+ import { TASK_OVERVIEW_SCRIPT } from "./views/task/overview.js";
48
+ import { TASK_PAGE_SCRIPT } from "./views/task/page.js";
49
+ import { TASK_ACTIONS_SCRIPT } from "./views/task/actions.js";
50
+ import { TASK_RECORDS_SCRIPT } from "./views/task/records.js";
51
+ import { TASK_RUNTIME_SCRIPT } from "./views/task/runtime.js";
52
+ import { TASK_TIMELINE_SCRIPT } from "./views/task/timeline.js";
53
+ import { RESIZER_SCRIPT } from "./layout/resizer.js";
54
+ import { ROUTER_SCRIPT } from "./layout/router.js";
55
+ import { SHORTCUTS_SCRIPT } from "./layout/shortcuts.js";
56
+ import { SIZING_SCRIPT } from "./layout/sizing.js";
57
+ import { WORKSPACE_SCRIPT } from "./layout/workspace.js";
58
+ import { CATALOG_SCRIPT } from "./app/catalog.js";
59
+ import { SELECTION_SCRIPT } from "./app/selection.js";
60
+ import { TASK_VIEW_SCRIPT } from "./app/taskView.js";
61
+ import { SETTINGS_SCRIPT } from "./app/settings.js";
62
+ import { SKILLS_SCRIPT } from "./views/skills.js";
63
+ export { APP_SCRIPT } from "./app/main.js";
64
+ export const CLIENT_MODULES = Object.freeze({
65
+ "views/skills": SKILLS_SCRIPT,
66
+ "lib/dom": DOM_SCRIPT,
67
+ "lib/format": FORMAT_SCRIPT,
68
+ "lib/prefs": PREFS_SCRIPT,
69
+ "lib/i18n": I18N_SCRIPT,
70
+ "lib/theme": THEME_SCRIPT,
71
+ "lib/api": API_SCRIPT,
72
+ "lib/markdown": MARKDOWN_SCRIPT,
73
+ "ui/primitives": PRIMITIVES_SCRIPT,
74
+ "ui/containers": CONTAINERS_SCRIPT,
75
+ "ui/text": TEXT_SCRIPT,
76
+ "ui/controls": CONTROLS_SCRIPT,
77
+ "ui/forms": FORMS_SCRIPT,
78
+ "ui/metrics": METRICS_SCRIPT,
79
+ "ui/toast": TOAST_SCRIPT,
80
+ "domain/vocab": VOCAB_SCRIPT,
81
+ "domain/context": CONTEXT_SCRIPT,
82
+ "domain/records": RECORDS_SCRIPT,
83
+ "domain/work": WORK_SCRIPT,
84
+ "domain/runs": RUNS_SCRIPT,
85
+ "domain/taskForms": TASK_FORMS_SCRIPT,
86
+ "views/sidebar": SIDEBAR_SCRIPT,
87
+ "views/overview": OVERVIEW_SCRIPT,
88
+ "views/globalInput": GLOBAL_INPUT_SCRIPT,
89
+ "views/createTask": CREATE_TASK_SCRIPT,
90
+ "views/bodySearch": BODY_SEARCH_SCRIPT,
91
+ "views/dock/discussion": DISCUSSION_SCRIPT,
92
+ "views/dock/conversation": CONVERSATION_SCRIPT,
93
+ "views/dock/terminal": TERMINAL_SCRIPT,
94
+ "views/dock/preview": PREVIEW_SCRIPT,
95
+ "views/task/page": TASK_PAGE_SCRIPT,
96
+ "views/task/actions": TASK_ACTIONS_SCRIPT,
97
+ "views/task/overview": TASK_OVERVIEW_SCRIPT,
98
+ "views/task/observation": TASK_OBSERVATION_SCRIPT,
99
+ "views/task/runtime": TASK_RUNTIME_SCRIPT,
100
+ "views/task/timeline": TASK_TIMELINE_SCRIPT,
101
+ "views/task/records": TASK_RECORDS_SCRIPT,
102
+ "views/task/delivery": TASK_DELIVERY_SCRIPT,
103
+ "views/task/deliveryResults": TASK_DELIVERY_RESULTS_SCRIPT,
104
+ "views/task/files": TASK_FILES_SCRIPT,
105
+ "layout/resizer": RESIZER_SCRIPT,
106
+ "layout/sizing": SIZING_SCRIPT,
107
+ "layout/workspace": WORKSPACE_SCRIPT,
108
+ "layout/router": ROUTER_SCRIPT,
109
+ "layout/shortcuts": SHORTCUTS_SCRIPT,
110
+ "app/catalog": CATALOG_SCRIPT,
111
+ "app/taskView": TASK_VIEW_SCRIPT,
112
+ "app/settings": SETTINGS_SCRIPT,
113
+ "app/selection": SELECTION_SCRIPT
114
+ });
@@ -0,0 +1,37 @@
1
+ export const RESIZER_SCRIPT = String.raw `
2
+ // A column divider (role="separator") that resizes by pointer drag, arrow /
3
+ // Home / End keys and an optional double-click reset. Dragging is a desktop
4
+ // gesture: below the narrow breakpoint the columns stack and nothing resizes.
5
+ //
6
+ // options: narrow (breakpoint px), bodyClass (set on <body> while dragging),
7
+ // drag(event), release() after a drag, keyWidth(event) → width or null,
8
+ // setWidth(width) for keyboard changes, reset() on double-click.
9
+ export function bindResizeHandle(handle, options) {
10
+ let dragging = false;
11
+ handle.addEventListener("pointerdown", function (event) {
12
+ if (event.button !== 0 || window.innerWidth <= options.narrow) return;
13
+ dragging = true;
14
+ handle.setPointerCapture(event.pointerId);
15
+ document.body.classList.add(options.bodyClass);
16
+ event.preventDefault();
17
+ });
18
+ handle.addEventListener("pointermove", function (event) {
19
+ if (dragging) options.drag(event);
20
+ });
21
+ function finish() {
22
+ if (!dragging) return;
23
+ dragging = false;
24
+ document.body.classList.remove(options.bodyClass);
25
+ options.release();
26
+ }
27
+ handle.addEventListener("pointerup", finish);
28
+ handle.addEventListener("pointercancel", finish);
29
+ handle.addEventListener("keydown", function (event) {
30
+ const width = options.keyWidth(event);
31
+ if (width === null) return;
32
+ event.preventDefault();
33
+ options.setWidth(width);
34
+ });
35
+ if (options.reset) handle.addEventListener("dblclick", options.reset);
36
+ }
37
+ `;
@@ -0,0 +1,35 @@
1
+ export const ROUTER_SCRIPT = String.raw `
2
+ // URL state. The selected Task, section, status filter, search, attention
3
+ // filter and archive scope live in the query string so back/forward, refresh
4
+ // and deep links keep context. Empty parameters are dropped.
5
+ export function readQuery() { return new URLSearchParams(window.location.search); }
6
+
7
+ export function applyUrl(params, replace) {
8
+ const entries = Array.from(params.entries()).filter(function (entry) { return entry[1] !== ""; });
9
+ const search = entries.length ? "?" + entries.map(function (entry) {
10
+ return encodeURIComponent(entry[0]) + "=" + encodeURIComponent(entry[1]);
11
+ }).join("&") : "";
12
+ const url = window.location.pathname + search + window.location.hash;
13
+ history[replace ? "replaceState" : "pushState"]({ task: params.get("task") || null }, "", url);
14
+ }
15
+
16
+ export function urlTaskId() { return readQuery().get("task") || null; }
17
+
18
+ export function syncUrl(state, replace) {
19
+ const params = readQuery();
20
+ if (state.selected) params.set("task", state.selected);
21
+ else { params.delete("task"); params.delete("section"); }
22
+ if (state.filter !== "all") params.set("filter", state.filter); else params.delete("filter");
23
+ if (state.query) params.set("q", state.query); else params.delete("q");
24
+ if (state.attentionFilter) params.set("attention", state.attentionFilter); else params.delete("attention");
25
+ if (state.catalogAll) params.set("all", "true"); else params.delete("all");
26
+ applyUrl(params, replace);
27
+ }
28
+
29
+ export function setSectionParam(state, section) {
30
+ const params = readQuery();
31
+ if (!state.selected || params.get("section") === section) return;
32
+ if (section === "overview") params.delete("section"); else params.set("section", section);
33
+ applyUrl(params, true);
34
+ }
35
+ `;
@@ -0,0 +1,45 @@
1
+ import { TASK_TABS } from "../../shared/taskTabs.js";
2
+ export const SHORTCUTS_SCRIPT = String.raw `
3
+ // Keyboard shortcuts (listed in the settings dialog). They yield to open
4
+ // dialogs, to typing and to a focused native Session, which needs its own keys.
5
+ import { isEditing } from "/assets/js/lib/dom.js";
6
+
7
+ const TABS = ${JSON.stringify(TASK_TABS)};
8
+
9
+ // deps: { el, state, globalInput, workspace, selection, catalog, taskView }
10
+ // el #search, #settings-dialog and #terminal-host
11
+ // state read-only here: state.selected, state.detail
12
+ // globalInput views/globalInput (its dialog blocks shortcuts while open)
13
+ // workspace layout/workspace: the dock and the operator Session
14
+ // selection app/selection: Escape leaves the Task
15
+ // catalog app/catalog: "r" refreshes
16
+ // taskView app/taskView: 1–4 switch tabs
17
+ export function bindShortcuts(deps) {
18
+ document.addEventListener("keydown", function (event) {
19
+ if (document.querySelector("dialog[open]")) return;
20
+ const active = document.activeElement;
21
+ const typing = isEditing(active);
22
+ const inTerminal = deps.el.terminalHost.contains(active);
23
+ if (event.key === "Escape") { escape(deps, active, typing, inTerminal); return; }
24
+ if (typing || inTerminal || event.metaKey || event.ctrlKey || event.altKey) return;
25
+ shortcut(deps, event);
26
+ });
27
+ }
28
+
29
+ // Escape unwinds one level: leave a field, close the dock, leave the Task.
30
+ function escape(deps, active, typing, inTerminal) {
31
+ if (inTerminal) return;
32
+ if (typing) { active.blur(); return; }
33
+ if (deps.workspace.dockVisible()) { deps.workspace.setDockOpen(false); return; }
34
+ if (deps.state.selected) deps.selection.clearSelection();
35
+ }
36
+
37
+ function shortcut(deps, event) {
38
+ const key = event.key.toLowerCase();
39
+ if (key === "/") { event.preventDefault(); deps.el.search.focus(); deps.el.search.select(); }
40
+ else if (key === "r") deps.catalog.refresh();
41
+ else if (key === "o") deps.workspace.openOperator();
42
+ else if (key === "d") deps.workspace.toggleDock();
43
+ else if (/^[1-9]$/.test(key) && Number(key) <= TABS.length && deps.state.detail) deps.taskView.switchTab(TABS[Number(key) - 1]);
44
+ }
45
+ `;
@@ -0,0 +1,95 @@
1
+ import { LAYOUT_GEOMETRY } from "../../shared/geometry.js";
2
+ export const SIZING_SCRIPT = String.raw `
3
+ // Column widths. The task list and the dock are user-sized preferences; the
4
+ // width actually applied is clamped so the task column keeps its minimum in
5
+ // the current window. Geometry comes from shared/geometry.ts.
6
+ import { writePreference, clearPreference } from "/assets/js/lib/prefs.js";
7
+ import { bindResizeHandle } from "/assets/js/layout/resizer.js";
8
+
9
+ const G = ${JSON.stringify(LAYOUT_GEOMETRY)};
10
+
11
+ function clamp(value, min, max) {
12
+ return Math.max(min, Math.min(max, value));
13
+ }
14
+
15
+ // el: { sidebar, sidebarDivider, dock, divider }; dock: the dock view state
16
+ // (width, center); sidebar: { width } where null keeps the CSS default.
17
+ export function createSizing(el, dock, sidebar, dockVisible) {
18
+ const root = document.documentElement.style;
19
+
20
+ function maxDockWidth() {
21
+ const aside = window.innerWidth > G.narrow ? el.sidebar.offsetWidth : 0;
22
+ return Math.max(G.dock.min, Math.min(G.dock.max, window.innerWidth - aside - G.centerMin));
23
+ }
24
+ function setDockWidth(width, persist) {
25
+ const effective = clamp(width, G.dock.min, maxDockWidth());
26
+ root.setProperty("--dock-w", effective + "px");
27
+ el.divider.setAttribute("aria-valuemax", String(maxDockWidth()));
28
+ el.divider.setAttribute("aria-valuenow", String(effective));
29
+ if (persist) { dock.width = effective; writePreference("yui.dock.width", String(effective)); }
30
+ }
31
+ function maxSidebarWidth() {
32
+ // An open dock can shrink to its minimum, so it reserves only that much.
33
+ const reserve = dockVisible() ? G.dock.min + G.divider : 0;
34
+ return Math.max(G.sidebar.min, Math.min(G.sidebar.max, window.innerWidth - reserve - G.centerMin));
35
+ }
36
+ function applySidebarWidth() {
37
+ if (sidebar.width === null) root.removeProperty("--sidebar-w");
38
+ else root.setProperty("--sidebar-w", clamp(sidebar.width, G.sidebar.min, maxSidebarWidth()) + "px");
39
+ // A wider task list leaves the dock less room; the dock keeps its stored width.
40
+ setDockWidth(dock.width, false);
41
+ el.sidebarDivider.setAttribute("aria-valuemax", String(maxSidebarWidth()));
42
+ el.sidebarDivider.setAttribute("aria-valuenow", String(el.sidebar.offsetWidth));
43
+ }
44
+ function setSidebarWidth(width, persist) {
45
+ sidebar.width = width === null ? null : clamp(Math.round(width), G.sidebar.min, maxSidebarWidth());
46
+ if (persist) {
47
+ if (sidebar.width === null) clearPreference("yui.sidebar.width");
48
+ else writePreference("yui.sidebar.width", String(sidebar.width));
49
+ }
50
+ applySidebarWidth();
51
+ }
52
+
53
+ const sizing = { maxDockWidth, setDockWidth, maxSidebarWidth, applySidebarWidth, setSidebarWidth };
54
+ bindDockDivider(el, dock, sizing);
55
+ bindSidebarDivider(el, sidebar, sizing);
56
+ window.addEventListener("resize", applySidebarWidth);
57
+ return sizing;
58
+ }
59
+
60
+ function bindDockDivider(el, dock, sizing) {
61
+ bindResizeHandle(el.divider, {
62
+ narrow: G.narrow, bodyClass: "dock-resizing",
63
+ drag: function (event) {
64
+ const rect = el.dock.getBoundingClientRect();
65
+ const width = dock.center ? event.clientX - rect.left : rect.right - event.clientX;
66
+ sizing.setDockWidth(width, false);
67
+ dock.width = clamp(width, G.dock.min, sizing.maxDockWidth());
68
+ },
69
+ release: function () { writePreference("yui.dock.width", String(dock.width)); },
70
+ keyWidth: function (event) {
71
+ // The dock grows away from the divider: leftwards at the end, rightwards in the center.
72
+ const grow = dock.center ? "ArrowRight" : "ArrowLeft";
73
+ const shrink = dock.center ? "ArrowLeft" : "ArrowRight";
74
+ return event.key === grow ? dock.width + G.dock.step : event.key === shrink ? dock.width - G.dock.step
75
+ : event.key === "Home" ? G.dock.min : event.key === "End" ? sizing.maxDockWidth() : null;
76
+ },
77
+ setWidth: function (width) { sizing.setDockWidth(width, true); }
78
+ });
79
+ }
80
+
81
+ function bindSidebarDivider(el, sidebar, sizing) {
82
+ bindResizeHandle(el.sidebarDivider, {
83
+ narrow: G.narrow, bodyClass: "sidebar-resizing",
84
+ drag: function (event) { sizing.setSidebarWidth(event.clientX - el.sidebar.getBoundingClientRect().left, false); },
85
+ release: function () { if (sidebar.width !== null) writePreference("yui.sidebar.width", String(sidebar.width)); },
86
+ keyWidth: function (event) {
87
+ const current = el.sidebar.offsetWidth;
88
+ return event.key === "ArrowRight" ? current + G.sidebar.step : event.key === "ArrowLeft" ? current - G.sidebar.step
89
+ : event.key === "Home" ? G.sidebar.min : event.key === "End" ? sizing.maxSidebarWidth() : null;
90
+ },
91
+ setWidth: function (width) { sizing.setSidebarWidth(width, true); },
92
+ reset: function () { sizing.setSidebarWidth(null, true); }
93
+ });
94
+ }
95
+ `;
@@ -0,0 +1,247 @@
1
+ import { BREAKPOINTS, DOCK } from "../../shared/geometry.js";
2
+ export const WORKSPACE_SCRIPT = String.raw `
3
+ // The sidebar | center | dock workspace. The dock holds the Task discussion
4
+ // or a live native Session; on desktop it is a resizable column (at the end or
5
+ // in the center), below the narrow breakpoint a full-screen sheet opened
6
+ // explicitly per Task. Everything here is view state and browser preference.
7
+ import { readPreference, writePreference, readSessionAccessMode } from "/assets/js/lib/prefs.js";
8
+ import { markSelected } from "/assets/js/lib/dom.js";
9
+ import { createSizing } from "/assets/js/layout/sizing.js";
10
+
11
+ const NARROW_QUERY = "(max-width: ${BREAKPOINTS.narrow}px)";
12
+ const DOCK_INITIAL = ${DOCK.initial};
13
+
14
+ // deps: { el, state, terminal, sessionOpened }
15
+ // el the shell elements (dock, dividers, sidebar, operator button,
16
+ // and the Task page's [data-dock-toggle] buttons inside el.detail)
17
+ // state read-only here: state.selected
18
+ // terminal the dock's native Session (views/dock/terminal)
19
+ // sessionOpened() a Session was just opened in the dock; the caller
20
+ // refreshes the Session target chips (app/taskView).
21
+ // The dock state (open, mode, side, width, sheet) is private to this module.
22
+ export function createWorkspace(deps) {
23
+ const ws = {
24
+ deps: deps,
25
+ dock: readDockState(),
26
+ // Task list width: null keeps the CSS default (--sidebar-w); otherwise
27
+ // the width the user dragged to.
28
+ sidebar: { width: Number(readPreference("yui.sidebar.width", "")) || null },
29
+ narrow: window.matchMedia(NARROW_QUERY),
30
+ sizing: null
31
+ };
32
+ ws.sizing = createSizing(deps.el, ws.dock, ws.sidebar, function () { return dockVisible(ws); });
33
+ bindDockControls(ws);
34
+ ws.narrow.addEventListener("change", function () { updateLayout(ws); });
35
+ return {
36
+ dockVisible: function () { return dockVisible(ws); },
37
+ updateLayout: function () { updateLayout(ws); },
38
+ syncDockButtons: function () { syncDockButtons(ws); },
39
+ setDockOpen: function (open) { setDockOpen(ws, open); },
40
+ toggleDock: function (mode) { toggleDock(ws, mode); },
41
+ openSession: function (target) { openSession(ws, target); },
42
+ openConversation: function (target, materials) {
43
+ ws.deps.terminal.close();
44
+ showDock(ws, true);
45
+ ws.dock.mode = "conversation";
46
+ updateLayout(ws);
47
+ ws.deps.conversation.open(target, { current: true, materials: materials });
48
+ syncDockButtons(ws);
49
+ },
50
+ openOperator: function () { openOperator(ws); },
51
+ restoreDefaultMode: function () {
52
+ if (!ws.deps.state.selected && ws.dock.open && !ws.narrow.matches && preferredMode() === "session") {
53
+ openSession(ws, { scope: "global", roleName: "operator" });
54
+ }
55
+ },
56
+ // A newly selected Task starts with the narrow-screen sheet closed.
57
+ enterTask: function () {
58
+ ws.deps.terminal.close();
59
+ ws.terminalTarget = { scope: "task", taskId: ws.deps.state.selected, roleName: "leader" };
60
+ ws.dock.sheet = false;
61
+ ws.dock.mode = preferredMode();
62
+ ws.deps.conversation.open({ scope: "task", taskId: ws.deps.state.selected, roleName: "leader" });
63
+ if (ws.dock.mode === "session" && !ws.narrow.matches && ws.dock.open) {
64
+ ws.deps.terminal.open({ scope: "task", taskId: ws.deps.state.selected, roleName: "leader" });
65
+ }
66
+ },
67
+ leaveTask: function () { leaveTask(ws); }
68
+ };
69
+ }
70
+
71
+ function readDockState() {
72
+ return {
73
+ open: readPreference("yui.dock.open", "true") !== "false",
74
+ mode: "conversation",
75
+ center: readPreference("yui.dock.side", "end") === "center",
76
+ width: Number(readPreference("yui.dock.width", String(DOCK_INITIAL))) || DOCK_INITIAL,
77
+ // On narrow screens the dock is a full-screen sheet opened explicitly per
78
+ // Task, never restored from the desktop preference.
79
+ sheet: false
80
+ };
81
+ }
82
+
83
+ function preferredMode() {
84
+ return readSessionAccessMode() === "native" ? "session" : "conversation";
85
+ }
86
+
87
+ function dockVisible(ws) {
88
+ const dock = ws.dock;
89
+ if (ws.narrow.matches ? !dock.sheet : !dock.open) return false;
90
+ if (ws.deps.state.selected) return true;
91
+ if (dock.mode === "conversation") return true;
92
+ return dock.mode === "session" && !!ws.deps.terminal.current();
93
+ }
94
+
95
+ function updateLayout(ws) {
96
+ const el = ws.deps.el;
97
+ const dock = ws.dock;
98
+ const selected = !!ws.deps.state.selected;
99
+ const visible = dockVisible(ws);
100
+ document.body.classList.toggle("task-open", selected);
101
+ document.body.classList.toggle("dock-open", visible);
102
+ document.body.classList.toggle("dock-center", dock.center);
103
+ el.dock.hidden = !visible;
104
+ el.divider.hidden = !visible;
105
+ el.discussion.hidden = dock.mode !== "discussion";
106
+ el.session.hidden = dock.mode !== "session";
107
+ el.conversation.hidden = dock.mode !== "conversation";
108
+ el.preview.hidden = dock.mode !== "preview";
109
+ el.dockTabPreview.setAttribute("aria-selected", String(dock.mode === "preview"));
110
+ el.dockTabPreview.disabled = !selected;
111
+ if (visible && dock.mode === "preview" && selected) ws.deps.preview.open(ws.deps.state.selected);
112
+ else ws.deps.preview.close();
113
+ el.dockTabConversation.setAttribute("aria-selected", String(dock.mode === "conversation"));
114
+ el.dockTabDiscussion.setAttribute("aria-selected", String(dock.mode === "discussion"));
115
+ el.dockTabSession.setAttribute("aria-selected", String(dock.mode === "session"));
116
+ el.dockTabDiscussion.disabled = !selected;
117
+ el.dockSwap.setAttribute("aria-pressed", String(dock.center));
118
+ ws.sizing.applySidebarWidth();
119
+ syncDockButtons(ws);
120
+ }
121
+
122
+ function syncDockButtons(ws) {
123
+ const el = ws.deps.el;
124
+ const visible = dockVisible(ws);
125
+ markSelected(el.detail.querySelectorAll("[data-dock-toggle]"), "aria-pressed", function (button) {
126
+ return visible && ws.dock.mode === button.dataset.dockToggle;
127
+ });
128
+ el.operator.setAttribute("aria-pressed", String(operatorShown(ws)));
129
+ }
130
+
131
+ // The dock currently shows the global operator Session.
132
+ function operatorShown(ws) {
133
+ if (ws.dock.mode === "conversation") return dockVisible(ws) && ws.deps.conversation.current()?.scope === "global";
134
+ const current = ws.deps.terminal.current();
135
+ return dockVisible(ws) && ws.dock.mode === "session" && !!current && current.scope === "global";
136
+ }
137
+
138
+ function showDock(ws, open) {
139
+ if (ws.narrow.matches) ws.dock.sheet = open;
140
+ else {
141
+ ws.dock.open = open;
142
+ writePreference("yui.dock.open", String(open));
143
+ }
144
+ }
145
+
146
+ function setDockOpen(ws, open) {
147
+ showDock(ws, open);
148
+ if (!open) {
149
+ ws.terminalTarget = ws.deps.terminal.current() || ws.terminalTarget;
150
+ ws.deps.terminal.close();
151
+ }
152
+ if (!open) ws.deps.conversation.close();
153
+ if (open && ws.dock.mode === "conversation") ws.deps.conversation.reconnect();
154
+ if (open && ws.dock.mode === "session") {
155
+ // Keep the selected owner, not a Session identity cached before hiding.
156
+ const target = ws.terminalTarget || { scope: "global", roleName: "operator" };
157
+ ws.deps.terminal.open({ scope: target.scope, roleName: target.roleName,
158
+ ...(target.scope === "task" ? { taskId: target.taskId } : {}) });
159
+ }
160
+ updateLayout(ws);
161
+ }
162
+
163
+ function setDockMode(ws, mode) {
164
+ if (mode === "preview" && ws.deps.state.selected) {
165
+ ws.deps.terminal.close();
166
+ ws.deps.conversation.close();
167
+ ws.dock.mode = "preview";
168
+ updateLayout(ws);
169
+ return;
170
+ }
171
+ if (mode === "conversation") {
172
+ const target = ws.deps.terminal.current() || ws.deps.conversation.current();
173
+ ws.deps.terminal.close();
174
+ ws.dock.mode = mode;
175
+ updateLayout(ws);
176
+ ws.deps.conversation.open(target ? { scope: target.scope, ...(target.scope === "task" ? { taskId: target.taskId } : {}), roleName: target.roleName } : ws.deps.state.selected
177
+ ? { scope: "task", taskId: ws.deps.state.selected, roleName: "leader" }
178
+ : { scope: "global", roleName: "operator" });
179
+ return;
180
+ }
181
+ if (mode === "session") {
182
+ const target = ws.deps.conversation.selection();
183
+ if (!target) return;
184
+ openSession(ws, target);
185
+ return;
186
+ }
187
+ ws.deps.terminal.close();
188
+ ws.deps.conversation.close();
189
+ ws.dock.mode = mode === "session" || !ws.deps.state.selected ? "session" : "discussion";
190
+ updateLayout(ws);
191
+ }
192
+
193
+ function toggleDock(ws, mode) {
194
+ const dock = ws.dock;
195
+ const selected = ws.deps.state.selected;
196
+ if (dockVisible(ws) && (!mode || dock.mode === mode)) { setDockOpen(ws, false); return; }
197
+ if (mode) dock.mode = mode === "session" || !selected ? mode : "discussion";
198
+ if (!selected && dock.mode === "discussion") dock.mode = "session";
199
+ setDockOpen(ws, true);
200
+ }
201
+
202
+ function openSession(ws, target) {
203
+ ws.terminalTarget = target;
204
+ ws.deps.conversation.close();
205
+ ws.dock.mode = "session";
206
+ showDock(ws, true);
207
+ ws.deps.terminal.open(target);
208
+ updateLayout(ws);
209
+ ws.deps.sessionOpened();
210
+ }
211
+
212
+ function openOperator(ws) {
213
+ ws.deps.terminal.close();
214
+ showDock(ws, true);
215
+ setDockMode(ws, "conversation");
216
+ ws.deps.conversation.open({ scope: "global", roleName: "operator" });
217
+ if (preferredMode() === "session") openSession(ws, { scope: "global", roleName: "operator" });
218
+ syncDockButtons(ws);
219
+ }
220
+
221
+ // Leaving a Task: when the dock's last Session belonged to a Task and is no
222
+ // longer connected, the dock returns to the discussion mode.
223
+ function leaveTask(ws) {
224
+ ws.deps.terminal.close();
225
+ ws.dock.mode = "conversation";
226
+ ws.deps.conversation.open({ scope: "global", roleName: "operator" });
227
+ }
228
+
229
+ function bindDockControls(ws) {
230
+ const el = ws.deps.el;
231
+ const dock = ws.dock;
232
+ el.dockTabDiscussion.addEventListener("click", function () { setDockMode(ws, "discussion"); });
233
+ el.dockTabConversation.addEventListener("click", function () { setDockMode(ws, "conversation"); });
234
+ el.dockTabSession.addEventListener("click", function () { setDockMode(ws, "session"); });
235
+ el.dockTabPreview.addEventListener("click", function () { setDockMode(ws, "preview"); });
236
+ el.dockClose.addEventListener("click", function () { setDockOpen(ws, false); });
237
+ el.dockSwap.addEventListener("click", function () {
238
+ dock.center = !dock.center;
239
+ writePreference("yui.dock.side", dock.center ? "center" : "end");
240
+ updateLayout(ws);
241
+ });
242
+ el.operator.addEventListener("click", function () {
243
+ if (operatorShown(ws)) setDockOpen(ws, false);
244
+ else openOperator(ws);
245
+ });
246
+ }
247
+ `;
@@ -57,12 +57,24 @@ export function releaseMutation(key) { unresolved.delete(key); }
57
57
  const task = function (taskId) { return "/api/tasks/" + encodeURIComponent(taskId); };
58
58
 
59
59
  export const api = {
60
+ searchBodies: function (query) { return requestJson("/api/search?" + query); },
61
+ searchSource: function (item, offset) {
62
+ return requestJson(task(item.taskId) + "/search-source?" + new URLSearchParams({
63
+ store: item.ref.store, ref: item.ref.refId, digest: item.ref.digest, field: item.field, offset: String(offset)
64
+ }));
65
+ },
60
66
  dashboard: function (query) { return requestJson("/api/dashboard?" + query); },
61
67
  pageSessions: function (query) {
62
68
  return requestJson("/api/dashboard/sessions?" + query, { signal: AbortSignal.timeout(5000) });
63
69
  },
64
70
  context: function (taskId) { return requestJson(task(taskId) + "/context"); },
65
- observation: function (taskId) { return requestJson(task(taskId), { signal: AbortSignal.timeout(1500) }); },
71
+ workbench: function (taskId) { return requestJson(task(taskId) + "/workbench"); },
72
+ observation: function (taskId) { return requestJson(task(taskId) + "?compact=true", { signal: AbortSignal.timeout(1500) }); },
73
+ projects: function (after) { return requestJson("/api/projects" + (after ? "?after=" + encodeURIComponent(after) : "")); },
74
+ createTask: function (input) { return submitMutation("task/create", "/api/tasks", input); },
75
+ taskAction: function (taskId, action, requestId) {
76
+ return submitMutation(taskId + "/" + action, task(taskId) + "/" + action, { requestId });
77
+ },
66
78
  inspect: async function (taskId, ref) {
67
79
  const query = new URLSearchParams({ store: ref.store, ref: ref.refId });
68
80
  if (ref.digest) query.set("digest", ref.digest);
@@ -92,9 +104,13 @@ export const api = {
92
104
  });
93
105
  return requestJson(task(taskId) + "/list?" + query);
94
106
  },
95
- artifacts: function (taskId) { return requestJson(task(taskId) + "/artifacts"); },
96
- artifact: function (taskId, path, commit) {
97
- return requestJson(task(taskId) + "/artifacts?" + new URLSearchParams({ path, commit }));
107
+ artifacts: function (taskId, commit, offset) {
108
+ return requestJson(task(taskId) + "/artifacts?" + new URLSearchParams(commit ? { commit, offset: offset || 0 } : {}));
109
+ },
110
+ artifact: function (taskId, path, commit, offset, before) {
111
+ return requestJson(task(taskId) + "/artifacts?" + new URLSearchParams({
112
+ path, commit, offset: offset || 0, ...(before ? { before } : {})
113
+ }));
98
114
  },
99
115
  evidence: function (taskId) { return requestJson(task(taskId) + "/evidence"); },
100
116
  panels: function (taskId) { return requestJson(task(taskId) + "/panels", { signal: AbortSignal.timeout(3000) }); },