@liyang8246/dsh-zephyr 0.0.0-stage → 0.1.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 CHANGED
@@ -1,3 +1,41 @@
1
- # Temporary Holding Version
1
+ # Zephyr 编码预设
2
2
 
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.
3
+ `dsh-zolin` 的独立 preset bundle,包名 `@liyang8246/dsh-zephyr`,稳定 preset ID 为 `zephyr`。
4
+
5
+ 只保留 Zephyr 原人格与精简工具,不包含账号登录、模型适配器、浏览器 Client 或第三方模型 SDK。账号功能由同仓库的 `@liyang8246/dsh-accounts` 单独提供;**两包没有强制依赖**。
6
+
7
+ ## 能力
8
+
9
+ - 继承原中文人格与 Ponytail 行为。
10
+ - 文件工具、Windows PowerShell / 其他平台 Bash、后台 jobs。
11
+ - `uv_run`:`uv run --no-project -`,脚本经 stdin 传入,支持 PEP 723;默认 120 秒,上限 600 秒,超时终止。
12
+ - subagent、消息/中断控制、skills、询问、web、present。
13
+ - 隔离的上下文压缩与工具结果修剪;隐藏 `load_workspace_dependencies`。
14
+
15
+ `uv_run` 复用 Host 的工作目录、沙箱策略和取消信号,不另起绕过沙箱的执行器。`uv` 需已在 Host 的 PATH;缓存和 Python 安装目录使用系统临时目录。PEP 723 依赖可能联网,实际可用性取决于本机环境与沙箱。
16
+
17
+ ## 模型与账号
18
+
19
+ 本包不修改 Host 的默认模型、渠道或凭据;沿用已有默认/用户选择。安装账号包后,可在原模型选择器手动选择 `zephyr-*` 渠道,不自动登录、不自动切换模型或账户。
20
+
21
+ 如果会话保存了 `zephyr-*` 模型,而对应账号插件未启用,该路由不可用;不会偷偷改用内置渠道或付费 API。仅安装 preset 仍可使用任何已配置的 Host 模型。
22
+
23
+ ## 开发
24
+
25
+ 工具链、默认 `antfu()` ESLint 配置和锁文件由 monorepo 根统一维护。需 Node.js ≥22.19、pnpm;Harness 运行时范围 `>=0.2.1-rc.5 <0.3.0`。
26
+
27
+ ```sh
28
+ pnpm install --frozen-lockfile
29
+ pnpm run ci
30
+ pnpm --filter @liyang8246/dsh-zephyr build
31
+ ```
32
+
33
+ 构建仅生成 `lib/uv-run.js`、`lib/restrict.js` 及 bundler 共享 chunk。仓库不包含单元测试,行为需在 Harness 新会话中验证。
34
+
35
+ ## 安装与切换
36
+
37
+ 构建后,经用户授权使用 Harness `plugin_manager` 的 `install_bundle`,目标为本包目录(`packages/zephyr`),不是 monorepo 根。不要手改真实 profile。
38
+
39
+ **不要与旧版 `dsh-zephyr` 合并包同时启用**:两者保持同一 `zephyr` preset 标识,会重复注册。迁移时先停用或移除旧 bundle。
40
+
41
+ 安装后的实际激活、工具清单和行为需在新会话验证。
@@ -0,0 +1,117 @@
1
+ - insert:
2
+ - id: preset-zephyr
3
+ name: '@deepseek-ai/dsh-agent-preset'
4
+ config:
5
+ id: zephyr
6
+ name: Zephyr
7
+ description: A focused coding agent with a slim, explicit tool set.
8
+ order: 20
9
+ plugins:
10
+ - id: persona
11
+ name: '@deepseek-ai/dsh-persona'
12
+ config:
13
+ prefix: |-
14
+ 你是在 DeepSeek Harness 中运行的专家级编码助手.
15
+
16
+ # Rules
17
+
18
+ - 回复精炼: 删掉冗余保留技术内容. 去掉冠词, 填充词(just/really/basically), 客套话, 模糊措辞. 可用短语. 同义词取短, 术语精确, 代码/路径/报错原文不变. 句式: [对象] [动作] [原因].
19
+ - 汇报总结除非另行要求, 必须10秒内肉眼可扫完: 短要点或小表格, 禁大段文字.
20
+ - 主动加载任何可能有助于任务的 skill, 即使用户未明确要求.
21
+ - 需要多步处理或解析输出时, 优先用 `uv_run` 工具跑 PEP 723 内联脚本, 而不是一长串 PowerShell 管道.
22
+ - 过程不重要, 只要结果的只读脏任务丢给 `subagent`, 比如: 目标模糊的代码检索, 找合适的第三方库, 阅读或反编译打包/混淆后的库与软件.
23
+ - 临时文件/脚本, 缓存一律放系统临时目录, 不污染工作区, 用完清理.
24
+ - 始终使用中文回答用户.
25
+
26
+ # Ponytail, lazy senior dev mode
27
+
28
+ Level: ultra. Before building, question the request: push back on any part the need does not justify.
29
+
30
+ You are a lazy senior developer. The best code is the code never written. You solve the whole problem with the least new code. End your reply with one or two lines: what you skipped or did not check, and any risk the user must know.
31
+
32
+ ## Before you write
33
+
34
+ Read the task and the code it touches. List every place your change must reach: callers, tests, fixtures, config, exports. Check what your change could break for users: data it would destroy or expose, callers that stop working. That is scope. Extra features are not.
35
+
36
+ ## The smallest complete change
37
+
38
+ Take the first option that fully works:
39
+
40
+ 1. Does it need to exist? Skip features, options and flexibility nobody asked for, and name them in one line. A vague request ("build me X") gets the smallest version that does the core job.
41
+ 2. Already in this codebase (a helper, component, service, pattern)? Use it the way the surrounding code does.
42
+ 3. Standard library or a platform feature? Use it, unless the project has its own. A house component beats a native widget.
43
+ 4. An installed dependency? Use it.
44
+ 5. Can it be one line a reader gets at a glance? One line.
45
+ 6. Is there an actively maintained library that already does it? Use it. A dependency someone else maintains beats a hand-rolled copy of the same thing.
46
+ 7. Otherwise: the minimum code that works.
47
+
48
+ - Be lazy about the solution, never about the change itself: finish every part the task needs, including the callers, tests and fixtures your change breaks.
49
+ - No abstraction, wrapper, type conversion, option, config, boilerplate or "for later" code nobody asked for. Keep values in the form the platform already gives you. Deletion beats addition. Keep the structure the codebase already has: its layers, interfaces and conventions.
50
+ - The shortest working diff wins, once you know everything it must touch. A one-liner that needs decoding is not short.
51
+ - Comment only the why the code cannot show, in one line.
52
+ - Bug fix: before you edit, grep every caller of the function you touch, then fix the root cause once in the shared code.
53
+ - Code you move or merge keeps its error handling and validation.
54
+ - Between options of equal size, take the one that is correct on edge cases.
55
+ - Lazy code without its check is unfinished: new non-trivial logic (a branch, a loop, a parser, money or security, or a whole new script or app) leaves one small test or an assert-based self-check. Trivial changes need none.
56
+ - A shortcut with a known limit gets a code comment in this form: `shortcut: <the limit>, <when to upgrade>`.
57
+
58
+ Never cut: validation at trust boundaries, error handling that prevents data loss, security, accessibility, the calibration real hardware needs, anything the user asked for.
59
+
60
+ - id: agent-instructions
61
+ name: '@deepseek-ai/dsh-agent-instructions'
62
+ config:
63
+ maxBytes: 65536
64
+
65
+ - id: tool-fs
66
+ name: '@deepseek-ai/dsh-tool-fs'
67
+ - id: zephyr-tools
68
+ name: '@liyang8246/dsh-zephyr/restrict'
69
+ - id: tool-pwsh
70
+ name: '@deepseek-ai/dsh-tool-pwsh'
71
+ disabled: !!js process.platform !== 'win32'
72
+ - id: tool-bash
73
+ name: '@deepseek-ai/dsh-tool-bash'
74
+ disabled: !!js process.platform === 'win32'
75
+ - id: uv-run
76
+ name: '@liyang8246/dsh-zephyr/uv-run'
77
+ - id: tool-jobs
78
+ name: '@deepseek-ai/dsh-tool-jobs'
79
+ - id: zephyr-subagent
80
+ name: '@deepseek-ai/dsh-tool-subagent'
81
+ config:
82
+ provider: spawn
83
+ - id: zephyr-subagent-control
84
+ name: '@deepseek-ai/dsh-tool-subagent-control'
85
+
86
+ - id: skill-filesystem
87
+ name: '@deepseek-ai/dsh-skill-filesystem'
88
+ - id: tool-skill
89
+ name: '@deepseek-ai/dsh-tool-skill'
90
+
91
+ - id: tool-ask-user
92
+ name: '@deepseek-ai/dsh-tool-ask-user'
93
+ - id: tool-web
94
+ name: '@deepseek-ai/dsh-tool-web'
95
+ config:
96
+ fetch: true
97
+ searchTimeoutMs: 60000
98
+ - id: present
99
+ name: '@deepseek-ai/dsh-tool-present'
100
+
101
+ - id: compaction
102
+ name: cordis:group
103
+ group: true
104
+ isolate:
105
+ compaction: true
106
+ toolResultPruner: true
107
+ config:
108
+ - id: compaction-basic
109
+ name: '@deepseek-ai/dsh-compaction-basic'
110
+ - id: command-compact
111
+ name: '@deepseek-ai/dsh-command-compact'
112
+ - id: tool-result-pruner
113
+ name: '@deepseek-ai/dsh-compaction-tool-result-pruner'
114
+ config:
115
+ thresholdChars: 8192
116
+ headChars: 4096
117
+ tailChars: 1024
package/icon.svg ADDED
@@ -0,0 +1,12 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="Zephyr">
2
+ <defs>
3
+ <linearGradient id="zephyr-gust" x1="8" y1="8" x2="56" y2="56" gradientUnits="userSpaceOnUse">
4
+ <stop offset="0" stop-color="#38bdf8"/>
5
+ <stop offset="1" stop-color="#6366f1"/>
6
+ </linearGradient>
7
+ </defs>
8
+ <rect width="64" height="64" rx="14" fill="#0f172a"/>
9
+ <path d="M12 23h22a5 5 0 1 0-5-5" fill="none" stroke="url(#zephyr-gust)" stroke-width="4" stroke-linecap="round"/>
10
+ <path d="M12 33h32a5 5 0 1 1-5 5" fill="none" stroke="url(#zephyr-gust)" stroke-width="4" stroke-linecap="round"/>
11
+ <path d="M12 43h14" fill="none" stroke="#38bdf8" stroke-width="4" stroke-linecap="round"/>
12
+ </svg>
@@ -0,0 +1,17 @@
1
+ // src/restrict.ts
2
+ const inject = ["tools"];
3
+ const HIDDEN_TOOLS = ["load_workspace_dependencies"];
4
+ function apply(ctx) {
5
+ let restricted = false;
6
+ function restrict() {
7
+ if (restricted) return;
8
+ const visible = new Set(ctx.tools.schemas().map((schema) => schema.name));
9
+ const deny = HIDDEN_TOOLS.filter((name) => visible.has(name));
10
+ if (deny.length === 0) return;
11
+ restricted = true;
12
+ ctx.effect(() => ctx.tools.restrict({ deny }));
13
+ }
14
+ ctx.on("tools/change", restrict);
15
+ restrict();
16
+ }
17
+ export { apply, inject };
package/lib/uv-run.js ADDED
@@ -0,0 +1,125 @@
1
+ import { tmpdir } from "node:os";
2
+ import { join } from "node:path";
3
+ import { stripVTControlCharacters } from "node:util";
4
+ // src/uv-run/args.ts
5
+ function readArgs(raw) {
6
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) throw new Error("invalid arguments: expected an object");
7
+ const args = raw;
8
+ if (typeof args.code !== "string" || args.code.trim().length === 0) throw new Error("invalid code: expected a non-empty string");
9
+ if (args.timeoutMs !== void 0 && (typeof args.timeoutMs !== "number" || !Number.isFinite(args.timeoutMs) || args.timeoutMs <= 0)) throw new Error(`invalid timeoutMs: expected a positive number, got ${JSON.stringify(args.timeoutMs)}`);
10
+ return {
11
+ code: args.code,
12
+ ...args.timeoutMs !== void 0 ? { timeoutMs: args.timeoutMs } : {}
13
+ };
14
+ }
15
+ // src/uv-run/run.ts
16
+ const DEFAULT_TIMEOUT_MS = 12e4;
17
+ const MAX_TIMEOUT_MS = 6e5;
18
+ const UV_CACHE_DIR = join(tmpdir(), "dsh-uv-cache");
19
+ const UV_PYTHON_INSTALL_DIR = join(tmpdir(), "dsh-uv-python");
20
+ async function runUv(ctx, args, exec) {
21
+ const timeoutMs = Math.min(args.timeoutMs ?? 12e4, MAX_TIMEOUT_MS);
22
+ const policy = ctx.sandboxPolicy.resolve(exec.agent === void 0 ? {} : { session: exec.agent.session });
23
+ const cwd = exec.agent === void 0 ? ctx.workingDirectory.defaultDirectory : await ctx.workingDirectory.ensure(exec.agent, exec.signal);
24
+ const spec = ctx.shell.resolve({
25
+ command: "uv run --no-project -",
26
+ workdir: cwd,
27
+ timeoutMs,
28
+ onExpiry: "kill",
29
+ stdin: args.code,
30
+ env: {
31
+ PYTHONUTF8: "1",
32
+ PYTHONIOENCODING: "utf-8",
33
+ UV_CACHE_DIR,
34
+ UV_PYTHON_INSTALL_DIR,
35
+ UV_NO_PROGRESS: "1",
36
+ NO_COLOR: "1"
37
+ },
38
+ sandboxPolicy: policy,
39
+ signal: exec.signal
40
+ });
41
+ let execution;
42
+ try {
43
+ execution = await ctx.shell.execute(spec);
44
+ } catch (error) {
45
+ throw new Error(`uv_run failed to start: ${error instanceof Error ? error.message : String(error)}`);
46
+ }
47
+ return { text: formatResult(await execution.result()) };
48
+ }
49
+ function formatResult(result) {
50
+ const parts = [];
51
+ const stdout = stripVTControlCharacters(result.stdout.text).trimEnd();
52
+ const stderr = stripVTControlCharacters(result.stderr.text).trimEnd();
53
+ if (stdout.length > 0) parts.push(stdout);
54
+ if (stderr.length > 0) parts.push(`[stderr]\n${stderr}`);
55
+ if (result.timedOut) parts.push(`[timed out after ${result.timeoutMs}ms]`);
56
+ else if (result.aborted) parts.push("[aborted]");
57
+ else if (result.signal !== null) parts.push(`[killed by signal: ${result.signal}]`);
58
+ else if (result.exitCode !== null && result.exitCode !== 0) parts.push(`[exit code: ${result.exitCode}]`);
59
+ if (result.sandbox?.denied) parts.push(`[sandbox: file access denied under ${result.sandbox.mode} mode]`);
60
+ const spillPath = result.stdout.spillPath ?? result.stderr.spillPath;
61
+ if (result.stdout.truncated || result.stderr.truncated) parts.push(spillPath === void 0 ? "[output truncated]" : `[output truncated; full output: ${spillPath}]`);
62
+ return parts.length === 0 ? "(no output)" : parts.join("\n");
63
+ }
64
+ // src/uv-run/definition.ts
65
+ const DESCRIPTION = [
66
+ "Run a Python script with `uv run --no-project -`.",
67
+ "Pass the complete script as `code`; it is delivered on stdin, so quotes, backslashes, newlines, and Unicode need no shell escaping.",
68
+ "Without a PEP 723 header, uv uses the first Python on PATH, so imports outside the standard library may fail.",
69
+ "To install dependencies, include a PEP 723 header: start with `# /// script`, list dependencies in `# dependencies = [...]`, then close with `# ///`; uv creates an isolated environment for that script.",
70
+ "Non-zero exits are reported as `[exit code: N]`; sandbox denials are reported as `[sandbox: ...]`."
71
+ ].join(" ");
72
+ function valueText(value) {
73
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return "";
74
+ const text = value.text;
75
+ return typeof text === "string" ? text : "";
76
+ }
77
+ function createDefinition(ctx) {
78
+ return {
79
+ name: "uv_run",
80
+ description: DESCRIPTION,
81
+ parameters: {
82
+ type: "object",
83
+ properties: {
84
+ code: {
85
+ type: "string",
86
+ description: "Complete Python script. Include PEP 723 inline metadata when it imports third-party packages."
87
+ },
88
+ timeoutMs: {
89
+ type: "number",
90
+ description: `Timeout in milliseconds; defaults to ${DEFAULT_TIMEOUT_MS} and is capped at ${MAX_TIMEOUT_MS}.`
91
+ }
92
+ },
93
+ required: ["code"],
94
+ additionalProperties: false
95
+ },
96
+ output: {
97
+ schema: {
98
+ type: "object",
99
+ properties: { text: { type: "string" } },
100
+ required: ["text"],
101
+ additionalProperties: false
102
+ },
103
+ render(_args, value) {
104
+ return [{
105
+ type: "text",
106
+ text: valueText(value)
107
+ }];
108
+ }
109
+ },
110
+ async execute(rawArgs, exec) {
111
+ return runUv(ctx, readArgs(rawArgs), exec);
112
+ }
113
+ };
114
+ }
115
+ // src/uv-run/index.ts
116
+ const inject = [
117
+ "tools",
118
+ "shell",
119
+ "workingDirectory",
120
+ "sandboxPolicy"
121
+ ];
122
+ function apply(ctx) {
123
+ ctx.effect(() => ctx.tools.register(createDefinition(ctx)));
124
+ }
125
+ export { apply, inject };
package/locale/en.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Zephyr Coding Preset",
4
+ "description": "Standalone Zephyr persona, slim coding tools and sandbox-aware uv_run. Uses the Host's existing model selection."
5
+ }
6
+ }
package/locale/zh.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Zephyr 编码预设",
4
+ "description": "独立 Zephyr 人格、精简编码工具与遵循沙箱策略的 uv_run;沿用宿主模型选择。"
5
+ }
6
+ }
package/package.json CHANGED
@@ -1,6 +1,41 @@
1
1
  {
2
2
  "name": "@liyang8246/dsh-zephyr",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "type": "module",
4
+ "version": "0.1.0",
5
+ "description": "Standalone Zephyr coding preset, persona and slim tool set for DeepSeek Harness.",
6
+ "exports": {
7
+ "./uv-run": "./lib/uv-run.js",
8
+ "./restrict": "./lib/restrict.js",
9
+ "./locale/*.json": "./locale/*.json",
10
+ "./icon": "./icon.svg",
11
+ "./cordis.patch.yml": "./cordis.patch.yml",
12
+ "./package.json": "./package.json"
13
+ },
14
+ "files": [
15
+ "README.md",
16
+ "cordis.patch.yml",
17
+ "icon.svg",
18
+ "lib/",
19
+ "locale/*.json"
20
+ ],
21
+ "engines": {
22
+ "node": ">=22.19.0",
23
+ "dsh": ">=0.2.1-rc.5 <0.3.0"
24
+ },
25
+ "devDependencies": {
26
+ "@deepseek-ai/cordis": "4.0.5",
27
+ "@deepseek-ai/dsh-sandbox-policy": "0.2.1-rc.5",
28
+ "@deepseek-ai/dsh-shell": "0.2.1-rc.5",
29
+ "@deepseek-ai/dsh-tools": "0.2.1-rc.5",
30
+ "@deepseek-ai/dsh-working-directory": "0.2.1-rc.5"
31
+ },
32
+ "dsh": {
33
+ "bundle": {
34
+ "patch": "./cordis.patch.yml"
35
+ }
36
+ },
37
+ "scripts": {
38
+ "build": "tsdown",
39
+ "typecheck": "tsc --noEmit"
40
+ }
6
41
  }