@exagone313/dsh-podman 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/card-route.d.ts +2 -2
- package/dist/card-route.js +7 -7
- package/dist/dsh-version.d.ts +7 -1
- package/dist/dsh-version.js +27 -14
- package/dist/dsh-version.test.d.ts +1 -0
- package/dist/dsh-version.test.js +25 -0
- package/dist/generated/version.d.ts +2 -2
- package/dist/generated/version.js +2 -2
- package/dist/index.js +6 -1
- package/dist/workspace-binding.test.js +13 -2
- package/docs/usage.md +12 -0
- package/docs/usage.zh.md +11 -0
- package/package.json +1 -1
package/dist/card-route.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { type CardSnapshot } from "./client/card-protocol.js";
|
|
|
2
2
|
import { type ReasonLocale } from "./approval-reasons.js";
|
|
3
3
|
import { type WorkspaceResolver } from "./workspace-binding.js";
|
|
4
4
|
/** Build the live snapshot the card renders. */
|
|
5
|
-
export declare function cardSnapshot(resolver: WorkspaceResolver, workspaceRegistry: any): Promise<CardSnapshot>;
|
|
5
|
+
export declare function cardSnapshot(resolver: WorkspaceResolver, workspaceRegistry: any, harnessVersion?: string): Promise<CardSnapshot>;
|
|
6
6
|
/**
|
|
7
7
|
* Run one card command, returning the notice to show (usually empty). `ctx` is
|
|
8
8
|
* the settings-injected context, read only for the session locale.
|
|
@@ -13,4 +13,4 @@ export declare function runCommand(_ctx: any, resolver: WorkspaceResolver, works
|
|
|
13
13
|
* harness API path, so the carrier applies its Host/Origin fence and browser
|
|
14
14
|
* authentication before the handler runs.
|
|
15
15
|
*/
|
|
16
|
-
export declare function registerCardRoute(ctx: any, resolver: WorkspaceResolver, workspaceRegistry?: any, readLocale?: () => ReasonLocale): void;
|
|
16
|
+
export declare function registerCardRoute(ctx: any, resolver: WorkspaceResolver, workspaceRegistry?: any, readLocale?: () => ReasonLocale, harnessVersion?: string): void;
|
package/dist/card-route.js
CHANGED
|
@@ -131,7 +131,7 @@ function dshWorkspaceCwd(registry, slug) {
|
|
|
131
131
|
throw new Error(`unknown workspace ${JSON.stringify(slug)}`);
|
|
132
132
|
}
|
|
133
133
|
/** Build the live snapshot the card renders. */
|
|
134
|
-
export async function cardSnapshot(resolver, workspaceRegistry) {
|
|
134
|
+
export async function cardSnapshot(resolver, workspaceRegistry, harnessVersion = dshVersion()) {
|
|
135
135
|
// The handshake RPC is exempt from the orchestrator's version check, so it
|
|
136
136
|
// succeeds even when the rest is refused; an older orchestrator that has no
|
|
137
137
|
// GetVersion yet leaves the version unknown.
|
|
@@ -156,7 +156,7 @@ export async function cardSnapshot(resolver, workspaceRegistry) {
|
|
|
156
156
|
return {
|
|
157
157
|
version: VERSION,
|
|
158
158
|
commit: GIT_COMMIT,
|
|
159
|
-
dshVersion:
|
|
159
|
+
dshVersion: harnessVersion,
|
|
160
160
|
orchestratorVersion,
|
|
161
161
|
versionState: "major-mismatch",
|
|
162
162
|
projectsRoot: resolver.getConfig().projectsRoot,
|
|
@@ -172,7 +172,7 @@ export async function cardSnapshot(resolver, workspaceRegistry) {
|
|
|
172
172
|
return {
|
|
173
173
|
version: VERSION,
|
|
174
174
|
commit: GIT_COMMIT,
|
|
175
|
-
dshVersion:
|
|
175
|
+
dshVersion: harnessVersion,
|
|
176
176
|
orchestratorVersion,
|
|
177
177
|
versionState: pluginVersionState(VERSION, orchestratorVersion),
|
|
178
178
|
projectsRoot: resolver.getConfig().projectsRoot,
|
|
@@ -537,10 +537,10 @@ function normalizeCommand(raw) {
|
|
|
537
537
|
mount: mountField(raw.mount),
|
|
538
538
|
};
|
|
539
539
|
}
|
|
540
|
-
async function handleCardRequest(request, ctx, resolver, workspaceRegistry, readLocale) {
|
|
540
|
+
async function handleCardRequest(request, ctx, resolver, workspaceRegistry, readLocale, harnessVersion) {
|
|
541
541
|
if (request.method === "GET") {
|
|
542
542
|
try {
|
|
543
|
-
return jsonResponse(200, await cardSnapshot(resolver, workspaceRegistry));
|
|
543
|
+
return jsonResponse(200, await cardSnapshot(resolver, workspaceRegistry, harnessVersion));
|
|
544
544
|
}
|
|
545
545
|
catch (error) {
|
|
546
546
|
return jsonResponse(500, {
|
|
@@ -578,13 +578,13 @@ async function handleCardRequest(request, ctx, resolver, workspaceRegistry, read
|
|
|
578
578
|
* harness API path, so the carrier applies its Host/Origin fence and browser
|
|
579
579
|
* authentication before the handler runs.
|
|
580
580
|
*/
|
|
581
|
-
export function registerCardRoute(ctx, resolver, workspaceRegistry, readLocale) {
|
|
581
|
+
export function registerCardRoute(ctx, resolver, workspaceRegistry, readLocale, harnessVersion) {
|
|
582
582
|
ctx.inject(["connection"], (connectionCtx) => {
|
|
583
583
|
connectionCtx.connection.fetch.register({
|
|
584
584
|
path: CARD_PATH,
|
|
585
585
|
methods: ["GET", "POST"],
|
|
586
586
|
requestBody: "buffered",
|
|
587
|
-
fetch: (request) => handleCardRequest(request, connectionCtx, resolver, workspaceRegistry, readLocale),
|
|
587
|
+
fetch: (request) => handleCardRequest(request, connectionCtx, resolver, workspaceRegistry, readLocale, harnessVersion),
|
|
588
588
|
});
|
|
589
589
|
});
|
|
590
590
|
}
|
package/dist/dsh-version.d.ts
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
export
|
|
1
|
+
export interface PluginPackageLookup {
|
|
2
|
+
packageOf?(specifier: string, parentURL: string): {
|
|
3
|
+
version?: unknown;
|
|
4
|
+
} | undefined;
|
|
5
|
+
}
|
|
6
|
+
export declare function dshVersion(packages?: PluginPackageLookup): string;
|
|
7
|
+
export declare function versionFromPackages(packages?: PluginPackageLookup): string | undefined;
|
package/dist/dsh-version.js
CHANGED
|
@@ -4,24 +4,37 @@
|
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import { existsSync, readFileSync } from "node:fs";
|
|
6
6
|
import { join } from "node:path";
|
|
7
|
-
// The harness version this plugin runs inside.
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
7
|
+
// The harness version this plugin runs inside. The dsh app package is not a
|
|
8
|
+
// physical dependency of the plugin: the boot loader serves profile plugin
|
|
9
|
+
// imports from an in-memory package table, so the plugin asks that table
|
|
10
|
+
// (`ctx.pluginPackages`) for the package it runs under. The physical module
|
|
11
|
+
// walk below is only a fallback for a development checkout. "" when the
|
|
12
|
+
// version cannot be resolved, which the card renders as unknown.
|
|
13
|
+
const PACKAGE = "@deepseek-ai/dsh";
|
|
12
14
|
let cached;
|
|
13
|
-
export function dshVersion() {
|
|
14
|
-
cached
|
|
15
|
-
|
|
15
|
+
export function dshVersion(packages) {
|
|
16
|
+
if (cached !== undefined)
|
|
17
|
+
return cached;
|
|
18
|
+
const resolved = versionFromPackages(packages) ?? resolveDshVersion();
|
|
19
|
+
// Only a resolved version is cached, so an early lookup without the package
|
|
20
|
+
// table cannot pin "" for the process lifetime.
|
|
21
|
+
if (resolved !== undefined && resolved !== "")
|
|
22
|
+
cached = resolved;
|
|
23
|
+
return resolved ?? "";
|
|
16
24
|
}
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
25
|
+
// versionFromPackages reads the running app package's manifest version through
|
|
26
|
+
// the profile package lookup. It is undefined when the lookup is absent, the
|
|
27
|
+
// package is unknown, or the manifest carries no usable version.
|
|
28
|
+
export function versionFromPackages(packages) {
|
|
29
|
+
const version = packages?.packageOf?.(PACKAGE, import.meta.url)?.version;
|
|
30
|
+
return typeof version === "string" && version !== "" ? version : undefined;
|
|
31
|
+
}
|
|
32
|
+
// resolveDshVersion walks the physical module search paths, for an install
|
|
33
|
+
// whose app package is a real node_modules entry (a source checkout).
|
|
20
34
|
function resolveDshVersion() {
|
|
21
35
|
let searchPaths;
|
|
22
36
|
try {
|
|
23
|
-
searchPaths =
|
|
24
|
-
createRequire(import.meta.url).resolve.paths("@deepseek-ai/dsh") ?? [];
|
|
37
|
+
searchPaths = createRequire(import.meta.url).resolve.paths(PACKAGE) ?? [];
|
|
25
38
|
}
|
|
26
39
|
catch {
|
|
27
40
|
return undefined;
|
|
@@ -29,7 +42,7 @@ function resolveDshVersion() {
|
|
|
29
42
|
for (const searchPath of searchPaths) {
|
|
30
43
|
if (searchPath === null)
|
|
31
44
|
continue;
|
|
32
|
-
const manifest = join(searchPath,
|
|
45
|
+
const manifest = join(searchPath, PACKAGE, "package.json");
|
|
33
46
|
if (!existsSync(manifest))
|
|
34
47
|
continue;
|
|
35
48
|
try {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 Elouan Martinet <exa@elou.world>
|
|
2
|
+
//
|
|
3
|
+
// SPDX-License-Identifier: MIT
|
|
4
|
+
import test from "node:test";
|
|
5
|
+
import assert from "node:assert/strict";
|
|
6
|
+
import { versionFromPackages } from "./dsh-version.js";
|
|
7
|
+
test("versionFromPackages reads the app version through the profile lookup", () => {
|
|
8
|
+
const packages = {
|
|
9
|
+
packageOf: (specifier, parentURL) => {
|
|
10
|
+
assert.equal(specifier, "@deepseek-ai/dsh");
|
|
11
|
+
assert.ok(parentURL.startsWith("file:"), "lookup uses this module's URL");
|
|
12
|
+
return { version: "1.2.3" };
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
assert.equal(versionFromPackages(packages), "1.2.3");
|
|
16
|
+
});
|
|
17
|
+
test("versionFromPackages reports no version when the package is unknown", () => {
|
|
18
|
+
assert.equal(versionFromPackages({ packageOf: () => undefined }), undefined);
|
|
19
|
+
});
|
|
20
|
+
test("versionFromPackages ignores a missing lookup and unusable versions", () => {
|
|
21
|
+
assert.equal(versionFromPackages(undefined), undefined);
|
|
22
|
+
assert.equal(versionFromPackages({}), undefined);
|
|
23
|
+
assert.equal(versionFromPackages({ packageOf: () => ({ version: "" }) }), undefined);
|
|
24
|
+
assert.equal(versionFromPackages({ packageOf: () => ({ version: 3 }) }), undefined);
|
|
25
|
+
});
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.
|
|
2
|
-
export declare const GIT_COMMIT = "
|
|
1
|
+
export declare const VERSION = "0.4.0";
|
|
2
|
+
export declare const GIT_COMMIT = "e5c1eb5";
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import { toolHandlers } from "./tool-handlers.js";
|
|
|
12
12
|
import { defineTool, TOOL_DESCRIPTIONS, toolOutput, TOOLS, } from "./tool-schemas.js";
|
|
13
13
|
import { toolCallView, toolResultView } from "./tool-views.js";
|
|
14
14
|
import { registerCardRoute } from "./card-route.js";
|
|
15
|
+
import { dshVersion } from "./dsh-version.js";
|
|
15
16
|
import { registerTerminalRoutes } from "./terminal-route.js";
|
|
16
17
|
import { TerminalSessions } from "./terminal-sessions.js";
|
|
17
18
|
import { normalizeToolError, WorkspaceResolver } from "./workspace-binding.js";
|
|
@@ -103,7 +104,11 @@ export function apply(ctx, config) {
|
|
|
103
104
|
ctx.inject(["settings"], (child) => {
|
|
104
105
|
child.effect(() => child.settings.configure({ auto: false }, ctx.fiber), "podman: settings presentation");
|
|
105
106
|
});
|
|
106
|
-
|
|
107
|
+
// The harness version is read through the profile's package lookup: the dsh
|
|
108
|
+
// app package is served from the loader's in-memory table, not a physical
|
|
109
|
+
// node_modules entry. It is resolved once and served with every snapshot.
|
|
110
|
+
const dshVersionValue = dshVersion(ctx.get("pluginPackages"));
|
|
111
|
+
registerCardRoute(ctx, resolver, ctx.workspaceRegistry, readLocale, dshVersionValue);
|
|
107
112
|
// The Podman terminal tab talks to guest ptys through its own routes; the
|
|
108
113
|
// registry keeps shells alive while the browser is away.
|
|
109
114
|
const terminalSessions = new TerminalSessions({ resolver });
|
|
@@ -8,7 +8,7 @@ import loader from "@grpc/proto-loader";
|
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
9
|
import { dirname, resolve } from "node:path";
|
|
10
10
|
import { tmpdir } from "node:os";
|
|
11
|
-
import { mkdirSync } from "node:fs";
|
|
11
|
+
import { existsSync, mkdirSync, rmSync } from "node:fs";
|
|
12
12
|
import { controlClient, guestClient } from "./grpc/runtime-client.js";
|
|
13
13
|
import { containerNotFound, metadata, normalizeToolError, WorkspaceResolver, workspaceSlug, } from "./workspace-binding.js";
|
|
14
14
|
import { VERSION } from "./generated/version.js";
|
|
@@ -190,9 +190,20 @@ async function startControlServer(containers = [], options = {}) {
|
|
|
190
190
|
versions,
|
|
191
191
|
createRequests,
|
|
192
192
|
recreateRequests,
|
|
193
|
-
stop: () =>
|
|
193
|
+
stop: () => {
|
|
194
|
+
server.forceShutdown();
|
|
195
|
+
// gRPC unlinks its sockets on shutdown; drop the root too so repeated
|
|
196
|
+
// runs do not accumulate directories under the system temp dir.
|
|
197
|
+
rmSync(socketsRoot, { recursive: true, force: true });
|
|
198
|
+
},
|
|
194
199
|
};
|
|
195
200
|
}
|
|
201
|
+
test("the control server cleanup removes its temp root", async () => {
|
|
202
|
+
const control = await startControlServer();
|
|
203
|
+
assert.ok(existsSync(control.socketsRoot));
|
|
204
|
+
control.stop();
|
|
205
|
+
assert.equal(existsSync(control.socketsRoot), false);
|
|
206
|
+
});
|
|
196
207
|
test("control calls carry the bearer token", async () => {
|
|
197
208
|
const { socketsRoot, received, versions, stop } = await startControlServer();
|
|
198
209
|
try {
|
package/docs/usage.md
CHANGED
|
@@ -49,6 +49,18 @@ dsh-podman organizes the images its containers run into three tiers:
|
|
|
49
49
|
Image references (`imageId`, `parent`, `image`) are **short names only** (no
|
|
50
50
|
registry prefix, no `:tag`).
|
|
51
51
|
|
|
52
|
+
### Base images
|
|
53
|
+
|
|
54
|
+
Each base image is built from its primitive reference with the same fixed,
|
|
55
|
+
dsh-podman-owned package list, and a custom image inherits its parent's package
|
|
56
|
+
manager.
|
|
57
|
+
|
|
58
|
+
| Short name | Package manager | Primitive | Packages |
|
|
59
|
+
| ----------- | --------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
60
|
+
| `archlinux` | `pacman` | `docker.io/library/archlinux:latest` | `base-devel`, `ca-certificates`, `curl`, `diffutils`, `fd`, `git`, `inetutils`, `jq`, `less`, `openbsd-netcat`, `openssh`, `patch`, `procps-ng`, `python`, `ripgrep`, `tree`, `unzip`, `wget`, `zstd` |
|
|
61
|
+
| `ubuntu` | `apt` | `docker.io/library/ubuntu:latest` | `build-essential`, `ca-certificates`, `curl`, `diffutils`, `fd-find`, `git`, `jq`, `less`, `netcat-openbsd`, `openssh-client`, `patch`, `procps`, `python3`, `ripgrep`, `tree`, `unzip`, `wget`, `zstd` |
|
|
62
|
+
| `alpine` | `apk` | `docker.io/library/alpine:latest` | `bash`, `build-base`, `ca-certificates`, `curl`, `diffutils`, `fd`, `git`, `jq`, `less`, `openssh-client`, `patch`, `procps`, `python3`, `ripgrep`, `tree`, `unzip`, `wget`, `zstd` |
|
|
63
|
+
|
|
52
64
|
## Tools
|
|
53
65
|
|
|
54
66
|
The plugin registers the following model-facing tools. Tools marked `✱` require
|
package/docs/usage.zh.md
CHANGED
|
@@ -42,6 +42,17 @@ dsh-podman 将容器运行的镜像组织为三个层级:
|
|
|
42
42
|
镜像引用(`imageId`、`parent`、`image`)**只能是短名称**(没有镜像仓库前缀,没有
|
|
43
43
|
`:tag`)。
|
|
44
44
|
|
|
45
|
+
### 基础镜像
|
|
46
|
+
|
|
47
|
+
每个基础镜像都从其原始引用构建,安装同一份由 dsh-podman
|
|
48
|
+
拥有的固定软件包列表;自定义镜像继承其父镜像的软件包管理器。
|
|
49
|
+
|
|
50
|
+
| 短名称 | 软件包管理器 | 原始镜像 | 软件包 |
|
|
51
|
+
| ----------- | ------------ | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
52
|
+
| `archlinux` | `pacman` | `docker.io/library/archlinux:latest` | `base-devel`、`ca-certificates`、`curl`、`diffutils`、`fd`、`git`、`inetutils`、`jq`、`less`、`openbsd-netcat`、`openssh`、`patch`、`procps-ng`、`python`、`ripgrep`、`tree`、`unzip`、`wget`、`zstd` |
|
|
53
|
+
| `ubuntu` | `apt` | `docker.io/library/ubuntu:latest` | `build-essential`、`ca-certificates`、`curl`、`diffutils`、`fd-find`、`git`、`jq`、`less`、`netcat-openbsd`、`openssh-client`、`patch`、`procps`、`python3`、`ripgrep`、`tree`、`unzip`、`wget`、`zstd` |
|
|
54
|
+
| `alpine` | `apk` | `docker.io/library/alpine:latest` | `bash`、`build-base`、`ca-certificates`、`curl`、`diffutils`、`fd`、`git`、`jq`、`less`、`openssh-client`、`patch`、`procps`、`python3`、`ripgrep`、`tree`、`unzip`、`wget`、`zstd` |
|
|
55
|
+
|
|
45
56
|
## 工具
|
|
46
57
|
|
|
47
58
|
插件注册了以下面向模型的工具。标记 `✱`
|