@hasna-internal/kai-host-directory-picker-auto 0.1.1-rc.2
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 +21 -0
- package/README.i18n.yaml +6 -0
- package/README.md +21 -0
- package/README.zh.md +21 -0
- package/lib/index.js +142 -0
- package/lib/invariant.js +20 -0
- package/lib/types/index.d.ts +46 -0
- package/lib/types/invariant.d.ts +16 -0
- package/lib/types/probe.d.ts +21 -0
- package/lib/types/resolve.d.ts +38 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DeepSeek
|
|
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.
|
package/README.i18n.yaml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
|
2
|
+
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
|
+
# after editing either side, bring the other along and re-record with:
|
|
4
|
+
# pnpm run verify-translation-pairing --write packages/host/directory-picker-auto/README.md
|
|
5
|
+
README.md: fd162e0652c7eb43de111323e93e0be936d39e2f
|
|
6
|
+
README.zh.md: da30e8008da5eb1741740f083c9bed5049d7b7bf
|
package/README.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# @hasna-internal/kai-host-directory-picker-auto
|
|
2
|
+
|
|
3
|
+
English | [中文](README.zh.md)
|
|
4
|
+
|
|
5
|
+
The **adaptive chooser** of the [directory-picker seam](../directory-picker/README.md): a node-half-only plugin that resolves the host's situation once at boot and mounts the matching dual-face backend — [`-native`](../directory-picker-native/README.md) or [`-browse`](../directory-picker-browse/README.md) — as a real Loader entry in the in-memory root tree (never persisted to a config file; the root tree's `write()` is a no-op). Because the backend arrives as an ordinary entry, its browser half is discovered by the client module table exactly as a config-row's would be, so the seam's one-row-swaps-both-faces invariant holds for the resolved choice. Unloading the chooser removes the entry again, unloading both faces with it.
|
|
6
|
+
|
|
7
|
+
Resolution is one pure boot-time sample (`resolveDirectoryPickerBackend`), exported for reuse. `native` requires every signal that the operator can see the host display and the native backend can serve it: a loopback-only bind (read from the injected `webServer`; an all-interfaces bind admits remote browsers no OS chooser can reach), no SSH launch (`SSH_CONNECTION`/`SSH_TTY` unset or blank — under SSH port-forwarding the chooser would open on the unattended server), and a servable display session — assumed on darwin/win32; on linux `DISPLAY`/`WAYLAND_DISPLAY` plus a zenity or kdialog binary on `PATH` (the probe is one more boot-time fact); never on any other platform, since the native backend drives exactly darwin/win32/linux. Anything ambiguous resolves to `browse`, which works everywhere. The sample happens exactly once per boot so the mounted capability stays stable for the service lifetime, as the seam requires. Pinning an interaction is not a config field here — compose the `-native` or `-browse` row directly instead of this one, the seam's documented swap point; mounting the chooser **and** a backend row together fails loud (duplicate `directoryPicker` service, duplicate client flow in the `single` holes).
|
|
8
|
+
|
|
9
|
+
## Model Experience
|
|
10
|
+
|
|
11
|
+
None, as the chooser only composes the GUI host's directory selection; nothing here reaches a model request.
|
|
12
|
+
|
|
13
|
+
#### KV Cache effect
|
|
14
|
+
|
|
15
|
+
None; this package neither assembles nor sends a provider request.
|
|
16
|
+
|
|
17
|
+
## Known Limitations and Deferred Work
|
|
18
|
+
|
|
19
|
+
- **Detection infers operator location from launch context, which no launch-side signal can prove** — a tmux session detached from its SSH launch loses the `SSH_*` markers; a Darwin process outside an Aqua session still counts as displayed; and a workstation-local launch later reached through `ssh -L` arrives from `127.0.0.1`, resolves `native`, and opens the chooser on the unattended workstation. A wrong `native` choice degrades to the backend's existing retryable failure dialog, and composing `-browse` directly selects the safe interaction for such deployments.
|
|
20
|
+
- **The Linux chooser probe reads `PATH` only** — a zenity/kdialog reachable some other way (shell alias, non-PATH install) still resolves `browse`; installing either binary on `PATH` restores `native` eligibility at the next boot.
|
|
21
|
+
- **Boot-time only** — one resolution serves every client of the boot; per-connection adaptivity (native for a local browser, browse for a remote one, same server) would need a per-client capability and the wire advertisement the seam deliberately deleted, and waits for a deployment that serves both at once.
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# @hasna-internal/kai-host-directory-picker-auto
|
|
2
|
+
|
|
3
|
+
[English](README.md) | 中文
|
|
4
|
+
|
|
5
|
+
[目录选择 seam](../directory-picker/README.zh.md) 的**自适应选择器**:一个只有 node 半侧的插件,在启动时一次性判定宿主处境,并把匹配的双面后端——[`-native`](../directory-picker-native/README.zh.md) 或 [`-browse`](../directory-picker-browse/README.zh.md)——作为真实的 Loader 条目挂进内存根树(绝不持久化到配置文件;根树的 `write()` 是 no-op)。由于后端以普通条目的形式到达,其 browser half 被 client 模块表发现的方式与配置行完全相同,因此对判定出的选择,seam 的“一行同时换两面”不变式依然成立。卸载该选择器会再次移除该条目,连同两面一起卸载。
|
|
6
|
+
|
|
7
|
+
判定是一次纯函数的启动时采样(`resolveDirectoryPickerBackend`),已导出供复用。`native` 要求“操作者看得到宿主屏幕、且 native 后端能服务它”的全部信号:仅回环的绑定(从注入的 `webServer` 读取;全网卡绑定会接入任何 OS 选择器都触及不到的远程浏览器);非 SSH 启动(`SSH_CONNECTION`/`SSH_TTY` 未设置或为空——SSH 端口转发下选择器会弹在无人值守的服务器上);以及可服务的显示会话——darwin/win32 上视为存在;linux 上要求 `DISPLAY`/`WAYLAND_DISPLAY`,外加 `PATH` 上有 zenity 或 kdialog 二进制(该探查是又一项启动时事实);其余任何平台上都不成立,因为 native 后端驱动的平台恰为 darwin/win32/linux。任何含糊情形都判定为处处可用的 `browse`。采样每次启动恰好发生一次,因此挂载的能力在服务生命周期内保持稳定,符合 seam 的要求。固定某种交互在这里不是配置字段——直接组合 `-native` 或 `-browse` 行来替代本行,那才是 seam 文档化的切换点;同时挂载选择器**和**某个后端行会明确报错(重复的 `directoryPicker` 服务、`single` 类 slot 中的重复 client 流程)。
|
|
8
|
+
|
|
9
|
+
## 模型体验
|
|
10
|
+
|
|
11
|
+
无。该选择器仅组合 GUI 宿主的目录选择;这里没有任何内容进入模型请求。
|
|
12
|
+
|
|
13
|
+
#### KV Cache 影响
|
|
14
|
+
|
|
15
|
+
无;该包既不组装也不发送提供方请求。
|
|
16
|
+
|
|
17
|
+
## 已知限制与暂缓事项
|
|
18
|
+
|
|
19
|
+
- **探测是从启动上下文推断操作者位置,而任何启动侧信号都无法证明这一点**——从 SSH 启动中脱离的 tmux 会话会丢失 `SSH_*` 标记;Aqua 会话之外的 Darwin 进程仍被算作有显示;在工作站本地启动、之后经 `ssh -L` 访问时,请求会从 `127.0.0.1` 到达,系统会判定 `native`,并把选择器弹在无人值守的工作站上。错误的 `native` 选择会退化为后端既有的可重试失败对话框,而对这类部署,直接组合 `-browse` 即选择安全的交互。
|
|
20
|
+
- **Linux 选择器探查只读 `PATH`**——以其他途径可用的 zenity/kdialog(shell 别名、未装在 PATH 上)仍判定为 `browse`;把任一二进制装到 `PATH` 上,下次启动即恢复 `native` 资格。
|
|
21
|
+
- **仅在启动时判定**——一次判定服务本次启动的所有客户端;按连接自适应(同一台服务器,本地浏览器用 native、远程浏览器用 browse)需要按客户端的能力对象以及 seam 有意删除的协议通告,等到出现同时服务两种形态的部署再做。
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { accessSync, constants } from "node:fs";
|
|
2
|
+
import { delimiter, join } from "node:path";
|
|
3
|
+
//#region lib/types/probe.js
|
|
4
|
+
/**
|
|
5
|
+
* PATH probe for the native backend's Linux chooser binaries: one boot-time
|
|
6
|
+
* sampled fact for the resolver, so an attended Linux host without
|
|
7
|
+
* zenity/kdialog keeps the working `browse` interaction instead of a backend
|
|
8
|
+
* whose every pick fails.
|
|
9
|
+
* @module @hasna-internal/kai-host-directory-picker-auto/probe
|
|
10
|
+
*/
|
|
11
|
+
/** The chooser binaries the native backend can drive on Linux (zenity, KDialog fallback). */
|
|
12
|
+
const LINUX_CHOOSER_BINARIES = ["zenity", "kdialog"];
|
|
13
|
+
/**
|
|
14
|
+
* Whether the current process may execute the candidate path.
|
|
15
|
+
* @param candidate - absolute or PATH-joined file path.
|
|
16
|
+
* @returns true only for an existing executable file.
|
|
17
|
+
*/
|
|
18
|
+
function canExecute(candidate) {
|
|
19
|
+
try {
|
|
20
|
+
accessSync(candidate, constants.X_OK);
|
|
21
|
+
} catch {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Scan a PATH value for one of the native backend's Linux chooser binaries.
|
|
28
|
+
* @param pathValue - the `PATH` environment value (absent or empty scans nothing).
|
|
29
|
+
* @param isExecutable - executability predicate ({@link canExecute} in production; injected for deterministic tests).
|
|
30
|
+
* @returns whether any PATH directory holds an executable chooser binary.
|
|
31
|
+
*/
|
|
32
|
+
function hasLinuxChooserBinary(pathValue, isExecutable) {
|
|
33
|
+
for (const dir of (pathValue ?? "").split(delimiter)) {
|
|
34
|
+
if (dir === "") continue;
|
|
35
|
+
for (const name of LINUX_CHOOSER_BINARIES) if (isExecutable(join(dir, name))) return true;
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region lib/types/resolve.js
|
|
41
|
+
/**
|
|
42
|
+
* Boot-time backend resolution for the adaptive directory-picker composition:
|
|
43
|
+
* one pure decision from sampled host facts to a concrete backend kind. The
|
|
44
|
+
* caller samples exactly once per boot, so the mounted capability stays
|
|
45
|
+
* stable for the service lifetime as the seam requires.
|
|
46
|
+
* @module @hasna-internal/kai-host-directory-picker-auto/resolve
|
|
47
|
+
*/
|
|
48
|
+
/** An env value counts only when set and non-blank (an empty export is "unset" by shell convention). */
|
|
49
|
+
const present = (value) => value !== void 0 && value !== "";
|
|
50
|
+
/**
|
|
51
|
+
* Resolve which backend serves this boot. `native` requires every signal that
|
|
52
|
+
* the operator can see the host display and the native backend can serve it:
|
|
53
|
+
* a loopback-only bind (an all-interfaces bind admits remote browsers no OS
|
|
54
|
+
* chooser can reach), no SSH launch (under SSH port-forwarding the chooser
|
|
55
|
+
* would open on the unattended server), and a servable display session —
|
|
56
|
+
* assumed on darwin/win32, requiring `DISPLAY`/`WAYLAND_DISPLAY` plus a
|
|
57
|
+
* chooser binary on linux, and never true elsewhere (the native backend
|
|
58
|
+
* drives exactly darwin/win32/linux). Anything ambiguous resolves to
|
|
59
|
+
* `browse`, which works everywhere.
|
|
60
|
+
* @param facts - the sampled host facts.
|
|
61
|
+
* @returns the backend kind to mount.
|
|
62
|
+
*/
|
|
63
|
+
function resolveDirectoryPickerBackend(facts) {
|
|
64
|
+
if (facts.bindHost !== "127.0.0.1") return "browse";
|
|
65
|
+
if (present(facts.env.SSH_CONNECTION) || present(facts.env.SSH_TTY)) return "browse";
|
|
66
|
+
if (facts.platform === "darwin" || facts.platform === "win32") return "native";
|
|
67
|
+
if (facts.platform !== "linux" || !facts.linuxChooser) return "browse";
|
|
68
|
+
return present(facts.env.DISPLAY) || present(facts.env.WAYLAND_DISPLAY) ? "native" : "browse";
|
|
69
|
+
}
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region lib/types/index.js
|
|
72
|
+
/**
|
|
73
|
+
* Adaptive chooser of the directory-picker seam: resolves the host's
|
|
74
|
+
* situation once at boot (bind host, SSH launch, display session, Linux
|
|
75
|
+
* chooser binary) and mounts the matching interaction — `native` or `browse`
|
|
76
|
+
* — as real Loader entries in the in-memory root tree. Each interaction is a
|
|
77
|
+
* pair: the Host backend serving the seam capability and the client surface
|
|
78
|
+
* occupying ui-workspace's directory-flow holes. Both arrive as ordinary
|
|
79
|
+
* entries, so the surface is discovered exactly as a config-row's would be
|
|
80
|
+
* and one resolved choice still swaps both faces; pinning an interaction
|
|
81
|
+
* remains composing that pair directly instead of this row.
|
|
82
|
+
* @module @hasna-internal/kai-host-directory-picker-auto
|
|
83
|
+
*/
|
|
84
|
+
/** Cordis plugin name. */
|
|
85
|
+
const name = "directory-picker-auto";
|
|
86
|
+
/** Required services: the effective bind host (`webServer`) and the entry tree the backend mounts into (`loader`). */
|
|
87
|
+
const inject = ["webServer", "loader"];
|
|
88
|
+
/**
|
|
89
|
+
* Host backend package per resolved kind — fixed composition vocabulary, not a
|
|
90
|
+
* tunable. Exported because the reference is a runtime string the static
|
|
91
|
+
* config gate cannot see in a yml row: `verify-cordis-config` requires every
|
|
92
|
+
* app composing this chooser to declare both values as dependencies.
|
|
93
|
+
*/
|
|
94
|
+
const BACKEND_PACKAGES = {
|
|
95
|
+
native: "@hasna-internal/kai-host-directory-picker-native",
|
|
96
|
+
browse: "@hasna-internal/kai-host-directory-picker-browse"
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Client surface package per resolved kind, mounted with its backend so one
|
|
100
|
+
* resolved interaction still composes both faces. Declared as dependencies by
|
|
101
|
+
* every composing app for the same reason as {@link BACKEND_PACKAGES}. Only the
|
|
102
|
+
* specifier is referenced here — the packages belong to the Client program, so
|
|
103
|
+
* no import of them exists on this side and knip needs them ignored for this
|
|
104
|
+
* workspace.
|
|
105
|
+
*/
|
|
106
|
+
const SURFACE_PACKAGES = {
|
|
107
|
+
native: "@hasna-internal/kai-client-ui-directory-picker-native",
|
|
108
|
+
browse: "@hasna-internal/kai-client-ui-directory-picker-browse"
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Resolve the interaction from one boot-time sample and mount its backend and
|
|
112
|
+
* surface as Loader entries; the effect's disposer removes both entries and
|
|
113
|
+
* joins their fibers' teardown, so unloading this plugin returns only after
|
|
114
|
+
* both faces of the mounted interaction (and their dependents) quiesced.
|
|
115
|
+
* @param ctx - cordis context carrying the injected `webServer` and `loader`.
|
|
116
|
+
*/
|
|
117
|
+
async function apply(ctx) {
|
|
118
|
+
const backend = resolveDirectoryPickerBackend({
|
|
119
|
+
bindHost: ctx.webServer.host,
|
|
120
|
+
platform: process.platform,
|
|
121
|
+
env: process.env,
|
|
122
|
+
linuxChooser: hasLinuxChooserBinary(process.env.PATH, canExecute)
|
|
123
|
+
});
|
|
124
|
+
await ctx.effect(async () => {
|
|
125
|
+
const ids = [];
|
|
126
|
+
const unmount = async () => {
|
|
127
|
+
for (const id of [...ids].reverse()) {
|
|
128
|
+
if (ctx.loader.store[id] === void 0) continue;
|
|
129
|
+
await ctx.loader.remove(id);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
try {
|
|
133
|
+
for (const name of [BACKEND_PACKAGES[backend], SURFACE_PACKAGES[backend]]) ids.push(await ctx.loader.create({ name }));
|
|
134
|
+
} catch (cause) {
|
|
135
|
+
await unmount();
|
|
136
|
+
throw cause;
|
|
137
|
+
}
|
|
138
|
+
return unmount;
|
|
139
|
+
}, "directory-picker-auto: interaction entries");
|
|
140
|
+
}
|
|
141
|
+
//#endregion
|
|
142
|
+
export { BACKEND_PACKAGES, SURFACE_PACKAGES, apply, canExecute, hasLinuxChooserBinary, inject, name, resolveDirectoryPickerBackend };
|
package/lib/invariant.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region lib/types/invariant.js
|
|
2
|
+
/**
|
|
3
|
+
* Package-owned invariant companion for the adaptive directory-picker chooser.
|
|
4
|
+
* @module @hasna-internal/kai-host-directory-picker-auto/invariant
|
|
5
|
+
*/
|
|
6
|
+
const PACKAGE_NAME = "@hasna-internal/kai-host-directory-picker-auto";
|
|
7
|
+
/** Cordis companion plugin name. */
|
|
8
|
+
const name = "host-directory-picker-auto-invariant";
|
|
9
|
+
/** Service required before the companion can reserve package ownership. */
|
|
10
|
+
const inject = ["invariants"];
|
|
11
|
+
/** No runtime invariant: the sole effect is one boot-time Loader-entry mount owned by the plugin fiber; the store is authoritative. */
|
|
12
|
+
const install = () => {};
|
|
13
|
+
/**
|
|
14
|
+
* Register the adaptive directory-picker invariant companion.
|
|
15
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
16
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
17
|
+
*/
|
|
18
|
+
const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
19
|
+
//#endregion
|
|
20
|
+
export { apply, inject, name };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adaptive chooser of the directory-picker seam: resolves the host's
|
|
3
|
+
* situation once at boot (bind host, SSH launch, display session, Linux
|
|
4
|
+
* chooser binary) and mounts the matching interaction — `native` or `browse`
|
|
5
|
+
* — as real Loader entries in the in-memory root tree. Each interaction is a
|
|
6
|
+
* pair: the Host backend serving the seam capability and the client surface
|
|
7
|
+
* occupying ui-workspace's directory-flow holes. Both arrive as ordinary
|
|
8
|
+
* entries, so the surface is discovered exactly as a config-row's would be
|
|
9
|
+
* and one resolved choice still swaps both faces; pinning an interaction
|
|
10
|
+
* remains composing that pair directly instead of this row.
|
|
11
|
+
* @module @hasna-internal/kai-host-directory-picker-auto
|
|
12
|
+
*/
|
|
13
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
14
|
+
import type { DirectoryPickerBackendKind } from './resolve.ts';
|
|
15
|
+
export { canExecute, hasLinuxChooserBinary } from './probe.ts';
|
|
16
|
+
export type { DirectoryPickerBackendKind, DirectoryPickerEnv, DirectoryPickerHostFacts } from './resolve.ts';
|
|
17
|
+
export { resolveDirectoryPickerBackend } from './resolve.ts';
|
|
18
|
+
/** Cordis plugin name. */
|
|
19
|
+
export declare const name = "directory-picker-auto";
|
|
20
|
+
/** Required services: the effective bind host (`webServer`) and the entry tree the backend mounts into (`loader`). */
|
|
21
|
+
export declare const inject: string[];
|
|
22
|
+
/**
|
|
23
|
+
* Host backend package per resolved kind — fixed composition vocabulary, not a
|
|
24
|
+
* tunable. Exported because the reference is a runtime string the static
|
|
25
|
+
* config gate cannot see in a yml row: `verify-cordis-config` requires every
|
|
26
|
+
* app composing this chooser to declare both values as dependencies.
|
|
27
|
+
*/
|
|
28
|
+
export declare const BACKEND_PACKAGES: Record<DirectoryPickerBackendKind, string>;
|
|
29
|
+
/**
|
|
30
|
+
* Client surface package per resolved kind, mounted with its backend so one
|
|
31
|
+
* resolved interaction still composes both faces. Declared as dependencies by
|
|
32
|
+
* every composing app for the same reason as {@link BACKEND_PACKAGES}. Only the
|
|
33
|
+
* specifier is referenced here — the packages belong to the Client program, so
|
|
34
|
+
* no import of them exists on this side and knip needs them ignored for this
|
|
35
|
+
* workspace.
|
|
36
|
+
*/
|
|
37
|
+
export declare const SURFACE_PACKAGES: Record<DirectoryPickerBackendKind, string>;
|
|
38
|
+
/**
|
|
39
|
+
* Resolve the interaction from one boot-time sample and mount its backend and
|
|
40
|
+
* surface as Loader entries; the effect's disposer removes both entries and
|
|
41
|
+
* joins their fibers' teardown, so unloading this plugin returns only after
|
|
42
|
+
* both faces of the mounted interaction (and their dependents) quiesced.
|
|
43
|
+
* @param ctx - cordis context carrying the injected `webServer` and `loader`.
|
|
44
|
+
*/
|
|
45
|
+
export declare function apply(ctx: Context): Promise<void>;
|
|
46
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-owned invariant companion for the adaptive directory-picker chooser.
|
|
3
|
+
* @module @hasna-internal/kai-host-directory-picker-auto/invariant
|
|
4
|
+
*/
|
|
5
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
6
|
+
/** Cordis companion plugin name. */
|
|
7
|
+
export declare const name = "host-directory-picker-auto-invariant";
|
|
8
|
+
/** Service required before the companion can reserve package ownership. */
|
|
9
|
+
export declare const inject: string[];
|
|
10
|
+
/**
|
|
11
|
+
* Register the adaptive directory-picker invariant companion.
|
|
12
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
13
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
14
|
+
*/
|
|
15
|
+
export declare const apply: (ctx: Context) => Promise<() => void>;
|
|
16
|
+
//# sourceMappingURL=invariant.d.ts.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PATH probe for the native backend's Linux chooser binaries: one boot-time
|
|
3
|
+
* sampled fact for the resolver, so an attended Linux host without
|
|
4
|
+
* zenity/kdialog keeps the working `browse` interaction instead of a backend
|
|
5
|
+
* whose every pick fails.
|
|
6
|
+
* @module @hasna-internal/kai-host-directory-picker-auto/probe
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Whether the current process may execute the candidate path.
|
|
10
|
+
* @param candidate - absolute or PATH-joined file path.
|
|
11
|
+
* @returns true only for an existing executable file.
|
|
12
|
+
*/
|
|
13
|
+
export declare function canExecute(candidate: string): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Scan a PATH value for one of the native backend's Linux chooser binaries.
|
|
16
|
+
* @param pathValue - the `PATH` environment value (absent or empty scans nothing).
|
|
17
|
+
* @param isExecutable - executability predicate ({@link canExecute} in production; injected for deterministic tests).
|
|
18
|
+
* @returns whether any PATH directory holds an executable chooser binary.
|
|
19
|
+
*/
|
|
20
|
+
export declare function hasLinuxChooserBinary(pathValue: string | undefined, isExecutable: (candidate: string) => boolean): boolean;
|
|
21
|
+
//# sourceMappingURL=probe.d.ts.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Boot-time backend resolution for the adaptive directory-picker composition:
|
|
3
|
+
* one pure decision from sampled host facts to a concrete backend kind. The
|
|
4
|
+
* caller samples exactly once per boot, so the mounted capability stays
|
|
5
|
+
* stable for the service lifetime as the seam requires.
|
|
6
|
+
* @module @hasna-internal/kai-host-directory-picker-auto/resolve
|
|
7
|
+
*/
|
|
8
|
+
import type { Config as HttpServerConfig } from '@hasna-internal/kai-host-webserver';
|
|
9
|
+
/** Concrete interaction backend the resolver chooses between. */
|
|
10
|
+
export type DirectoryPickerBackendKind = 'native' | 'browse';
|
|
11
|
+
/** Environment keys the resolution reads (a `process.env` subset). */
|
|
12
|
+
export type DirectoryPickerEnv = Readonly<Partial<Record<'SSH_CONNECTION' | 'SSH_TTY' | 'DISPLAY' | 'WAYLAND_DISPLAY', string>>>;
|
|
13
|
+
/** Host facts the backend choice is a pure function of, sampled once at boot. */
|
|
14
|
+
export interface DirectoryPickerHostFacts {
|
|
15
|
+
/** Effective webserver bind host (the schema's closed loopback/all-interfaces union). */
|
|
16
|
+
bindHost: HttpServerConfig['host'];
|
|
17
|
+
/** Host process platform. */
|
|
18
|
+
platform: NodeJS.Platform;
|
|
19
|
+
/** Environment sample; SSH marks a remote operator, DISPLAY/WAYLAND_DISPLAY a Linux display. */
|
|
20
|
+
env: DirectoryPickerEnv;
|
|
21
|
+
/** Whether a Linux chooser binary the native backend can drive (zenity/kdialog) is on PATH; consulted only when `platform` is linux. */
|
|
22
|
+
linuxChooser: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Resolve which backend serves this boot. `native` requires every signal that
|
|
26
|
+
* the operator can see the host display and the native backend can serve it:
|
|
27
|
+
* a loopback-only bind (an all-interfaces bind admits remote browsers no OS
|
|
28
|
+
* chooser can reach), no SSH launch (under SSH port-forwarding the chooser
|
|
29
|
+
* would open on the unattended server), and a servable display session —
|
|
30
|
+
* assumed on darwin/win32, requiring `DISPLAY`/`WAYLAND_DISPLAY` plus a
|
|
31
|
+
* chooser binary on linux, and never true elsewhere (the native backend
|
|
32
|
+
* drives exactly darwin/win32/linux). Anything ambiguous resolves to
|
|
33
|
+
* `browse`, which works everywhere.
|
|
34
|
+
* @param facts - the sampled host facts.
|
|
35
|
+
* @returns the backend kind to mount.
|
|
36
|
+
*/
|
|
37
|
+
export declare function resolveDirectoryPickerBackend(facts: DirectoryPickerHostFacts): DirectoryPickerBackendKind;
|
|
38
|
+
//# sourceMappingURL=resolve.d.ts.map
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hasna-internal/kai-host-directory-picker-auto",
|
|
3
|
+
"description": "Adaptive chooser of the directory-picker seam: resolves the host situation at boot and mounts the native or browse backend for the DeepSeek Harness web GUI host",
|
|
4
|
+
"version": "0.1.1-rc.2",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/deepseek-ai/deepseek-harness.git",
|
|
11
|
+
"directory": "packages/host/directory-picker-auto"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "lib/index.js",
|
|
15
|
+
"types": "lib/types/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./lib/types/index.d.ts",
|
|
19
|
+
"default": "./lib/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./invariant": {
|
|
22
|
+
"types": "./lib/types/invariant.d.ts",
|
|
23
|
+
"default": "./lib/invariant.js"
|
|
24
|
+
},
|
|
25
|
+
"./src/*": "./src/*",
|
|
26
|
+
"./package.json": "./package.json"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"lib/index.js",
|
|
30
|
+
"lib/invariant.js",
|
|
31
|
+
"lib/types/**/*.d.ts"
|
|
32
|
+
],
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@deepseek-ai/cordis-plugin-loader": "^1.0.2",
|
|
36
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
37
|
+
"@hasna-internal/kai-host-directory-picker-browse": "^0.1.1-rc.2",
|
|
38
|
+
"@hasna-internal/kai-client-ui-directory-picker-native": "^0.1.1-rc.2",
|
|
39
|
+
"@hasna-internal/kai-client-ui-directory-picker-browse": "^0.1.1-rc.2",
|
|
40
|
+
"@hasna-internal/kai-host-directory-picker-native": "^0.1.1-rc.2",
|
|
41
|
+
"@hasna-internal/kai-host-webserver": "^0.1.1-rc.2",
|
|
42
|
+
"@hasna-internal/kai-invariants": "^0.1.1-rc.2"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@deepseek-ai/cordis-plugin-loader": "^1.0.2",
|
|
46
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
47
|
+
"@deepseek-ai/cordis-plugin-include": "^1.0.6",
|
|
48
|
+
"@hasna-internal/kai-host-directory-picker": "^0.1.1-rc.2",
|
|
49
|
+
"@hasna-internal/kai-client-ui-directory-picker-native": "^0.1.1-rc.2",
|
|
50
|
+
"@hasna-internal/kai-host-directory-picker-browse": "^0.1.1-rc.2",
|
|
51
|
+
"@hasna-internal/kai-host-directory-picker-native": "^0.1.1-rc.2",
|
|
52
|
+
"@hasna-internal/kai-host-webserver": "^0.1.1-rc.2",
|
|
53
|
+
"@hasna-internal/kai-invariants": "^0.1.1-rc.2",
|
|
54
|
+
"@hasna-internal/kai-client-ui-directory-picker-browse": "^0.1.1-rc.2"
|
|
55
|
+
}
|
|
56
|
+
}
|