@qilin-agent/client-ui-settings-unarchive-sessions 0.0.0-stage → 3.1.4

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 kkutysllb
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,52 @@
1
+ # Bilingual-pair consistency record for README.md (docs/i18n/README.md): per heading
2
+ # section, a hash of its English and Chinese blocks outside code blocks and generated regions.
3
+ # After editing either side, bring the other along and re-record with:
4
+ # pnpm run verify-translation-pairing --write packages/client/ui-settings-unarchive-sessions/README.md
5
+ /:
6
+ en: cf17e23609461ff5
7
+ zh: d9bf8dec044aec4b
8
+ /qilin-agent-client-ui-settings-unarchive-sessions:
9
+ en: 825d1923cf600d31
10
+ zh: b7279c8f3adb8d63
11
+ /qilin-agent-client-ui-settings-unarchive-sessions/summary:
12
+ en: 8c95a9f635f0482e
13
+ zh: 93c557a88f421637
14
+ /qilin-agent-client-ui-settings-unarchive-sessions/table-of-contents:
15
+ en: d152484eb41ac6b4
16
+ zh: 09388d293f9be9cb
17
+ /qilin-agent-client-ui-settings-unarchive-sessions/use-this-package:
18
+ en: cc804295d917d25d
19
+ zh: 7080fa8e0bac79f5
20
+ /qilin-agent-client-ui-settings-unarchive-sessions/use-this-package/reading-a-row:
21
+ en: 5445c5c721b8db17
22
+ zh: 167ccf94c562ec95
23
+ /qilin-agent-client-ui-settings-unarchive-sessions/use-this-package/restoring-a-session:
24
+ en: 00960eb756b7e659
25
+ zh: edcd2d869ec61f49
26
+ /qilin-agent-client-ui-settings-unarchive-sessions/understand-the-implementation:
27
+ en: 3f8be000388c56e3
28
+ zh: 30edbe6915f5198c
29
+ /qilin-agent-client-ui-settings-unarchive-sessions/understand-the-implementation/registration-and-data-sources:
30
+ en: 797fe2512150ef8f
31
+ zh: 26c26ebebd288527
32
+ /qilin-agent-client-ui-settings-unarchive-sessions/understand-the-implementation/row-derivation:
33
+ en: b1085dd5b11f6493
34
+ zh: 7ab004a94b29f34c
35
+ /qilin-agent-client-ui-settings-unarchive-sessions/understand-the-implementation/source-map:
36
+ en: 282c196c6771ed5b
37
+ zh: 44c0795cfb20100d
38
+ /qilin-agent-client-ui-settings-unarchive-sessions/further-exploration:
39
+ en: 912d4348dff075c6
40
+ zh: 31cd0904b3f2f07a
41
+ /qilin-agent-client-ui-settings-unarchive-sessions/model-experience:
42
+ en: 3120df665299c634
43
+ zh: 1d9f365d091d0d2a
44
+ /qilin-agent-client-ui-settings-unarchive-sessions/model-experience/kv-cache-effect:
45
+ en: ca75c51c89c2c9b0
46
+ zh: de54f3467ef3b9be
47
+ /qilin-agent-client-ui-settings-unarchive-sessions/known-limitations-and-deferred-work:
48
+ en: a5e85bc8f04a6f95
49
+ zh: 096b2fb4c52e4e43
50
+ /qilin-agent-client-ui-settings-unarchive-sessions/known-limitations-and-deferred-work/dev-note:
51
+ en: e67f633dc6fe7773
52
+ zh: 3bb0c20c93f16f98
package/README.md CHANGED
@@ -1,3 +1,110 @@
1
- # Temporary Holding Version
1
+ ---
2
+ description: "Archived-session Settings page for the qilin web client: the registry-global archive set as a searchable list with one Unarchive action per row."
3
+ kind: "package-reference"
4
+ ---
2
5
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
6
+ # @qilin-agent/client-ui-settings-unarchive-sessions
7
+
8
+ English | [中文](README.zh.md)
9
+
10
+ ## Summary
11
+
12
+ The **Archived sessions** Settings page is the restore point for sessions hidden from Workspace navigation. It lists each archived session with the Workspace that owns it and its last activity, newest archive first, and offers one Unarchive action per row. A search box filters the list by session title or Workspace name. Rows come from the archive set joined with the loaded Session summaries, so an archive entry whose session record is gone has no row and no action. Every restore goes through the shared Workspace command.
13
+
14
+ ## Table of Contents
15
+
16
+ - [Use this package](#use-this-package)
17
+ - [Understand the implementation](#understand-the-implementation)
18
+ - [Further Exploration](#further-exploration)
19
+ - [Model Experience](#model-experience)
20
+ - [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
21
+ - [Dev Note](#dev-note)
22
+
23
+ -----
24
+
25
+ <a id="use-this-package"></a>
26
+ ## Use this package
27
+
28
+ Open Settings and select **Archived sessions** to see the sessions currently hidden from every grouping surface. Mount `@qilin-agent/client-ui-settings-unarchive-sessions` in a Web composition that already provides the settings shell, the Workspace service, and the Session list; the page registers its own navigation entry and needs no configuration.
29
+
30
+ ### Reading a row
31
+
32
+ Each row shows the session's display title, the title of the Workspace that accounts for it or the ungrouped label, and its last activity as a compact relative time. The page lists the most recently archived session first, the reverse of the durable archive order. The page waits for the Session list before rendering rows; while that list loads it shows a reading status instead of an empty archive. An empty archive, an archive whose entries have no loaded Session to restore, and a query matching no row report three different messages, so neither a search nor an unaddressable entry ever looks like an empty archive.
33
+
34
+ ### Restoring a session
35
+
36
+ Unarchive restores the session to its recorded position under its Workspace, or to the ungrouped sessions when it belongs to none, and the row disappears from the page. The action calls `ctx.uiWorkspace.unarchiveSession`, whose echoed archive set updates every surface that filters on it, so the session reappears in the sidebar and search as well. A rejected call is logged as a console diagnostic and leaves the row in place for another attempt.
37
+
38
+ -----
39
+
40
+ <a id="understand-the-implementation"></a>
41
+ ## Understand the implementation
42
+
43
+ <details>
44
+ <summary>Implementation internals — click to expand</summary>
45
+
46
+ The page is one localized `settings.section` contribution with id `archived-sessions`; the Settings shell owns the navigation entry, the modal, and the mounted section, so none of that chrome lives here.
47
+
48
+ ### Registration and data sources
49
+
50
+ `apply()` registers the locale namespace, binds it, and uses `ctx.slots.inject()` to contribute the section, so a late or restored slot declaration still reaches it. The page reads `state.archivedSessionIds` and `state.items` from `useWorkspaces` and the Session summaries from `useSessions`; it owns no store and no transport, and its only write is the injected `unarchive` callback that the registration closes over `ctx.uiWorkspace.unarchiveSession`.
51
+
52
+ ### Row derivation
53
+
54
+ Rows are derived from the archive set joined with the loaded summaries: a member with no summary produces no row, which is why a session deleted outside the Workspace registry leaves no unarchive action behind. Workspace ownership is read from each Workspace's `sessionIds`; a member outside every Workspace renders with the ungrouped label. Search normalizes the query once and matches it against the row title and Workspace label.
55
+
56
+ ### Source map
57
+
58
+ | File | Role |
59
+ |---|---|
60
+ | [`src/index.ts`](src/index.ts) | Host loader entry: the page is browser-only, so the plugin body is empty |
61
+ | [`src/client/index.ts`](src/client/index.ts) | Browser plugin: locale namespace, section registration, injected Unarchive operation |
62
+ | [`src/client/ArchivedSessionsSection.tsx`](src/client/ArchivedSessionsSection.tsx) | The page component: row derivation, search, per-row Unarchive |
63
+ | [`src/client/locales.ts`](src/client/locales.ts) | Chinese and English dictionaries for every visible and accessible string |
64
+ | [`src/client/ArchivedSessionsSection.module.css`](src/client/ArchivedSessionsSection.module.css) | Page styles |
65
+
66
+ </details>
67
+
68
+ -----
69
+
70
+ <a id="further-exploration"></a>
71
+ ## Further Exploration
72
+
73
+ These pages cover the settings surface that hosts the page, the archive write behind it, and the state it renders.
74
+
75
+ - [ui-settings](../ui-settings/README.md) — the domain base declaring `settings.section` and the namespace scope service.
76
+ - [ui-settings-general](../ui-settings-general/README.md) — the Settings shell that renders the navigation and mounts the section.
77
+ - [ui-workspace](../ui-workspace/README.md) — the sidebar browser whose Session rows archive, and the `ctx.uiWorkspace` service this page restores through.
78
+ - [Workspace Controller](../../api/workspace-controller/README.md) — the `workspace.unarchiveSession` Remote and the Client model that owns the archive set.
79
+ - [Workspace subsystem](../../../docs/subsystems/workspace.md) — the durable archive set, its domain field, and the registry operation behind a restore.
80
+
81
+ -----
82
+
83
+ <a id="model-experience"></a>
84
+ ## Model Experience
85
+
86
+ None, as the package is a browser-side UI plugin layer that registers nothing model-facing.
87
+
88
+ #### KV Cache effect
89
+
90
+ None; this package neither assembles nor sends a provider request.
91
+
92
+ ## Known Limitations and Deferred Work
93
+
94
+ <a id="known-limitations-and-deferred-work"></a>
95
+
96
+
97
+ These limits define which archived sessions this page can restore; they are current package constraints.
98
+
99
+ - **Archived sessions without a loaded summary are unaddressable** — the page derives its rows by joining the archive set with the Session list, so a member the list does not carry has no row and no Unarchive action even though the archive set still holds it; a set whose members are all in that state reports itself as unrestorable rather than empty.
100
+ - **The page lists sessions only; it offers no session deletion** — archives are reversible through this page, while deleting a session record remains a separate capability.
101
+
102
+ <a id="dev-note"></a>
103
+ ### Dev Note
104
+
105
+ <details>
106
+ <summary>Working context for maintainers — click to expand</summary>
107
+
108
+ None.
109
+
110
+ </details>
package/README.zh.md ADDED
@@ -0,0 +1,110 @@
1
+ ---
2
+ description: "qilin Web 客户端的已归档会话设置页:把注册表全局归档集合呈现为可搜索列表,每行提供一个取消归档操作。"
3
+ kind: "package-reference"
4
+ ---
5
+
6
+ # @qilin-agent/client-ui-settings-unarchive-sessions
7
+
8
+ [English](README.md) | 中文
9
+
10
+ ## 概述
11
+
12
+ **已归档会话**设置页是从 Workspace 导航中隐藏的会话的恢复入口。它按归档时间由新到旧列出每个已归档会话,并显示其所属 Workspace 与最近活动时间,每行提供一个取消归档操作。搜索框按会话标题或 Workspace 名称过滤列表。行由归档集合与已加载的 Session 摘要合并而来,因此会话记录已不存在的归档条目既没有行也没有操作。每次恢复都经由共享的 Workspace 命令。
13
+
14
+ ## 目录
15
+
16
+ - [使用本包](#use-this-package)
17
+ - [理解实现](#understand-the-implementation)
18
+ - [进一步探索](#further-exploration)
19
+ - [模型体验](#model-experience)
20
+ - [已知限制与延期工作](#known-limitations-and-deferred-work)
21
+ - [开发备注](#dev-note)
22
+
23
+ -----
24
+
25
+ <a id="use-this-package"></a>
26
+ ## 使用本包
27
+
28
+ 打开设置并选择**已归档会话**,即可看到当前从所有分组视图中隐藏的会话。在已提供设置外壳、Workspace 服务与 Session 列表的 Web 组合中挂载 `@qilin-agent/client-ui-settings-unarchive-sessions`;该页面注册自己的导航条目,无需配置。
29
+
30
+ ### 阅读一行
31
+
32
+ 每行显示会话的显示标题、为其记账的 Workspace 标题或未分组标签,以及以紧凑相对时间表示的最近活动。页面把最近归档的会话排在前面,与持久归档顺序相反。页面会先等待 Session 列表再渲染行;列表加载期间显示读取状态,而不是空归档。空归档、归档条目均无已加载 Session 可恢复、以及查询无匹配分别给出三种提示,因此搜索和不可寻址的条目都不会被误认为归档为空。
33
+
34
+ ### 恢复会话
35
+
36
+ 取消归档会把会话恢复到其 Workspace 下记录的位置;会话不属于任何 Workspace 时则恢复到未分组会话中,该行随即从页面消失。该操作调用 `ctx.uiWorkspace.unarchiveSession`,其回传的完整归档集合会更新所有依据它过滤的界面,因此会话也会重新出现在侧边栏与搜索中。调用被拒绝时会记录一条 console 诊断,并保留该行以便再次尝试。
37
+
38
+ -----
39
+
40
+ <a id="understand-the-implementation"></a>
41
+ ## 理解实现
42
+
43
+ <details>
44
+ <summary>实现细节——点击展开</summary>
45
+
46
+ 页面是 id 为 `archived-sessions` 的一个本地化 `settings.section` 贡献;导航条目、模态框与挂载的分区都归设置外壳所有,不在此包内。
47
+
48
+ ### 注册与数据来源
49
+
50
+ `apply()` 注册并绑定 locale namespace,再用 `ctx.slots.inject()` 贡献该分区,因此延迟声明或恢复声明的 slot 依然能触达它。页面从 `useWorkspaces` 读取 `state.archivedSessionIds` 与 `state.items`,从 `useSessions` 读取 Session 摘要;它不持有 store 也不持有 transport,唯一的写入是注册处以 `ctx.uiWorkspace.unarchiveSession` 闭包注入的 `unarchive` 回调。
51
+
52
+ ### 行的派生
53
+
54
+ 行由归档集合与已加载摘要合并派生:没有摘要的成员不产生行,因此在 Workspace 注册表之外被删除的会话不会留下取消归档操作。Workspace 归属从各 Workspace 的 `sessionIds` 读取;不属于任何 Workspace 的成员以未分组标签渲染。搜索只规范化一次查询,并与行标题和 Workspace 标签匹配。
55
+
56
+ ### 源码地图
57
+
58
+ | 文件 | 职责 |
59
+ |---|---|
60
+ | [`src/index.ts`](src/index.ts) | 宿主 loader 入口:该页面仅供浏览器使用,因此插件体为空 |
61
+ | [`src/client/index.ts`](src/client/index.ts) | 浏览器插件:locale namespace、分区注册、注入的取消归档操作 |
62
+ | [`src/client/ArchivedSessionsSection.tsx`](src/client/ArchivedSessionsSection.tsx) | 页面组件:行的派生、搜索、每行的取消归档 |
63
+ | [`src/client/locales.ts`](src/client/locales.ts) | 全部可见与无障碍字符串的中英文字典 |
64
+ | [`src/client/ArchivedSessionsSection.module.css`](src/client/ArchivedSessionsSection.module.css) | 页面样式 |
65
+
66
+ </details>
67
+
68
+ -----
69
+
70
+ <a id="further-exploration"></a>
71
+ ## 进一步探索
72
+
73
+ 以下页面覆盖承载该页面的设置界面、其背后的归档写入,以及它所渲染的状态。
74
+
75
+ - [ui-settings](../ui-settings/README.zh.md)——声明 `settings.section` 与 namespace scope 服务的领域底座。
76
+ - [ui-settings-general](../ui-settings-general/README.zh.md)——渲染导航并挂载该分区的设置外壳。
77
+ - [ui-workspace](../ui-workspace/README.zh.md)——其 Session 行负责归档的侧边栏浏览器,以及本页面借以恢复的 `ctx.uiWorkspace` 服务。
78
+ - [Workspace Controller](../../api/workspace-controller/README.zh.md)——`workspace.unarchiveSession` Remote 与持有归档集合的 Client model。
79
+ - [Workspace 子系统](../../../docs/subsystems/workspace.zh.md)——持久归档集合、其领域字段,以及恢复背后的注册表操作。
80
+
81
+ -----
82
+
83
+ <a id="model-experience"></a>
84
+ ## 模型体验
85
+
86
+ 无。该包是浏览器端 UI 插件层,不注册任何面向模型的内容。
87
+
88
+ #### KV Cache 影响
89
+
90
+ 无;该包既不组装也不发送提供方请求。
91
+
92
+ ## 已知限制与延期工作
93
+
94
+ <a id="known-limitations-and-deferred-work"></a>
95
+
96
+
97
+ 这些限制界定本页面能够恢复哪些已归档会话;它们是当前包约束。
98
+
99
+ - **已加载摘要缺失的已归档会话无法寻址**:页面通过与 Session 列表合并来派生行,因此列表未携带的成员没有行也没有取消归档操作,尽管归档集合仍持有它;当集合中的成员全部处于该状态时,页面报告无法恢复,而不是报告归档为空。
100
+ - **页面只列出会话,不提供会话删除**:归档可通过本页面恢复,而删除会话记录仍是彼此独立的能力。
101
+
102
+ <a id="dev-note"></a>
103
+ ### 开发备注
104
+
105
+ <details>
106
+ <summary>维护者的工作上下文——点击展开</summary>
107
+
108
+ 无。
109
+
110
+ </details>
package/lib/client.js ADDED
@@ -0,0 +1,216 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "@qilin-agent/client-ui-settings-unarchive-sessions",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ let react_jsx_runtime = require("react/jsx-runtime");
8
+ let react = require("react");
9
+ let _qilin_agent_client_ui_primitives = require("@qilin-agent/client-ui-primitives");
10
+ //#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-settings-unarchive-sessions/src/client/ArchivedSessionsSection.module.css.mjs
11
+ const css = ".qzV--q_section{width:100%;max-width:760px;color:var(--qilin-alias-label-primary);flex-direction:column;gap:12px;display:flex}.qzV--q_status{color:var(--qilin-alias-label-tertiary);margin:0;font-size:13px;line-height:20px}.qzV--q_search{width:100%;color:var(--qilin-alias-label-tertiary);align-items:center;display:flex;position:relative}.qzV--q_search>svg{pointer-events:none;position:absolute;left:12px}.qzV--q_search input{border:.5px solid var(--qilin-alias-border-l2);background:var(--qilin-alias-bg-base);width:100%;height:32px;color:var(--qilin-alias-label-primary);font:inherit;border-radius:8px;padding:0 12px 0 36px}.qzV--q_list{flex-direction:column;gap:2px;margin:0;padding:0;list-style:none;display:flex}.qzV--q_row{border-radius:8px;align-items:center;gap:12px;padding:8px 10px;display:flex}.qzV--q_row:hover{background:var(--qilin-alias-bg-layer-1)}.qzV--q_identity{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.qzV--q_title{text-overflow:ellipsis;white-space:nowrap;font-size:13px;line-height:20px;overflow:hidden}.qzV--q_meta{color:var(--qilin-alias-label-tertiary);font-size:12px;line-height:18px}";
12
+ const tagId = "@qilin-agent/client-ui-settings-unarchive-sessions/ArchivedSessionsSection.module.css";
13
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
14
+ const tag = document.createElement("style");
15
+ tag.dataset.plugin = "@qilin-agent/client-ui-settings-unarchive-sessions";
16
+ tag.dataset.pluginCss = tagId;
17
+ tag.textContent = css;
18
+ document.head.appendChild(tag);
19
+ }
20
+ var ArchivedSessionsSection_module_css_default = {
21
+ "identity": "qzV--q_identity",
22
+ "list": "qzV--q_list",
23
+ "meta": "qzV--q_meta",
24
+ "row": "qzV--q_row",
25
+ "search": "qzV--q_search",
26
+ "section": "qzV--q_section",
27
+ "status": "qzV--q_status",
28
+ "title": "qzV--q_title"
29
+ };
30
+ //#endregion
31
+ //#region lib/types/client/ArchivedSessionsSection.js
32
+ /**
33
+ * Archived-session Settings page: the registry-global archive set joined with
34
+ * the loaded Session summaries, newest archive first, filtered by one search
35
+ * box, with one Unarchive action per row. An archive entry whose Session is
36
+ * gone has no row and no action; the set itself stays host-owned.
37
+ */
38
+ /** Localized compact relative time of one row's last activity. */
39
+ function timeLabel(updatedAt, now, t) {
40
+ const { unit, n } = (0, _qilin_agent_client_ui_primitives.relativeTime)(updatedAt, now);
41
+ return unit === "now" ? t("time.now") : t(`time.${unit}`, { n });
42
+ }
43
+ /** Whether one row matches the normalized query in its title or Workspace label. */
44
+ function matches(row, normalizedQuery) {
45
+ return normalizedQuery.length === 0 || row.title.toLowerCase().includes(normalizedQuery) || row.workspace.toLowerCase().includes(normalizedQuery);
46
+ }
47
+ /**
48
+ * Render the archived-session page.
49
+ * @param props - composed slot props (see {@link ArchivedSessionsSectionProps}).
50
+ * @returns the settings page element tree.
51
+ */
52
+ function ArchivedSessionsSection(props) {
53
+ const { t, unarchive, useSessions, useWorkspaces } = props;
54
+ const sessions = useSessions((state) => state);
55
+ const workspaces = useWorkspaces((state) => state.items);
56
+ const archivedSessionIds = useWorkspaces((state) => state.archivedSessionIds);
57
+ const [query, setQuery] = (0, react.useState)("");
58
+ const ungrouped = t("ungrouped");
59
+ const summaries = sessions.byId;
60
+ const rows = (0, react.useMemo)(() => {
61
+ const owners = /* @__PURE__ */ new Map();
62
+ for (const workspace of workspaces) for (const id of workspace.sessionIds) owners.set(id, workspace.title);
63
+ return [...archivedSessionIds].reverse().flatMap((id) => {
64
+ const summary = summaries[id];
65
+ if (summary === void 0) return [];
66
+ return [{
67
+ id,
68
+ title: summary.displayTitle,
69
+ workspace: owners.get(id) ?? ungrouped,
70
+ updatedAt: summary.updatedAt
71
+ }];
72
+ });
73
+ }, [
74
+ archivedSessionIds,
75
+ workspaces,
76
+ summaries,
77
+ ungrouped
78
+ ]);
79
+ if (sessions.phase !== "ready") return (0, react_jsx_runtime.jsx)("p", {
80
+ className: ArchivedSessionsSection_module_css_default.status,
81
+ children: t("loading")
82
+ });
83
+ const now = Date.now();
84
+ const visible = rows.filter((row) => matches(row, query.trim().toLowerCase()));
85
+ const archived = archivedSessionIds.length > 0;
86
+ return (0, react_jsx_runtime.jsxs)("div", {
87
+ className: ArchivedSessionsSection_module_css_default.section,
88
+ children: [
89
+ (0, react_jsx_runtime.jsxs)("div", {
90
+ className: ArchivedSessionsSection_module_css_default.search,
91
+ children: [(0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconSearchOutline16, { "aria-hidden": "true" }), (0, react_jsx_runtime.jsx)("input", {
92
+ type: "search",
93
+ value: query,
94
+ placeholder: t("search"),
95
+ "aria-label": t("search"),
96
+ onChange: (event) => {
97
+ setQuery(event.currentTarget.value);
98
+ }
99
+ })]
100
+ }),
101
+ !archived ? (0, react_jsx_runtime.jsx)("p", {
102
+ className: ArchivedSessionsSection_module_css_default.status,
103
+ children: t("empty")
104
+ }) : null,
105
+ archived && rows.length === 0 ? (0, react_jsx_runtime.jsx)("p", {
106
+ className: ArchivedSessionsSection_module_css_default.status,
107
+ children: t("unavailable")
108
+ }) : null,
109
+ rows.length > 0 && visible.length === 0 ? (0, react_jsx_runtime.jsx)("p", {
110
+ className: ArchivedSessionsSection_module_css_default.status,
111
+ children: t("emptySearch")
112
+ }) : null,
113
+ visible.length > 0 ? (0, react_jsx_runtime.jsx)("ul", {
114
+ className: ArchivedSessionsSection_module_css_default.list,
115
+ children: visible.map((row) => (0, react_jsx_runtime.jsxs)("li", {
116
+ className: ArchivedSessionsSection_module_css_default.row,
117
+ children: [(0, react_jsx_runtime.jsxs)("span", {
118
+ className: ArchivedSessionsSection_module_css_default.identity,
119
+ children: [(0, react_jsx_runtime.jsx)("span", {
120
+ className: ArchivedSessionsSection_module_css_default.title,
121
+ children: row.title
122
+ }), (0, react_jsx_runtime.jsx)("span", {
123
+ className: ArchivedSessionsSection_module_css_default.meta,
124
+ children: [row.workspace, timeLabel(row.updatedAt, now, t)].join(" · ")
125
+ })]
126
+ }), (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.Button, {
127
+ variant: "outline",
128
+ size: "sm",
129
+ "aria-label": t("unarchiveNamed", { title: row.title }),
130
+ onClick: () => {
131
+ unarchive(row.id).catch((reason) => {
132
+ console.warn("session unarchive rejected:", reason);
133
+ });
134
+ },
135
+ children: t("unarchive")
136
+ })]
137
+ }, row.id))
138
+ }) : null
139
+ ]
140
+ });
141
+ }
142
+ //#endregion
143
+ //#region lib/types/client/locales.js
144
+ /** Copy dictionaries for the archived-session Settings page. */
145
+ /** Simplified Chinese dictionary and key source of truth. */
146
+ const zh = {
147
+ nav: "已归档会话",
148
+ search: "搜索已归档会话",
149
+ loading: "正在读取会话…",
150
+ empty: "暂无已归档会话。",
151
+ unavailable: "这里没有可恢复的已归档会话。",
152
+ emptySearch: "没有匹配的会话。",
153
+ unarchive: "取消归档",
154
+ unarchiveNamed: "取消归档 {title}",
155
+ ungrouped: "未分组",
156
+ "time.now": "刚刚",
157
+ "time.minutes": "{n}分钟",
158
+ "time.hours": "{n}小时",
159
+ "time.days": "{n}天",
160
+ "time.months": "{n}个月",
161
+ "time.years": "{n}年"
162
+ };
163
+ /** English dictionary checked against the Chinese key set. */
164
+ const en = {
165
+ nav: "Archived sessions",
166
+ search: "Search archived sessions",
167
+ loading: "Reading sessions…",
168
+ empty: "No archived sessions.",
169
+ unavailable: "No archived session here can be restored.",
170
+ emptySearch: "No matching sessions.",
171
+ unarchive: "Unarchive",
172
+ unarchiveNamed: "Unarchive {title}",
173
+ ungrouped: "Ungrouped",
174
+ "time.now": "now",
175
+ "time.minutes": "{n}min",
176
+ "time.hours": "{n}h",
177
+ "time.days": "{n}d",
178
+ "time.months": "{n}mo",
179
+ "time.years": "{n}y"
180
+ };
181
+ //#endregion
182
+ //#region lib/types/client/index.js
183
+ /** Archived-session Settings page, browser half. */
184
+ /** Dictionary namespace owned by this plugin. */
185
+ const NS = "settings.archivedSessions";
186
+ /** Services required by the Settings registration and the archive write. */
187
+ const inject = [
188
+ "slots",
189
+ "locale",
190
+ "uiWorkspace"
191
+ ];
192
+ /** Contribute the archived-session page to Settings. */
193
+ function apply(ctx) {
194
+ ctx.effect(() => ctx.locale.register(NS, {
195
+ zh,
196
+ en
197
+ }), "ui-settings-unarchive-sessions: dictionaries");
198
+ const t = ctx.locale.bind(NS);
199
+ const injected = () => ({ unarchive: (sessionId) => ctx.uiWorkspace.unarchiveSession(sessionId) });
200
+ ctx.slots.inject("settings.section", () => ctx.slots.register({
201
+ name: "settings.section",
202
+ id: "archived-sessions",
203
+ order: 25,
204
+ label: () => t("nav"),
205
+ locale: NS,
206
+ inject: injected
207
+ }, ArchivedSessionsSection));
208
+ }
209
+ //#endregion
210
+ exports.apply = apply;
211
+ exports.inject = inject;
212
+ return module.exports;
213
+ }
214
+ });
215
+
216
+ //# sourceMappingURL=client.js.map
package/lib/index.js ADDED
@@ -0,0 +1,6 @@
1
+ //#region lib/types/index.js
2
+ /** Host loader entry for the archived-session page exported from `./client`. */
3
+ /** Host plugin body — the archived-session page is browser-only. */
4
+ function apply() {}
5
+ //#endregion
6
+ export { apply };
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Archived-session Settings page: the registry-global archive set joined with
3
+ * the loaded Session summaries, newest archive first, filtered by one search
4
+ * box, with one Unarchive action per row. An archive entry whose Session is
5
+ * gone has no row and no action; the set itself stays host-owned.
6
+ */
7
+ import { type ReactNode } from 'react';
8
+ import type { InjectFace, PropsLocale, PropsRuntime } from '@qilin-agent/client-ui-slots';
9
+ import type { SessionId } from '@qilin-agent/session/types';
10
+ /** Registration-side face used by the page. */
11
+ export interface ArchivedSessionsSectionInjected {
12
+ /**
13
+ * Restore one archived Session.
14
+ * @param sessionId - Session to unarchive.
15
+ */
16
+ unarchive: (sessionId: SessionId) => Promise<void>;
17
+ }
18
+ /** Full component props assembled by the Settings slot renderer. */
19
+ export type ArchivedSessionsSectionProps = PropsRuntime<'settings.section'> & PropsLocale<'settings.archivedSessions'> & InjectFace<ArchivedSessionsSectionInjected>;
20
+ /**
21
+ * Render the archived-session page.
22
+ * @param props - composed slot props (see {@link ArchivedSessionsSectionProps}).
23
+ * @returns the settings page element tree.
24
+ */
25
+ export declare function ArchivedSessionsSection(props: ArchivedSessionsSectionProps): ReactNode;
26
+ //# sourceMappingURL=ArchivedSessionsSection.d.ts.map
@@ -0,0 +1,16 @@
1
+ /** Archived-session Settings page, browser half. */
2
+ import type { Context as ClientContext } from '@qilin-agent/kylin';
3
+ import { type ArchivedSessionsLocaleKey } from './locales.ts';
4
+ export type { ArchivedSessionsSectionInjected, ArchivedSessionsSectionProps } from './ArchivedSessionsSection.tsx';
5
+ export type { ArchivedSessionsLocaleKey } from './locales.ts';
6
+ declare module '@qilin-agent/client-ui-slots' {
7
+ interface LocaleNamespaceMap {
8
+ /** Archived-session page copy. */
9
+ 'settings.archivedSessions': ArchivedSessionsLocaleKey;
10
+ }
11
+ }
12
+ /** Services required by the Settings registration and the archive write. */
13
+ export declare const inject: string[];
14
+ /** Contribute the archived-session page to Settings. */
15
+ export declare function apply(ctx: ClientContext): void;
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,40 @@
1
+ /** Copy dictionaries for the archived-session Settings page. */
2
+ /** Simplified Chinese dictionary and key source of truth. */
3
+ export declare const zh: {
4
+ nav: string;
5
+ search: string;
6
+ loading: string;
7
+ empty: string;
8
+ unavailable: string;
9
+ emptySearch: string;
10
+ unarchive: string;
11
+ unarchiveNamed: string;
12
+ ungrouped: string;
13
+ 'time.now': string;
14
+ 'time.minutes': string;
15
+ 'time.hours': string;
16
+ 'time.days': string;
17
+ 'time.months': string;
18
+ 'time.years': string;
19
+ };
20
+ /** Archived-session page locale key union. */
21
+ export type ArchivedSessionsLocaleKey = keyof typeof zh;
22
+ /** English dictionary checked against the Chinese key set. */
23
+ export declare const en: {
24
+ nav: string;
25
+ search: string;
26
+ loading: string;
27
+ empty: string;
28
+ unavailable: string;
29
+ emptySearch: string;
30
+ unarchive: string;
31
+ unarchiveNamed: string;
32
+ ungrouped: string;
33
+ 'time.now': string;
34
+ 'time.minutes': string;
35
+ 'time.hours': string;
36
+ 'time.days': string;
37
+ 'time.months': string;
38
+ 'time.years': string;
39
+ };
40
+ //# sourceMappingURL=locales.d.ts.map
@@ -0,0 +1,4 @@
1
+ /** Host loader entry for the archived-session page exported from `./client`. */
2
+ /** Host plugin body — the archived-session page is browser-only. */
3
+ export declare function apply(): void;
4
+ //# sourceMappingURL=index.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,74 @@
1
1
  {
2
2
  "name": "@qilin-agent/client-ui-settings-unarchive-sessions",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "description": "Archived-session settings page: the registry-global archive set with one Unarchive action per row",
4
+ "version": "3.1.4",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/kkutysllb/QiLin.git",
11
+ "directory": "packages/client/ui-settings-unarchive-sessions"
12
+ },
13
+ "engines": {
14
+ "node": "^22.19.0 || >=24.0.0"
15
+ },
16
+ "type": "module",
17
+ "main": "lib/index.js",
18
+ "types": "lib/types/index.d.ts",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./lib/types/index.d.ts",
22
+ "default": "./lib/index.js"
23
+ },
24
+ "./client": {
25
+ "types": "./lib/types/client/index.d.ts",
26
+ "default": "./lib/client.js"
27
+ },
28
+ "./src/*": "./src/*",
29
+ "./package.json": "./package.json"
30
+ },
31
+ "qilin": {
32
+ "client": {
33
+ "inject": [
34
+ "@qilin-agent/client-locale",
35
+ "@qilin-agent/client-ui-renderer",
36
+ "@qilin-agent/client-ui-session",
37
+ "@qilin-agent/client-ui-settings",
38
+ "@qilin-agent/client-ui-workspace"
39
+ ],
40
+ "platform": "web"
41
+ }
42
+ },
43
+ "license": "MIT",
44
+ "peerDependencies": {
45
+ "@qilin-agent/kylin": "~4.0.3"
46
+ },
47
+ "devDependencies": {
48
+ "@testing-library/react": "^16.1.0",
49
+ "@types/react": "~18.3.1",
50
+ "react": "^18.2.0",
51
+ "react-dom": "^18.2.0",
52
+ "@qilin-agent/kylin": "~4.0.3",
53
+ "@qilin-agent/api-session-controller": "3.1.4",
54
+ "@qilin-agent/client-locale": "3.1.4",
55
+ "@qilin-agent/client-ui-primitives": "3.1.4",
56
+ "@qilin-agent/client-test-runtime": "3.1.4",
57
+ "@qilin-agent/api-workspace-controller": "3.1.4",
58
+ "@qilin-agent/client-ui-settings": "3.1.4",
59
+ "@qilin-agent/client-ui-session": "3.1.4",
60
+ "@qilin-agent/client-ui-slots": "3.1.4",
61
+ "@qilin-agent/client-ui-workspace": "3.1.4",
62
+ "@qilin-agent/session": "3.1.4",
63
+ "@qilin-agent/client-ui-renderer": "3.1.4"
64
+ },
65
+ "files": [
66
+ "lib/index.js",
67
+ "lib/client.js",
68
+ "lib/types/**/*.d.ts"
69
+ ],
70
+ "scripts": {
71
+ "bundle": "tsdown",
72
+ "watch": "tsdown --watch"
73
+ }
6
74
  }