@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.
- package/README.md +15 -1
- package/dist/artifacts/artifactCapability.js +39 -10
- package/dist/artifacts/imageMetadata.js +120 -0
- package/dist/artifacts/managedGit.js +7 -4
- package/dist/artifacts/taskArtifactRepository.js +6 -0
- package/dist/cli/commandCatalog.js +18 -9
- package/dist/cli/invocationAuthority.js +1 -1
- package/dist/commands/executionAuditCommands.js +5 -0
- package/dist/commands/globalRoleCommands.js +41 -3
- package/dist/commands/projectCommands.js +89 -94
- package/dist/commands/roleSkillValidation.js +4 -8
- package/dist/commands/taskCommands.js +65 -14
- package/dist/commands/taskUsageCommand.js +38 -0
- package/dist/context/roleSessionContext.js +18 -2
- package/dist/context/runContextPack.js +5 -1
- package/dist/context/sessionBootstrapManifest.js +18 -3
- package/dist/context/skillCatalog.js +108 -0
- package/dist/context/skillPackage.js +161 -0
- package/dist/context/taskContext.js +3 -2
- package/dist/context/taskSearch.js +127 -0
- package/dist/controlPlaneCli.js +25 -20
- package/dist/controller/fileSchedulerStoreAdapter.js +39 -8
- package/dist/controller/globalInputDelivery.js +2 -4
- package/dist/controller/jobControl.js +2 -0
- package/dist/controller/nativeHostInput.js +37 -0
- package/dist/controller/providerRetryDelivery.js +4 -2
- package/dist/controller/runtime.js +93 -2
- package/dist/controller/runtimeEventInbox.js +2 -2
- package/dist/controller/runtimeEventProcessor.js +3 -3
- package/dist/doctor/doctor.js +10 -0
- package/dist/execution/reviewMainRun.js +1 -0
- package/dist/execution/workItemMainRun.js +1 -0
- package/dist/executor/agentAdapter.js +3 -5
- package/dist/executor/codexConfigConflict.js +6 -4
- package/dist/executor/effectiveLaunch.js +24 -1
- package/dist/executor/fileRoleLaunchPlanner.js +15 -7
- package/dist/integration/gitIntegrationService.js +7 -12
- package/dist/integration/integrationSourceApplication.js +4 -2
- package/dist/interaction/notificationPresentation.js +85 -0
- package/dist/interaction/operatorPresentation.js +1 -2
- package/dist/job/httpPreview.js +61 -0
- package/dist/job/jobRunner.js +12 -2
- package/dist/kernel/builtinCapabilities.js +3 -1
- package/dist/message/message.js +15 -1
- package/dist/output/rolePresentation.js +4 -1
- package/dist/repository/executionLaneGitSnapshot.js +2 -1
- package/dist/repository/gitCompatibility.js +62 -0
- package/dist/repository/gitWorkspace.js +48 -71
- package/dist/repository/gitWorktreeInventory.js +121 -0
- package/dist/repository/project.js +74 -25
- package/dist/resources/resourceDiscovery.js +2 -2
- package/dist/resources/resourceGc.js +7 -4
- package/dist/resources/resourceRegistrar.js +2 -1
- package/dist/runtime/agentEndpoint.js +8 -0
- package/dist/runtime/agentHost.js +170 -3
- package/dist/runtime/codexAppServerRuntime.js +1 -1
- package/dist/runtime/codexNativeAccess.js +175 -0
- package/dist/runtime/controlledCodexTui.js +116 -0
- package/dist/runtime/publicReply.js +23 -0
- package/dist/runtime/runtimeObservation.js +48 -0
- package/dist/runtime/structuredProviderHost.js +16 -7
- package/dist/runtime/taskCostMetrics.js +133 -0
- package/dist/runtime/taskUsageMetrics.js +11 -2
- package/dist/runtime/taskUsageQuery.js +38 -0
- package/dist/scheduler/leaderWakeupProcessor.js +1 -9
- package/dist/scheduler/taskExecutionProjection.js +2 -0
- package/dist/scheduler/taskObservabilityProjection.js +9 -1
- package/dist/storage/homeLayout.js +13 -0
- package/dist/storage/sqliteSchema.js +44 -0
- package/dist/storage/sqliteStore.js +53 -0
- package/dist/storage/storageVersions.js +1 -1
- package/dist/storage/storeRpc.js +2 -0
- package/dist/storage/taskSearch.js +35 -0
- package/dist/storage/upgrade/projectKnowledgeMigration.js +52 -0
- package/dist/task/ordinaryArchive.js +42 -0
- package/dist/tmux/tmuxManager.js +8 -8
- package/dist/web/assets/assetManifest.js +11 -51
- package/dist/web/assets/client/app/catalog.js +215 -0
- package/dist/web/assets/client/app/main.js +148 -0
- package/dist/web/assets/client/app/selection.js +139 -0
- package/dist/web/assets/client/app/settings.js +326 -0
- package/dist/web/assets/client/app/taskView.js +280 -0
- package/dist/web/assets/client/domain/context.js +96 -0
- package/dist/web/assets/client/domain/records.js +126 -0
- package/dist/web/assets/client/domain/runs.js +119 -0
- package/dist/web/assets/client/domain/taskForms.js +197 -0
- package/dist/web/assets/client/domain/vocab.js +69 -0
- package/dist/web/assets/client/domain/work.js +116 -0
- package/dist/web/assets/client/i18n/en.js +900 -0
- package/dist/web/assets/client/i18n/zh-CN.js +898 -0
- package/dist/web/assets/client/index.js +114 -0
- package/dist/web/assets/client/layout/resizer.js +37 -0
- package/dist/web/assets/client/layout/router.js +35 -0
- package/dist/web/assets/client/layout/shortcuts.js +45 -0
- package/dist/web/assets/client/layout/sizing.js +95 -0
- package/dist/web/assets/client/layout/workspace.js +247 -0
- package/dist/web/assets/client/{api.js → lib/api.js} +20 -4
- package/dist/web/assets/client/{dom.js → lib/dom.js} +24 -12
- package/dist/web/assets/client/{format.js → lib/format.js} +7 -0
- package/dist/web/assets/client/lib/i18n.js +54 -0
- package/dist/web/assets/client/lib/markdown.js +167 -0
- package/dist/web/assets/client/lib/prefs.js +28 -0
- package/dist/web/assets/client/lib/theme.js +68 -0
- package/dist/web/assets/client/ui/containers.js +101 -0
- package/dist/web/assets/client/ui/controls.js +51 -0
- package/dist/web/assets/client/ui/forms.js +48 -0
- package/dist/web/assets/client/ui/metrics.js +137 -0
- package/dist/web/assets/client/ui/primitives.js +92 -0
- package/dist/web/assets/client/ui/text.js +33 -0
- package/dist/web/assets/client/ui/toast.js +12 -0
- package/dist/web/assets/client/views/bodySearch.js +172 -0
- package/dist/web/assets/client/views/createTask.js +85 -0
- package/dist/web/assets/client/views/dock/conversation.js +612 -0
- package/dist/web/assets/client/views/dock/discussion.js +173 -0
- package/dist/web/assets/client/views/dock/preview.js +129 -0
- package/dist/web/assets/client/views/dock/terminal.js +199 -0
- package/dist/web/assets/client/views/globalInput.js +67 -0
- package/dist/web/assets/client/{overview.js → views/overview.js} +61 -51
- package/dist/web/assets/client/{sidebar.js → views/sidebar.js} +56 -62
- package/dist/web/assets/client/views/skills.js +152 -0
- package/dist/web/assets/client/views/task/actions.js +36 -0
- package/dist/web/assets/client/views/task/delivery.js +185 -0
- package/dist/web/assets/client/views/task/deliveryResults.js +159 -0
- package/dist/web/assets/client/views/task/files.js +272 -0
- package/dist/web/assets/client/views/task/observation.js +153 -0
- package/dist/web/assets/client/views/task/overview.js +161 -0
- package/dist/web/assets/client/views/task/page.js +131 -0
- package/dist/web/assets/client/views/task/records.js +163 -0
- package/dist/web/assets/client/views/task/runtime.js +130 -0
- package/dist/web/assets/client/views/task/timeline.js +190 -0
- package/dist/web/assets/shared/geometry.js +19 -0
- package/dist/web/assets/shared/taskTabs.js +8 -0
- package/dist/web/assets/shared/themes.js +93 -0
- package/dist/web/assets/shell/dialogs.js +63 -0
- package/dist/web/assets/shell/dock.js +40 -0
- package/dist/web/assets/shell/index.js +40 -0
- package/dist/web/assets/shell/settings.js +34 -0
- package/dist/web/assets/shell/sidebar.js +45 -0
- package/dist/web/assets/styles/index.js +41 -0
- package/dist/web/assets/styles/{responsive.js → layout/responsive.js} +10 -10
- package/dist/web/assets/styles/{layout.js → layout/workspace.js} +17 -24
- package/dist/web/assets/styles/markdown.js +22 -3
- package/dist/web/assets/styles/tokens.js +10 -63
- package/dist/web/assets/styles/ui/controls.js +76 -0
- package/dist/web/assets/styles/ui/forms.js +46 -0
- package/dist/web/assets/styles/ui/surfaces.js +122 -0
- package/dist/web/assets/styles/views/delivery.js +29 -0
- package/dist/web/assets/styles/views/dock.js +71 -0
- package/dist/web/assets/styles/views/page.js +32 -0
- package/dist/web/assets/styles/views/records.js +70 -0
- package/dist/web/assets/styles/views/settings.js +26 -0
- package/dist/web/assets/styles/views/sidebar.js +74 -0
- package/dist/web/assets/styles/views/task.js +80 -0
- package/dist/web/assets/styles/views/terminal.js +38 -0
- package/dist/web/taskPreviews.js +205 -0
- package/dist/web/tmuxWebTerminal.js +16 -9
- package/dist/web/webConversation.js +373 -0
- package/dist/web/webMaterials.js +155 -0
- package/dist/web/webServer.js +295 -18
- package/dist/web/webSettings.js +331 -0
- package/dist/web/webSkills.js +86 -0
- package/dist/web/webSnapshot.js +40 -8
- package/dist/web/webTaskSurface.js +106 -8
- package/dist/workspace/gitChangeSetCapture.js +3 -1
- package/docs/cli-information-contract.md +1 -1
- package/docs/cli-information-contract.zh-CN.md +1 -1
- package/docs/managed-turn-and-session-runtime.md +31 -0
- package/docs/managed-turn-and-session-runtime.zh-CN.md +22 -0
- package/docs/release-workflow.md +54 -0
- package/docs/release-workflow.zh-CN.md +39 -0
- package/docs/storage-baseline.md +38 -1
- package/docs/storage-baseline.zh-CN.md +22 -0
- package/docs/task-discovery.md +28 -0
- package/docs/testing/verification-levels.md +2 -2
- package/i18n/README.zh-CN.md +1 -1
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +5 -4
- package/skills/yui-leader/references/execution.md +2 -1
- package/skills/yui-operator/SKILL.md +3 -0
- package/skills/yui-reviewer/SKILL.md +4 -2
- package/skills/yui-runtime/SKILL.md +43 -2
- package/skills/yui-worker/SKILL.md +3 -2
- package/dist/web/assets/client/app.js +0 -808
- package/dist/web/assets/client/components.js +0 -477
- package/dist/web/assets/client/detail.js +0 -379
- package/dist/web/assets/client/dock.js +0 -309
- package/dist/web/assets/client/evidence.js +0 -364
- package/dist/web/assets/client/forms.js +0 -230
- package/dist/web/assets/client/i18n.js +0 -1277
- package/dist/web/assets/client/markdown.js +0 -114
- package/dist/web/assets/client/records.js +0 -198
- package/dist/web/assets/client/sections.js +0 -349
- package/dist/web/assets/client/theme.js +0 -71
- package/dist/web/assets/shell.js +0 -161
- package/dist/web/assets/styles/components.js +0 -216
- package/dist/web/assets/styles/views.js +0 -309
- /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
|
-
|
|
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
|
|
96
|
-
|
|
97
|
-
|
|
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) }); },
|