@dsh-fly/dsh-plugin-fly-mode 0.0.0-stage → 0.1.3

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.
Files changed (26) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +79 -2
  3. package/cordis.patch.yml +399 -0
  4. package/package.json +32 -4
  5. package/tools/dsh-plugin-fly-binary/index.js +520 -0
  6. package/tools/dsh-plugin-fly-binary/package.json +23 -0
  7. package/tools/dsh-plugin-fly-blackbox/assets/client-blackbox/SKILL.md +163 -0
  8. package/tools/dsh-plugin-fly-blackbox/assets/client-blackbox/code/mitm_addon_template.py +302 -0
  9. package/tools/dsh-plugin-fly-blackbox/assets/client-blackbox/code/rules.example.json +52 -0
  10. package/tools/dsh-plugin-fly-blackbox/assets/client-blackbox/reference/case-ttw.md +157 -0
  11. package/tools/dsh-plugin-fly-blackbox/assets/client-blackbox/reference/checklist.md +133 -0
  12. package/tools/dsh-plugin-fly-blackbox/assets/client-blackbox/reference/playbook.md +228 -0
  13. package/tools/dsh-plugin-fly-blackbox/assets/client-blackbox/reference/rules.schema.md +76 -0
  14. package/tools/dsh-plugin-fly-blackbox/index.js +1453 -0
  15. package/tools/dsh-plugin-fly-blackbox/package.json +31 -0
  16. package/tools/dsh-plugin-fly-diag/index.js +772 -0
  17. package/tools/dsh-plugin-fly-diag/package.json +24 -0
  18. package/tools/dsh-plugin-fly-diag/wifi.js +402 -0
  19. package/tools/dsh-plugin-fly-guard/index.js +101 -0
  20. package/tools/dsh-plugin-fly-guard/package.json +26 -0
  21. package/tools/dsh-plugin-fly-pwn/index.js +583 -0
  22. package/tools/dsh-plugin-fly-pwn/package.json +23 -0
  23. package/tools/dsh-plugin-fly-recon/index.js +184 -0
  24. package/tools/dsh-plugin-fly-recon/package.json +23 -0
  25. package/tools/dsh-plugin-fly-reverse/index.js +178 -0
  26. package/tools/dsh-plugin-fly-reverse/package.json +23 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DSH Fly contributors
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.md CHANGED
@@ -1,3 +1,80 @@
1
- # Temporary Holding Version
1
+ # @dsh-fly/dsh-plugin-fly-mode
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
+ 把 **Fly 安全模式**(agent preset `fly`)作为一个**可安装的 bundle 层**发出去:任何 profile
4
+ 装上它之后就能服务 `fly` preset,于是跨 profile 共用的会话库里那些带 `fly` 标签的会话不再是
5
+ "看得见、拿不到"(宿主会抛 `agent-preset/not-found: Unknown agent preset: fly`)。
6
+
7
+ ## 它是什么 / 不是什么
8
+
9
+ - **是**:一条 `- insert:` 声明(`id: preset-fly`,行表来自 `presets/fly/agent.cordis.yml`)。其中
10
+ **7 个 Fly 工具**(binary / reverse / pwn / diag / recon / blackbox / guard)的源码**内联在包内
11
+ `tools/`**,行表用**本包子路径**引用它们 —— 装这个包**不会**在 npm 上再拉这 7 个包;
12
+ **`fly-smart` 单独一个 plugin**:它是本包 `dependencies` 里**唯一**一项,行表保持裸名,
13
+ 由 npm 装进 profile 的 `node_modules`(它变化最快,且与工作台面板是一个整体,不适合内联)。
14
+ - **不是**:不带 `dsh.client`(模式是 agent 平面,没有浏览器半边);不带 Fly 工作台
15
+ (console / diagnostics / netops / plugins / smart-panel 是各自独立的包);**不带**
16
+ `dsh-plugin-fly-shell`(那会在别人的 UI 上再画一层 Fly 外壳)。
17
+ - **不写 registry 的 `default:`**:默认模式归上游 `standard`。装上它 ≠ 默认变 fly —— fly
18
+ 只是「设置 → Agent 预设」里多出来的一个可选模式。
19
+ - **不含三模型路由**:`brainRoute` / `handRoute` / `reviewRoute` 是**用户机器**上的状态
20
+ (`~/.dsh-fly/smart-routes.json`,面板写),本机那份值还是内网 provider。未被配置时工具会
21
+ 大声报错并指路(行配置 `<field>Route` 优先,其次才是工作台抽屉)。
22
+
23
+ ## `cordis.patch.yml` 是生成的,别手改
24
+
25
+ ```bash
26
+ # 在 dsh-fly 仓库里:
27
+ node scripts/build-fly-mode-bundle.mjs --out ../dsh-plugins/dsh-plugin-fly-mode/cordis.patch.yml
28
+ node scripts/build-fly-mode-bundle.mjs --out ../dsh-plugins/dsh-plugin-fly-mode/cordis.patch.yml --check
29
+ ```
30
+
31
+ 同源:它跑的是 `dsh-fly` 仓库里 `scripts/lib/fly-profile.mjs` 的 `seedAgentPreset()` —— dev 装配
32
+ (`pnpm setup:profile`)写进 `~/.dsh/profiles/fly/cordis.patch.yml` 的是**同一个函数**的输出。
33
+ `--check` 用于门禁(漂移即红)。
34
+
35
+ ## 发布(0.1.3 起走 tag → OIDC,自动带 provenance)
36
+
37
+ - **以后每次发版**:升 `version` → 提交 → 打**注释 tag** → 推 tag;`.github/workflows/release.yml`
38
+ 会自动 `npm publish --access public --provenance` —— **不需要 token、不需要 2FA、不需要人工批准**。
39
+ 前提是包的「Settings → Trusted Publisher」按下面配好(**一次即可**):
40
+
41
+ ```
42
+ Publisher GitHub Actions
43
+ Organization or user ethanchen669
44
+ Repository dsh-plugin-fly-mode
45
+ Workflow filename release.yml ← 只写文件名,不是 workflow 里的 name:
46
+ Allowed actions ☑ Allow npm publish ← 不勾只会"暂存",npm publish 会"成功"但什么都不发
47
+ ```
48
+
49
+ 重推同一个 tag **不会**重跑 workflow ⇒ 要重跑就换一个新 tag。
50
+ - **首次发布(≤0.1.2)走的是另一条路**:包在 npm 上还不存在 ⇒ 没有 Trusted Publisher 页面可填,
51
+ 只能 `npm stage publish --access public` 再在网页上批准(`stage` 不需要 2FA)。
52
+ 0.1.0 / 0.1.1 已废弃,**0.1.2 是最后一个用 stage 发出去的版本**。
53
+ - **验收三件**(必须**换缓存键**再读:registry 的 packument 会被 CDN 缓存,反复查同一把钥匙只会读到第一次的结果):
54
+ ① `dist-tags.latest == 新版本`;② **`dist.attestations` 存在**(= provenance 成了);
55
+ ③ `readme` 是**发布那一刻**的快照(改了 README 要等下一次发版才上 npm 页面)。
56
+ - 发布前两条硬要求:`repository.url` 与跑 workflow 的仓库**逐字一致**(`--provenance` 会校验,写错**直接拒发**);
57
+ 发布目标钉在 `publishConfig.registry = https://registry.npmjs.org/` —— 本机默认 registry 是**内网镜像**。
58
+
59
+ ## 安装
60
+
61
+ ```bash
62
+ # CLI 路径(web 等 profile);cwd 必须是 DSH_HOME
63
+ cd ~/.dsh
64
+ dsh plugin --profile=web add @dsh-fly/dsh-plugin-fly-mode@0.1.3 --registry=https://registry.npmjs.org/
65
+ ```
66
+
67
+ - 装完**必须重启那个进程**:引擎把层与服务缓存在**进程内**,刷新页面不够。
68
+ - **官方桌面版**归 app 独占(`dsh plugin` 会拒:`profile "desktop" is managed exclusively by the
69
+ Electron application`)⇒ 在 `~/.dsh/profiles/desktop/` 里 `pnpm add …@0.1.3 --registry=…`,
70
+ 并且要把包名加进 `package.json` 的 **`dsh.profile.bundles`** —— 那一条才让它成为一层
71
+ (只写 `dependencies` 是不会生效的)。
72
+
73
+ ## 仓库状态(2026-10-11)
74
+
75
+ - 形状定稿:一条 `- insert:` 声明 + 包内 `tools/`(7 个工具内联,行表用本包子路径引用)+
76
+ `dsh-plugin-fly-smart` 作为**唯一** npm 依赖。声明由 `dsh-fly` 仓的
77
+ `scripts/build-fly-mode-bundle.mjs` 生成,门禁用 `--check` 断漂移(含多出来的文件)。
78
+ - `.github/workflows/{ci,release}.yml` **已适配本仓**(纯声明包:不装依赖、直接跑
79
+ `node scripts/verify.mjs`),CI 已在公开仓实测全绿,含 `fetch-depth: 0` 的**全历史署名硬门**。
80
+ - 身份已按规范设好(仓级 `user.email = ethanchen669@users.noreply.github.com`)。
@@ -0,0 +1,399 @@
1
+ # 由仓库脚本生成,别手改:node scripts/build-fly-mode-bundle.mjs --out <本文件>
2
+ # 同源:这段声明来自 scripts/lib/fly-profile.mjs 的 seedAgentPreset()(dev 装配写进 profile 的
3
+ # 是同一条);8 个工具的行名被改写成**本包的子路径**(tools/**,随包一起发布)。
4
+ # 门禁用 --check 断言本文件与 tools/** 都 == 生成器输出。
5
+ # 不含三模型路由(用户机器状态)、不写 registry default(默认归上游 standard)。
6
+ - insert:
7
+ - id: preset-fly
8
+ name: '@deepseek-ai/dsh-agent-preset'
9
+ config:
10
+ id: fly
11
+ name: "Fly 安全"
12
+ description: "功能完整的编码 Agent,附带 Fly 安全/CTF 工具链(binary / reverse / pwn / diag / recon)。"
13
+ order: 10
14
+ plugins:
15
+ # Fly 的 agent preset:完整编码 agent + Fly 安全工具链。每个进程挂载一次。
16
+ #
17
+ # **怎么被挂上去的**:0.1.7-rc.2 的 `dsh-agent-preset-registry` 只从
18
+ # `@deepseek-ai/dsh-agent-preset` **声明行**组合 preset;`$DSH_HOME/.agent-presets/`
19
+ # 已经没人读了。声明行由 `scripts/lib/fly-profile.mjs` 的 `seedAgentPreset()` 从本文件
20
+ # 生成到 profile 的 patch 层(`- insert:` 一条 `preset-fly`,外加只写一次的 registry
21
+ # `default: standard` —— **默认模式留给上游**,见那个块里的注释:官方 Web / 官方桌面版
22
+ # 各自从自己的 profile 读同一个字段,装皮肤的人不该替它们决定默认模式;Fly 模式在
23
+ # 「设置 → Agent 预设」里可选、可设为默认)。
24
+ # 改本文件后重跑 `pnpm setup:profile` 即生效。
25
+ #
26
+ # This file is an AGENT-PLANE composition. The roster mounts it ONCE under a
27
+ # standing scope; every session naming it joins by scope parentage, so the
28
+ # tools and prompt sections registered here cover each joined agent while a
29
+ # session's own state stays keyed per Session/Agent inside the plugins. The
30
+ # host composition (`base.cordis.yml` + `web.cordis.yml`) keeps everything a
31
+ # preset must not own: the registries themselves, the sandbox and approval
32
+ # stack, persistence, and the model route.
33
+ #
34
+ # A service row here MUST sit inside a group carrying an `isolate` realm.
35
+ # Without one it publishes into the root realm, where it is process-global —
36
+ # another preset publishing the same name collides, and a host reader would
37
+ # resolve one preset's instance for every session; `dsh-agent-presets` rejects
38
+ # that at mount. `true` means an entry-local realm: this standing mount's own
39
+ # private instance, apart from every other preset's. (A shared label does NOT
40
+ # pool instances — `provide()` throws on the second registration under the
41
+ # same realm symbol; labels join REALMS, and are not what this file needs.)
42
+
43
+ # ── identity ────────────────────────────────────────────────────────────────
44
+
45
+ # The preset's own persona, shadowing the deployment default for this agent.
46
+ # `{{model}}` and `{{cwd}}` resolve from the agent's own route and workspace.
47
+ #
48
+ # `prefix`/`suffix` are the schema (`dsh-persona`: `prefix` required, `suffix`
49
+ # defaulted, `text` is a *boolean* interpolation switch). A `text: <string>` row
50
+ # used to sit here: it is not this plugin's config, so the row failed to activate
51
+ # and — because a preset mounts as one composition — the rejected row took the
52
+ # whole Fly preset down with it (symptom: sessions that never become composable).
53
+ - id: persona
54
+ name: '@deepseek-ai/dsh-persona'
55
+ config:
56
+ prefix: You are a coding agent powered by the {{model}} model.
57
+ suffix: Your working directory is {{cwd}}.
58
+
59
+ - id: agent-instructions
60
+ name: '@deepseek-ai/dsh-agent-instructions'
61
+ config:
62
+ maxBytes: 65536
63
+
64
+ # ── shell ───────────────────────────────────────────────────────────────────
65
+
66
+ # `shell-env` stays in the HOST composition: `apps/cli/src/web.ts` injects it to
67
+ # publish `DSH_WEB_URL`/`DSH_WEB_MODE`, and a host row that injects a service is
68
+ # the criterion for host-plane ownership — injection resolves before any session
69
+ # exists, so there is no agent to key by. Behind a preset realm those variables
70
+ # never reached the model's shell at all. Both shell tools consume the host
71
+ # registry from here; their executors (`bash-sandbox`/`pwsh-sandbox`) are
72
+ # host-plane too.
73
+ - id: tool-bash
74
+ name: '@deepseek-ai/dsh-tool-bash'
75
+ disabled: !!js process.platform === 'win32'
76
+
77
+ - id: tool-pwsh
78
+ name: '@deepseek-ai/dsh-tool-pwsh'
79
+ disabled: !!js process.platform !== 'win32'
80
+
81
+ # ── filesystem ──────────────────────────────────────────────────────────────
82
+
83
+ # Both register into the host `tools` registry and provide nothing, so
84
+ # they need no realm. The `fs` service and its policy stay in the host.
85
+ - id: tool-fs
86
+ name: '@deepseek-ai/dsh-tool-fs'
87
+
88
+ - id: tool-fs-search
89
+ name: '@deepseek-ai/dsh-tool-fs-search'
90
+ config:
91
+ sampleOverCapGlobResults: false
92
+
93
+ # ── background jobs ────────────────────────────────────────────────────────
94
+
95
+ # Only the model-facing controls. The task REGISTRY stays on the host plane:
96
+ # its producers sit outside any realm this file could put it in — `tool-bash`
97
+ # above resolves it with `ctx.get`, and an entry-local realm here is invisible
98
+ # to every sibling row, so `run_in_background` would answer "background jobs
99
+ # unavailable" while these controls sat in the catalog. The registry is keyed by
100
+ # owning agent anyway, so one host instance serves every session. What a preset
101
+ # chooses is whether its agent can collect and stop background work at all.
102
+ - id: tool-jobs
103
+ name: '@deepseek-ai/dsh-tool-jobs'
104
+
105
+ # ── skills ──────────────────────────────────────────────────────────────────
106
+
107
+ # The skill REGISTRY lives in the host composition and is layered per scope:
108
+ # these rows register into THIS preset's layer of it, so they need no realm.
109
+ # `skill-filesystem` contributes local-root discovery for agents on this preset, and
110
+ # `tool-skill` gives them the catalog and loader; the merged catalog also
111
+ # carries whatever the deployment registered globally (repository plugins).
112
+ #
113
+ # `customSkillDirs` 借的是官方**创造模式**自带的那四份 skill
114
+ # (`agent-experience` / `cordis-plugin-development` / `editing-cordis-compositions` /
115
+ # `cordis-composition-reference`):它们随 `@deepseek-ai/dsh-agent-preset` 出货,
116
+ # 创造模式用下面这条完全相同的表达式挂它们(见
117
+ # `@deepseek-ai/dsh-web-app/presets/cordis.patch.yml` 的 `skill-filesystem` 行)。
118
+ #
119
+ # 为什么 Fly 要借:Fly 的定位就是"用 DSH 扩展 DSH"——本仓库的装配(手写 `- insert:`
120
+ # 补丁 + `fly-bundle.mjs` 打包)与官方创造模式的运行时路径是**同一条**(preset registry
121
+ # 的 README:新建 preset 只能是 bundle 补丁 + 装上 profile)。这四份 skill 是上游对那条
122
+ # 路径的说明书,且随包更新;我们自己的 `docs/analysis/dsh-plugin-composition-rules.md`
123
+ # 是它的手工版本。**门禁**:`acceptance fly-shell` 在真会话的 `/` 菜单里按名过滤出它们
124
+ # (`/cordis` 与 `/agent-experience` 都要命中、乱敲一个名字必须 0 行)——只声明不生效会红。
125
+ #
126
+ # 表达式逐字照抄,别"简化":`baseUrl` 是 Loader 求值 `!!js` 时的配置基准(app-boot:
127
+ # `ctx.baseUrl = new URL('.', pathToFileURL(filename)).href`),`createRequire(baseUrl)` 从
128
+ # **profile 目录**向上找 `@deepseek-ai/dsh-agent-preset`(它在 `profiles/node_modules` 里,
129
+ # dev 与打包两条路都把引擎闭包铺在那儿),所以不需要新加依赖。
130
+ - id: skill-filesystem
131
+ name: '@deepseek-ai/dsh-skill-filesystem'
132
+ config:
133
+ customSkillDirs:
134
+ - !!js process.getBuiltinModule('node:path').join(process.getBuiltinModule('node:path').dirname(process.getBuiltinModule('node:module').createRequire(baseUrl).resolve('@deepseek-ai/dsh-agent-preset/package.json')), 'skills')
135
+
136
+ - id: tool-skill
137
+ name: '@deepseek-ai/dsh-tool-skill'
138
+
139
+ # ── goals ───────────────────────────────────────────────────────────────────
140
+
141
+ # The goal service and session driver stay on the host plane, where the Gateway
142
+ # can resolve them. The human command and model-facing tool register into this
143
+ # preset's scoped layers.
144
+ - id: command-goal
145
+ name: '@deepseek-ai/dsh-command-goal'
146
+
147
+ - id: tool-goal
148
+ name: '@deepseek-ai/dsh-tool-goal'
149
+
150
+ # ── plan mode ───────────────────────────────────────────────────────────────
151
+
152
+ # Plan state is per-agent by nature, so an entry-local realm is not a
153
+ # workaround here — it is the correct lifetime.
154
+ - id: planning
155
+ name: cordis:group
156
+ group: true
157
+ isolate:
158
+ planMode: true
159
+ config:
160
+ - id: plan-mode
161
+ name: '@deepseek-ai/dsh-plan-mode'
162
+ config:
163
+ section: |
164
+ You are in plan mode. Stay in plan mode until exit_plan_mode succeeds or the user switches the session mode. Imperative language to implement changes means plan the implementation, not execute it. A user's conversational agreement — including an answer confirming something you asked — approves nothing and does not end plan mode; fold the confirmed decision into the plan and submit it through exit_plan_mode.
165
+
166
+ Explore first. Use non-mutating reads, searches, static analysis, and checks to ground the plan in the actual repository. Do not edit or write files, change configuration, run formatters or code generation that rewrites tracked files, commit, or otherwise carry out the plan. Prefer existing functions and patterns over new machinery.
167
+
168
+ The tool catalog stays the same across modes for request-cache stability. These plan-mode rules override any later tool description or guidance that suggests using mutation tools; those tools remain listed to keep the tool catalog unchanged. Do not use todo_write to track this planning phase: it tracks implementation after an approved plan, while the plan itself belongs in exit_plan_mode.
169
+
170
+ Resolve discoverable facts by inspection. Use ask_user_question only for user-owned choices or material ambiguity that inspection cannot answer. Do not ask the user where code lives or how current behavior works when you can find out.
171
+
172
+ Make the plan decision-complete: state the goal and success criteria; group implementation changes by subsystem; identify public API, schema, and data-flow changes; cover edge cases, failure modes, tests, acceptance criteria, and explicit assumptions. Keep it concise enough to review but detailed enough that another engineer can implement it without making design decisions.
173
+
174
+ When ready, call exit_plan_mode with the complete plan markdown, starting with a # title. Make exit_plan_mode the only and final tool call in that assistant response: it presents the plan for approval, and implementation begins only in a later step after approval. Do not paste the final plan as a plain reply or ask "should I proceed?" through prose or ask_user_question. If review rejects it, incorporate the feedback and present again. If the review channel is unavailable or aborted, stay in plan mode and ask the user to switch modes manually; do not proceed with implementation.
175
+
176
+ # ── compaction ──────────────────────────────────────────────────────────────
177
+
178
+ # `compaction-basic` reads `toolResultPrune` through `ctx.get`, so the pruner must
179
+ # share this realm rather than sit outside it.
180
+ #
181
+ # `tokenMeter` is deliberately NOT in this realm: the meter stays on the HOST
182
+ # plane, and the rows here resolve that one instance. It takes no configuration,
183
+ # keys every fold by Session, and owns the context-meter projection units the
184
+ # browser reads for every session — behind a realm those units would come and go
185
+ # with whichever presets happen to be mounted. What a preset chooses is whether
186
+ # its agent compacts at all, which is `compaction-basic` below.
187
+ - id: compaction
188
+ name: cordis:group
189
+ group: true
190
+ isolate:
191
+ compaction: true
192
+ toolResultPruner: true
193
+ config:
194
+ - id: compaction-basic
195
+ name: '@deepseek-ai/dsh-compaction-basic'
196
+
197
+ - id: command-compact
198
+ name: '@deepseek-ai/dsh-command-compact'
199
+
200
+ - id: tool-result-pruner
201
+ name: '@deepseek-ai/dsh-compaction-tool-result-pruner'
202
+ config:
203
+ thresholdChars: 8192
204
+ headChars: 4096
205
+ tailChars: 1024
206
+
207
+ # ── delegation and workflows ────────────────────────────────────────────────
208
+
209
+ # The `subagents` registry and its spawn/fork backends live in the HOST
210
+ # composition: the registry is a process singleton whose cross-session queries
211
+ # the api-proxy serves to the browser, and a provider name may only be
212
+ # registered once. This preset contributes the delegation TOOLS, which resolve
213
+ # that host registry.
214
+ #
215
+ # `workflows` is different — nothing outside an agent reads it — so every row
216
+ # that reaches it shares one entry-local realm here, and a consumer left
217
+ # outside would resolve a host registry this preset does not populate.
218
+ - id: delegation
219
+ name: cordis:group
220
+ group: true
221
+ isolate:
222
+ workflowEngine: true
223
+ config:
224
+ - id: tool-subagent-control
225
+ name: '@deepseek-ai/dsh-tool-subagent-control'
226
+
227
+ - id: tool-subagent-list-agents
228
+ name: '@deepseek-ai/dsh-tool-subagent-control/list-agents'
229
+
230
+ - id: tool-subagent
231
+ name: '@deepseek-ai/dsh-tool-subagent'
232
+ config:
233
+ provider: spawn
234
+ toolName: subagent
235
+ modelSelectionSettings: true
236
+ backgroundMode: continuable
237
+
238
+ # Fork omits model selection so provider/model stay equal to the parent and
239
+ # the inherited history remains eligible for KV Cache reuse. This preset
240
+ # keeps fork continuable; parent and child inherit the same messaging tool,
241
+ # while the parent id and return guidance follow the inherited history.
242
+ - id: tool-subagent-fork
243
+ name: '@deepseek-ai/dsh-tool-subagent'
244
+ config:
245
+ provider: fork
246
+ toolName: subagent_fork
247
+ backgroundMode: continuable
248
+
249
+ # Production dsh does not install these optional providers. Install the
250
+ # matching Bundle in this Profile and restart the Host, then copy this
251
+ # preset and remove `disabled` from the matching tool row. Host availability
252
+ # alone grants no tool.
253
+ - id: tool-subagent-codex
254
+ name: '@deepseek-ai/dsh-tool-subagent'
255
+ disabled: true
256
+ config:
257
+ provider: codex
258
+ toolName: subagent_codex
259
+ backgroundMode: one-shot
260
+ maxDepth: provider-managed
261
+
262
+ - id: tool-subagent-claude-code
263
+ name: '@deepseek-ai/dsh-tool-subagent'
264
+ disabled: true
265
+ config:
266
+ provider: claude-code
267
+ toolName: subagent_claude_code
268
+ backgroundMode: one-shot
269
+ maxDepth: provider-managed
270
+
271
+ - id: workflow-ptc
272
+ name: '@deepseek-ai/dsh-workflow-ptc'
273
+ config:
274
+ provider: spawn
275
+
276
+ - id: tool-workflow
277
+ name: '@deepseek-ai/dsh-tool-workflow'
278
+
279
+ - id: tool-ralph
280
+ name: '@deepseek-ai/dsh-tool-ralph'
281
+ config:
282
+ subagentProvider: spawn
283
+ maxRounds: 64
284
+
285
+ # ── remaining model-facing rows ─────────────────────────────────────────────
286
+
287
+ - id: tool-ask-user
288
+ name: '@deepseek-ai/dsh-tool-ask-user'
289
+
290
+ - id: tool-todo
291
+ name: '@deepseek-ai/dsh-tool-todo'
292
+ config:
293
+ allowParallelInProgress: true
294
+
295
+ # The `web` service and its search provider stay in the host composition; only
296
+ # the model-facing tool is per-session.
297
+ - id: tool-web
298
+ name: '@deepseek-ai/dsh-tool-web'
299
+ config:
300
+ fetch: true
301
+ searchTimeoutMs: 60000
302
+
303
+ # ── fly security tooling ─────────────────────────────────────────────────────
304
+
305
+ # Out-of-tree DSH Fly tool plugins. Like `tool-bash`/`tool-fs` above, each row
306
+ # registers model-facing tools into the HOST `tools` registry and provides
307
+ # nothing, so it needs no realm; it CONSUMES the host `shell` seam for sandboxed
308
+ # command execution (never node:child_process). The packages are installed as
309
+ # plain profile dependencies (they declare no `dsh.bundle`), and this preset is
310
+ # what mounts them per session.
311
+ #
312
+ # fly-recon registers BOTH a `tools/pre-execute` guard (deny unless
313
+ # FLY_ALLOW_RECON=1) and its two tools from one apply(), so it is a single row.
314
+ - id: tool-fly-binary
315
+ name: '@dsh-fly/dsh-plugin-fly-mode/tools/dsh-plugin-fly-binary/index.js'
316
+ - id: tool-fly-reverse
317
+ name: '@dsh-fly/dsh-plugin-fly-mode/tools/dsh-plugin-fly-reverse/index.js'
318
+ - id: tool-fly-pwn
319
+ name: '@dsh-fly/dsh-plugin-fly-mode/tools/dsh-plugin-fly-pwn/index.js'
320
+ - id: tool-fly-diag
321
+ name: '@dsh-fly/dsh-plugin-fly-mode/tools/dsh-plugin-fly-diag/index.js'
322
+ - id: tool-fly-recon
323
+ name: '@dsh-fly/dsh-plugin-fly-mode/tools/dsh-plugin-fly-recon/index.js'
324
+ # 客户端黑盒排查链(微信小程序实战沉淀):`bx_proxy` / `bx_flows` / `bx_diff` /
325
+ # `bx_doctor` / `bx_ca` / `bx_sysproxy` 六个工具 + 包内 `client-blackbox` skill 资产。
326
+ # 行形状与上面几个 `tool-fly-*` 完全一致(`id` + `name`,**不**写 `inject`):
327
+ # 声明面由包自己的 `export const inject` 决定(本包是 `['tools','shell','skills']`)。
328
+ # 为什么要在注释里点明 `skills`:skill provider 是在 `apply(ctx)` 里用
329
+ # `ctx.skills.registerProvider()` 注册的 —— 包上漏写 `skills`,引擎就不会把
330
+ # `ctx.skills` 交给它,apply 里那一步直接抛 ⇒ **整棵 preset 挂载被拒**(不是少一个
331
+ # skill,是整个 Fly 会话起不来)。门禁 `verify blackbox` 第 7/19 条同时盯
332
+ # "inject 恰好是这三项"与"preset 里有这一行"。
333
+ # 起停代理 / 主动探测 / 改系统代理走 `FLY_ALLOW_INTERCEPT=1` 授权门;只读面永远可用。
334
+ - id: tool-fly-blackbox
335
+ name: '@dsh-fly/dsh-plugin-fly-mode/tools/dsh-plugin-fly-blackbox/index.js'
336
+ # ── fly smart mode ───────────────────────────────────────────────────────────
337
+
338
+ # Smart 模式(docs/smart-mode-design.md):先设计、后执行、再验收的双模型工作流。
339
+ # 它只注册工具、自己不提供服务,所以和上面几行一样是普通行、不需要 realm;每个会话
340
+ # 的当前任务以 agent.session 为键记在插件闭包里,会话之间不串。除了九个工具,这一行还挂
341
+ # 纪律 section(`fly-smart:policy`)与宿主平面的 `/smart` 命令(官方 `/goal` 同款:
342
+ # 宿主 `commands` 注册表 + 本行 ctx 的 scoped layer),因此声明面是
343
+ # `inject = ['tools', 'commands', 'systemPrompt']` —— 少一个都会在 apply 里抛,
344
+ # 而抛 = 整棵 preset 挂载被拒(S6 根因,§12.6)。两个模型路由
345
+ # (brainRoute/handRoute)留给设置行配置。
346
+ - id: tool-fly-smart
347
+ name: dsh-plugin-fly-smart
348
+ config:
349
+ enabled: true
350
+ # 返工额度是**每阶段**的:一个阶段反复迭代不该把后面阶段的预算吃掉。额度耗尽不是强制
351
+ # 收尾 —— 门会把它交回用户(选「退回重做」=同意再加一个预算),详见 docs/smart-mode-design.md。
352
+ maxRework: 5
353
+ requireConsult: true
354
+
355
+ # ── 改自己:官方创造模式的能力 + Fly 的门 ───────────────────────────────────
356
+ #
357
+ # `present`:把工作区里的文件声明成「交付物」(官方 `@deepseek-ai/dsh-tool-present`)。宿主平面的
358
+ # `FILE_REFERENCE_PROMPT` 明确要求用它、而不是在回复里贴长文件;官方那两个 preset 都带这一行
359
+ # (`presets/cordis.patch.yml` 与 `presets/standard.patch.yml` 各一份,逐字相同),而我们此前没有 ——
360
+ # 尺子(`scripts/tests/preset-relation.spec.mjs`)把它记成 `DECLARED_MISSING`,所以它是一条**可见**的
361
+ # 偏差,而不是悄悄少一行。现在补齐:Fly 相对 `standard` 不再缺任何一行。
362
+ # 判据两面都断(`acceptance fly-shell`):mounted preset 里真的有这一行;并且把上游那个包真
363
+ # `apply()` 一遍 —— 注册出名为 `present` 的工具、`inject` 三个服务、配置不合法必须抛。
364
+ # 只断"行在"会漏掉"包解析不到/挂不上"这一半(那正是 preset 行最常见的失败形状)。
365
+ - id: present
366
+ name: '@deepseek-ai/dsh-tool-present'
367
+
368
+ # 这一段是"Fly 安全 × 官方创造模式"的交点。两者是同一个 registry 里的**兄弟**(同样的
369
+ # `dsh-agent-preset` 声明行、同一棵 profile 树,`packages/dsh-plugin-fly-plugins` 的面板里
370
+ # 并排显示):官方创造模式(preset `cordis`)= 标准 preset **加上"能改自己"的那两样**,
371
+ # 也就是下面这一行 cordis 组合工具与一行 plugin_manager。
372
+ #
373
+ # 我们的差异只在**门**上。创造模式那一层的授权面就是会话的沙箱模式 + 逐次审批 ——
374
+ # 而本机实测这两项是 `danger-full-access` + 审批 `never`,等于**没有门**;`plugin_manager`
375
+ # 能把包写进 profile、能让**会在宿主进程里跑起来**的代码落地,且跨会话存活。
376
+ # 所以 Fly 补一道自己的门:`packages/dsh-plugin-fly-guard`(默认全拒写入,只读面照旧;
377
+ # 人要显式给宿主设 `FLY_ALLOW_PROFILE_WRITE=1` 才放行)。这就是"Fly 安全是创造能力的护栏"。
378
+ #
379
+ # `@deepseek-ai/dsh-tool-cordis/host` 已经在宿主平面上注册过一次(`dsh-web-app` 的 patch
380
+ # 层,上游注释点名了这条重复 id 的坑),所以这里**只**挂 agent 半边。
381
+ - id: tool-cordis
382
+ name: '@deepseek-ai/dsh-tool-cordis'
383
+
384
+ # `disabled:` 那一行逐字照抄官方创造模式的同名行。判据:`profileContext` 由宿主提供
385
+ # (`dsh/lib/profile-boot-*.js` 里 `hostCtx.provide('profileContext', …)`),而会话上下文
386
+ # **看得见**宿主服务(反向不通,见 AGENTS.md 平面隔离那条),所以在 profile 里它恒为"启用";
387
+ # 在没有任何 profile 的裸上下文里它会自动关掉 —— 那里没有 `pluginManager` 服务,
388
+ # 硬挂会让**整棵 preset 挂载被拒**(不是少一个工具,是整个 Fly 会话起不来)。
389
+ - id: tool-plugin-manager
390
+ name: '@deepseek-ai/dsh-plugin-manager/tools'
391
+ disabled: !!js "!ctx.get('profileContext')"
392
+
393
+ # 这道门自己。它不注册任何工具(只挂 `tools/pre-execute` 的 waterfall),但仍是一行 preset 行:
394
+ # 门必须与它管的东西在同一个 scope 里(`inject: ['tools']`)。行 id 用 `tool-` 前缀不是口味问题 ——
395
+ # `scripts/lib/fly-profile.mjs` 的 `toolPackages` 是装配的唯一实现,门禁(含
396
+ # `verify-fly-profile.mjs` 的"preset 挂上全部 N 行")**从它派生**行名,凭喜好起名会让那条断言看不见这一行。
397
+ - id: tool-fly-guard
398
+ name: '@dsh-fly/dsh-plugin-fly-mode/tools/dsh-plugin-fly-guard/index.js'
399
+ # <<< fly-agent-preset
package/package.json CHANGED
@@ -1,6 +1,34 @@
1
1
  {
2
2
  "name": "@dsh-fly/dsh-plugin-fly-mode",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.3",
4
+ "description": "Fly 安全模式(agent preset `fly`)作为一个可安装的包:自带 7 个 Fly 工具(源码内联在包内 tools/,行表用本包子路径引用),并依赖单独发布的 dsh-plugin-fly-smart;装进任何 profile 后那里就能服务 fly preset。",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/ethanchen669/dsh-plugin-fly-mode.git"
10
+ },
11
+ "engines": {
12
+ "node": ">=20"
13
+ },
14
+ "files": [
15
+ "cordis.patch.yml",
16
+ "README.md",
17
+ "tools"
18
+ ],
19
+ "dsh": {
20
+ "bundle": {
21
+ "patch": "./cordis.patch.yml"
22
+ }
23
+ },
24
+ "scripts": {
25
+ "verify": "node scripts/verify.mjs"
26
+ },
27
+ "publishConfig": {
28
+ "registry": "https://registry.npmjs.org/",
29
+ "access": "public"
30
+ },
31
+ "dependencies": {
32
+ "dsh-plugin-fly-smart": "^0.1.0"
33
+ }
34
+ }