@dsh-cc/subagent-task 0.5.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/LICENSE +201 -0
- package/README.i18n.yaml +6 -0
- package/README.md +214 -0
- package/README.zh.md +100 -0
- package/lib/background-start.d.ts +207 -0
- package/lib/background-start.d.ts.map +1 -0
- package/lib/background-start.js +354 -0
- package/lib/background-start.js.map +1 -0
- package/lib/catalog.d.ts +99 -0
- package/lib/catalog.d.ts.map +1 -0
- package/lib/catalog.js +197 -0
- package/lib/catalog.js.map +1 -0
- package/lib/epoch-collector.d.ts +126 -0
- package/lib/epoch-collector.d.ts.map +1 -0
- package/lib/epoch-collector.js +243 -0
- package/lib/epoch-collector.js.map +1 -0
- package/lib/index.d.ts +62 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +143 -0
- package/lib/index.js.map +1 -0
- package/lib/preload-tools.d.ts +66 -0
- package/lib/preload-tools.d.ts.map +1 -0
- package/lib/preload-tools.js +101 -0
- package/lib/preload-tools.js.map +1 -0
- package/lib/registry.d.ts +49 -0
- package/lib/registry.d.ts.map +1 -0
- package/lib/registry.js +66 -0
- package/lib/registry.js.map +1 -0
- package/lib/resume-capture.d.ts +107 -0
- package/lib/resume-capture.d.ts.map +1 -0
- package/lib/resume-capture.js +232 -0
- package/lib/resume-capture.js.map +1 -0
- package/lib/sanitize-filter.d.ts +27 -0
- package/lib/sanitize-filter.d.ts.map +1 -0
- package/lib/sanitize-filter.js +95 -0
- package/lib/sanitize-filter.js.map +1 -0
- package/lib/strip-instructions.d.ts +47 -0
- package/lib/strip-instructions.d.ts.map +1 -0
- package/lib/strip-instructions.js +77 -0
- package/lib/strip-instructions.js.map +1 -0
- package/lib/suppress-settled.d.ts +45 -0
- package/lib/suppress-settled.d.ts.map +1 -0
- package/lib/suppress-settled.js +80 -0
- package/lib/suppress-settled.js.map +1 -0
- package/lib/tool.d.ts +49 -0
- package/lib/tool.d.ts.map +1 -0
- package/lib/tool.js +247 -0
- package/lib/tool.js.map +1 -0
- package/package.json +78 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright [yyyy] [name of copyright owner]
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
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/subagent/task/README.md
|
|
5
|
+
README.md: 2f41225a5a429d06b1c499a0f764797183ce6ab4
|
|
6
|
+
README.zh.md: 5388f67d88f9e8bec717ab5cb353e35e962de8b1
|
package/README.md
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# @dsh-cc/subagent-task
|
|
2
|
+
|
|
3
|
+
English | [中文](README.zh.md)
|
|
4
|
+
|
|
5
|
+
The Claude Code-compatible **Task tool** and **per-workspace subagent catalog** for the
|
|
6
|
+
DeepSeek Harness. It mounts:
|
|
7
|
+
|
|
8
|
+
- the `subagent_fork` tool (CC display name `Task`) with `subagent_type` dispatch over the
|
|
9
|
+
session workspace's `.claude/agents` definitions;
|
|
10
|
+
- the `Available subagents` system-prompt section, rendered per workspace;
|
|
11
|
+
- the reserved tool names (`subagent`, `workflow`) that keep disabled harness rows
|
|
12
|
+
restrictable;
|
|
13
|
+
- a pre-step strip listener that removes the harness `agent-instructions` workspace
|
|
14
|
+
baseline (CLAUDE.md / AGENTS.md) from delegated Task children.
|
|
15
|
+
|
|
16
|
+
The `ccModelRoutes` service (from `@dsh-cc/model-aliases`) supplies the spawn-time
|
|
17
|
+
alias resolver; when it is absent, every child inherits its parent's route (the builtin
|
|
18
|
+
fallback).
|
|
19
|
+
|
|
20
|
+
## What it is
|
|
21
|
+
|
|
22
|
+
Claude Code's `Task` tool lets the main agent delegate to a named subagent
|
|
23
|
+
(`subagent_type`, e.g. `deep-reasoner`) defined in `.claude/agents`, and the runner loads
|
|
24
|
+
that agent's own system prompt, model, and tool restriction. Historically the DeepSeek
|
|
25
|
+
Harness only had a generic fork (`description`/`prompt`), so `subagent_type` dispatch was a
|
|
26
|
+
dead letter: the child only ever got the *hand-written role copy* the main model put in the
|
|
27
|
+
prompt, and the agent's `model: opus` alias never reached the backend route.
|
|
28
|
+
|
|
29
|
+
This package restores the real link. It discovers the CC `.claude/agents` definitions that
|
|
30
|
+
are visible from the **session's** working directory (not the host process cwd — a web host
|
|
31
|
+
serves many workspaces, so `~/.dsh/…` startup must still see `my-repo/.claude/agents`), and
|
|
32
|
+
turns the internal `subagent_fork` tool into a genuine subagent-type dispatcher.
|
|
33
|
+
|
|
34
|
+
## How dispatch works
|
|
35
|
+
|
|
36
|
+
Given a `Task(subagent_type, description, prompt)` call from a CC preset session:
|
|
37
|
+
|
|
38
|
+
1. **`subagent_type` omitted, blank, or `general-purpose`** → a **fresh spawn** of the
|
|
39
|
+
caller: the prompt text becomes the child's first user message, no definition
|
|
40
|
+
participates, no parent conversation is copied. Write a self-contained prompt.
|
|
41
|
+
2. **`subagent_type` equal to the reserved sentinel `fork`** → a conversation-inheriting
|
|
42
|
+
**fork** of the caller (Claude Code's `subagent_type: "fork"`): completed parent turns
|
|
43
|
+
seed the child; no definition participates. The sentinel is reserved and wins over a
|
|
44
|
+
workspace file of the same name — `.claude/agents/fork.md` is unreachable.
|
|
45
|
+
3. **A type that matches a definition** under the session cwd (`cwdOf` the assembling agent)
|
|
46
|
+
→ a `spawn` with:
|
|
47
|
+
- `persona` = the definition's `systemPrompt` (delivered as the child's system segment);
|
|
48
|
+
- the task text as the child's **first user message**;
|
|
49
|
+
- `agentOptions` = the alias-resolved `{ provider?, model? }` from
|
|
50
|
+
`ctx.get('ccModelRoutes').resolve(def.model)` (only provider/model fields that resolve
|
|
51
|
+
to a value are forwarded, so per-field inheritance never breaks);
|
|
52
|
+
- `toolFilter` = the definition's `toolRestriction` (allow/deny), **sanitized** of tool
|
|
53
|
+
names this composition no longer registers;
|
|
54
|
+
- `maxDepth` = 3 (matches the harness default; configurable).
|
|
55
|
+
4. **Any other type** (not found in the workspace) → an **error result** listing the
|
|
56
|
+
available types in this workspace (or noting the workspace defines none).
|
|
57
|
+
|
|
58
|
+
The dispatch is **foreground unless the child is explicitly or definition-pinned background**:
|
|
59
|
+
with `run_in_background` omitted, the run is foreground — the tool awaits the child to
|
|
60
|
+
completion, surfaces a non-`completed` stop reason as an error, and concatenates only the
|
|
61
|
+
`text` blocks of the child output — unless the definition pins `background: true`, in which
|
|
62
|
+
case the run backgrounds on omit. Explicit `run_in_background: false` wins over the pin and
|
|
63
|
+
forces foreground. An explicit `run_in_background: true` (or a pin on omit) starts the child
|
|
64
|
+
as a durable continuable background agent and returns promptly with its `agentId`.
|
|
65
|
+
|
|
66
|
+
### Tool-restriction sanitization and reserved names
|
|
67
|
+
|
|
68
|
+
When a definition's frontmatter narrows tools (e.g. `tools: Read, Task`), the allow/deny
|
|
69
|
+
lists are forced through the CC→harness translation and then checked against the **live**
|
|
70
|
+
set of names the tools registry knows (`ctx.tools.view(callingAgent).restrictableNames` —
|
|
71
|
+
registered and reserved names, read at execute time against the calling agent's scope so
|
|
72
|
+
standing-scope MCP reservations are visible). A name the registry does not know is dropped
|
|
73
|
+
with a warning; there is no static legal-names set, so mounted MCP tools and any future
|
|
74
|
+
registered row are accepted without code churn:
|
|
75
|
+
|
|
76
|
+
- **MCP public names.** An exact `mcp__<server>__<tool>` entry is kept as written — it must
|
|
77
|
+
be the tool's public name, including the deterministic 12-hex identity-hash suffix when
|
|
78
|
+
normalization truncated or replaced the name.
|
|
79
|
+
- **Server-level MCP wildcards.** `mcp__<server>` and `mcp__<server>__*` both expand to
|
|
80
|
+
every mounted tool of that server (`mcp__<server>__` prefix), so frontmatter survives
|
|
81
|
+
servers publishing new tools without naming hashed entries.
|
|
82
|
+
- **A bare `mcp__`** (no server segment) is dropped with an invalid-wildcard warning.
|
|
83
|
+
- **Auto-`ToolSearch`.** If the filter carried an `allow` list, any kept allow name is an
|
|
84
|
+
MCP tool, and the `ToolSearch` tool is itself mounted (restrictable), `ToolSearch` is
|
|
85
|
+
appended (deduped) — otherwise the child would hold MCP names with no load path. When
|
|
86
|
+
`ToolSearch` is not mounted it is never injected.
|
|
87
|
+
- **Spawn-time preload of explicit deferred MCP names.** An explicit `tools:` entry that is
|
|
88
|
+
still deferred (not yet registered) is activated through the duck-typed `ctx.toolSearch`
|
|
89
|
+
seam at spawn, BEFORE the child starts, on BOTH dispatch paths (foreground collect and
|
|
90
|
+
background) — activation is process-global, so every admitting agent's schema grows after
|
|
91
|
+
the spawn. Server-level wildcard entries (`mcp__<server>`, `mcp__<server>__*`) are
|
|
92
|
+
restrict-only: their expansions are never preloaded. Names the sanitized deny list
|
|
93
|
+
excludes, or that sanitize dropped as unknown, are never activated; already-registered
|
|
94
|
+
(eager) names are skipped silently. Outcomes surface in the Task result text
|
|
95
|
+
(`Preloaded deferred tools for child: …`, plus `Not preloaded: <name> (<reason>)` for
|
|
96
|
+
denied/unknown activations); with no `toolSearch` service mounted the step degrades to a
|
|
97
|
+
single warning and the spawn proceeds normally.
|
|
98
|
+
- **Unmounted names are dropped** with the standard `dropping unknown tool name …`
|
|
99
|
+
warning — including MCP names of servers that are not mounted.
|
|
100
|
+
- **An allow-list that matches nothing is deny-all, loudly.** If the filter carried an
|
|
101
|
+
`allow` list and sanitization left zero names, the emitted filter is `{ allow: [] }`
|
|
102
|
+
(the child runs with zero tools) with a warning naming the dropped originals — omitting
|
|
103
|
+
`allow` would instead widen the child to every tool. An emptied `deny` list is simply
|
|
104
|
+
omitted.
|
|
105
|
+
|
|
106
|
+
The internal tool name `subagent_fork` is registered by this package, and
|
|
107
|
+
`ctx.tools.reserve('subagent')` / `reserve('workflow')` keep those names in the restrictable
|
|
108
|
+
universe without exposing visible definitions (the CC frontmatter `Task` translation is
|
|
109
|
+
`['subagent', 'subagent_fork']`, so `subagent` must remain legal even though the harness
|
|
110
|
+
spawn row is disabled; `workflow` is reserved for the deferred workflow row). Because
|
|
111
|
+
sanitization checks the live registry rather than a static list, these reserved names and
|
|
112
|
+
every static CC name (`read`, `bash`, …) survive only when they are actually
|
|
113
|
+
reserved/registered — which they are in the cc preset. A definition that omits both
|
|
114
|
+
`tools` and `disallowedTools` passes no `toolFilter`, so the child inherits the full
|
|
115
|
+
parent tool view (including MCP schemas).
|
|
116
|
+
|
|
117
|
+
## Available subagents system-prompt section
|
|
118
|
+
|
|
119
|
+
A single global section (`cc:subagent-catalog`, order 110) serves every agent. Its text
|
|
120
|
+
callback receives the assembling agent through the assemble scope, derives that agent's cwd,
|
|
121
|
+
and renders:
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
## Available subagents
|
|
125
|
+
|
|
126
|
+
- deep-reasoner — reason through hard architecture and design problems
|
|
127
|
+
- fast-worker — execute a pre-approved mechanical plan
|
|
128
|
+
|
|
129
|
+
To delegate to one, pass its name as the `subagent_type` argument of the Task tool.
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Because the section text is composed synchronously but discovery is async, the first
|
|
133
|
+
assembly for an unknown workspace shows nothing, then `system-prompt/change` fires once
|
|
134
|
+
discovery lands and reassembly reveals the catalog. When a workspace defines no agents (or
|
|
135
|
+
there is no agent to scope to) the section renders an empty string and drops out of the
|
|
136
|
+
prompt. The catalog lists only file definitions — it deliberately does **not** enumerate seam
|
|
137
|
+
backend provider names (`fork`/`spawn`/`codex`/`claude-code`) as if they were addressable
|
|
138
|
+
agent types.
|
|
139
|
+
|
|
140
|
+
## Workspace instructions on Task children
|
|
141
|
+
|
|
142
|
+
The harness `agent-instructions` plugin injects the workspace CLAUDE.md / AGENTS.md
|
|
143
|
+
baseline as an `agent-instructions`-sourced user message on every session — including
|
|
144
|
+
Task children. This package mounts an `agent/pre-step` listener that strips that baseline
|
|
145
|
+
from delegated children (`delegationDepth > 0`):
|
|
146
|
+
|
|
147
|
+
- A delegated child receives only the enter batch and pending inbox messages that are not
|
|
148
|
+
`agent-instructions`-sourced; its persona remains the agent-file `systemPrompt` (or the
|
|
149
|
+
deployment persona for `general-purpose`).
|
|
150
|
+
- Fork children still inherit any CLAUDE.md already in the parent seed — the listener only
|
|
151
|
+
skips a *fresh* child scan; parent history is never rewritten.
|
|
152
|
+
- This is an intentional deviation from Claude Code, whose custom subagents **do** load
|
|
153
|
+
CLAUDE.md (Explore/Plan in CC skip it). dsh-cc applies the skip to every Task child
|
|
154
|
+
because the dsh-cc repo CLAUDE.md is orchestrator policy, not a worker contract.
|
|
155
|
+
- Residual: the harness still reads the instruction files from disk on the child's behalf;
|
|
156
|
+
they just never enter the child's model-visible batch.
|
|
157
|
+
|
|
158
|
+
## Mounting
|
|
159
|
+
|
|
160
|
+
Mounted by the `cc` preset's `tool-task` row (`@dsh-cc/subagent-task`) inside the
|
|
161
|
+
`cc-services` group, alongside `cc-model-routes` (`@dsh-cc/model-aliases`) which
|
|
162
|
+
supplies the alias resolver. The cc preset **disables** the harness `tool-subagent` and
|
|
163
|
+
`tool-subagent-fork` rows in favour of this tool so there is no double registration of the
|
|
164
|
+
`subagent_fork` name.
|
|
165
|
+
|
|
166
|
+
## Known limits
|
|
167
|
+
|
|
168
|
+
- **Cold resume drops extra `agentOptions`.** Background (continuable) dispatch exists —
|
|
169
|
+
`run_in_background: true` or a `background: true` definition pin — but cold resume restores
|
|
170
|
+
`persona`/`toolFilter`/model route only and drops every other `agentOptions` field
|
|
171
|
+
(alias-stamped `reasoningEffort`, `maxTokens`). See the parity matrix for the full
|
|
172
|
+
background contract (drain on parent exit, no `outputFile`, fork + background rejected).
|
|
173
|
+
- **Process-level discovery cache.** The registry caches per workspace root for the process
|
|
174
|
+
lifetime and does not watch the filesystem. Editing a `.claude/agents` definition takes
|
|
175
|
+
effect on the next session for a workspace whose cache entry has not yet been created, and
|
|
176
|
+
on process restart otherwise. mtime-based invalidation is a follow-up.
|
|
177
|
+
- **No plugin-agent dispatch (v1).** Only file definitions under `.claude/agents` are
|
|
178
|
+
dispatched. Seam plugin agents (`AgentProvider`) are not addressed by `subagent_type` in v1
|
|
179
|
+
(their start contract does not carry the task text and their capability flags would reject
|
|
180
|
+
`maxDepth`) — see the parity matrix.
|
|
181
|
+
- **Reserved type names.** `general-purpose` and `fork` are sentinels, not file types. A
|
|
182
|
+
workspace file `.claude/agents/fork.md` is unreachable; `subagent_type: "fork"` always
|
|
183
|
+
means inherit completed parent turns.
|
|
184
|
+
- **Instruction files are still scanned.** The strip happens after the harness
|
|
185
|
+
`agent-instructions` plugin has read the workspace CLAUDE.md / AGENTS.md from disk and
|
|
186
|
+
injected them; this listener only keeps them out of the child's model-visible batch, so
|
|
187
|
+
the disk scan itself cannot be prevented without changing the harness. A fork child's
|
|
188
|
+
parent seed is never rewritten, so CLAUDE.md already in the seed is inherited.
|
|
189
|
+
|
|
190
|
+
## API
|
|
191
|
+
|
|
192
|
+
- `apply(ctx)` — cordis plugin entry (plugin id `cc-subagent-task`); safe when either the
|
|
193
|
+
tools or the system-prompt seam is absent.
|
|
194
|
+
- `AgentRegistry` (`./registry`) — per-workspace definition cache (`ensure` / `list` /
|
|
195
|
+
`resolve`), lazily loading `loadClaudeCodeAgents(root)` (user layer + project layer,
|
|
196
|
+
project shadows user).
|
|
197
|
+
- `registerTaskTool` / `TASK_TOOL` (`./tool`) — register the `subagent_fork` Task tool.
|
|
198
|
+
- `mountAgentCatalog` / `CATALOG_SECTION_NAME` / `CATALOG_SECTION_ORDER` (`./catalog`) —
|
|
199
|
+
mount the `Available subagents` section.
|
|
200
|
+
- `mountStripWorkspaceInstructions` / `isDelegated` / `isAgentInstructions`
|
|
201
|
+
(`./strip-instructions`) — mount (or classify for) the pre-step strip of the harness
|
|
202
|
+
`agent-instructions` workspace baseline on delegated Task children.
|
|
203
|
+
|
|
204
|
+
## Non-goals
|
|
205
|
+
|
|
206
|
+
- Treating omitted `run_in_background` as background as a session policy (the Claude Code
|
|
207
|
+
interactive omit=background rule); dsh-cc stays foreground on omit unless the definition
|
|
208
|
+
pins `background: true`.
|
|
209
|
+
- In-flight promotion of a running foreground Task to background (TUI Ctrl+B) — a follow-up,
|
|
210
|
+
not a limitation of the package's existence.
|
|
211
|
+
- Seam plugin-agent dispatch.
|
|
212
|
+
- CC frontmatter `permissionMode` / `isolation` / `memory` / `effort` projection onto the
|
|
213
|
+
child (the loader parses them, v1 does not consume them).
|
|
214
|
+
- `registerBaseAgents` in cc-shell (base-agent discovery moved here; see the cc-shell README).
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# @dsh-cc/subagent-task
|
|
2
|
+
|
|
3
|
+
[English](README.md) | 中文
|
|
4
|
+
|
|
5
|
+
面向 DeepSeek Harness 的 **Claude Code 兼容 Task 工具** 与 **按工作区隔离的 subagent 目录**。它挂载:
|
|
6
|
+
|
|
7
|
+
- 内部工具名 `subagent_fork`(CC 显示名 `Task`),以 `subagent_type` 对会话工作区的 `.claude/agents` 定义做派发;
|
|
8
|
+
- `Available subagents` 系统提示词 section(**按工作区**渲染);
|
|
9
|
+
- 保留的工具名(`subagent`、`workflow`),使被禁用的 harness 行仍可被 restrict;
|
|
10
|
+
- 一个 pre-step 剥离监听器,把 harness `agent-instructions` 的工作区基线(CLAUDE.md / AGENTS.md)从被委派的 Task child 中移除。
|
|
11
|
+
|
|
12
|
+
`ccModelRoutes` 服务(来自 `@dsh-cc/model-aliases`)提供派发时的别名解析器;当其缺席时,每个 child 继承父路由(内置 fallback)。
|
|
13
|
+
|
|
14
|
+
## 是什么
|
|
15
|
+
|
|
16
|
+
Claude Code 的 `Task` 工具允许主代理按 `subagent_type`(如 `deep-reasoner`)委派给 `.claude/agents` 里定义的具名 subagent,运行时加载该 agent 自己的 system prompt、model 与工具限制。历史上 DeepSeek Harness 只有通用 fork(`description`/`prompt`),因此 `subagent_type` 派发形同虚设:child 只能拿到主模型写在 prompt 里的**手写角色文字**,而该 agent 的 `model: opus` alias 也从未抵达后端路由。
|
|
17
|
+
|
|
18
|
+
本包恢复真实链路。它发现从**会话**工作目录(而非宿主进程 cwd——web 宿主同时服务多个工作区,从 `~/.dsh/…` 启动也必须看到 `my-repo/.claude/agents`)可见的 CC `.claude/agents` 定义,并把内部 `subagent_fork` 工具变成一个真正的 subagent-type 派发器。
|
|
19
|
+
|
|
20
|
+
## 派发机制
|
|
21
|
+
|
|
22
|
+
给定 CC preset 会话中的一次 `Task(subagent_type, description, prompt)` 调用:
|
|
23
|
+
|
|
24
|
+
1. **`subagent_type` 省略、空白或为 `general-purpose`** → **全新 spawn**:prompt 文本成为 child 的首条 user message,无定义参与,不拷贝父对话。prompt 必须自包含。
|
|
25
|
+
2. **`subagent_type` 等于保留哨兵 `fork`** → 继承对话的 **fork**(Claude Code 的 `subagent_type: "fork"`):父已完成轮次作为 seed,无定义参与。哨兵优先于同名文件,`.claude/agents/fork.md` 不可达。
|
|
26
|
+
3. **命中会话 cwd(`cwdOf` 组装 agent)下的定义** → 以 `spawn` 启动并携带:
|
|
27
|
+
- `persona` = 定义的 `systemPrompt`(作为 child 的系统段下发);
|
|
28
|
+
- 任务文本作为 child 的**首条 user message**;
|
|
29
|
+
- `agentOptions` = 来自 `ctx.get('ccModelRoutes').resolve(def.model)` 的别名解析结果 `{ provider?, model? }`(只透传解析到值的 provider/model 字段,绝不破坏按字段继承);
|
|
30
|
+
- `toolFilter` = 定义的 `toolRestriction`(allow/deny),**消毒**掉本组合已不再注册的工具名;
|
|
31
|
+
- `maxDepth` = 3(与 harness 默认一致;可配置)。
|
|
32
|
+
4. **其它类型**(工作区内找不到)→ **报错结果**,附带本工作区可用类型清单(或说明本工作区未定义任何 agent)。
|
|
33
|
+
|
|
34
|
+
派发规则是**前台,除非显式指定或定义钉死了后台**:`run_in_background` 缺省时运行是前台——工具等待 child 跑完,非 `completed` 的 stop reason 以错误浮出,child 输出只拼接 `text` 块——除非定义钉了 `background: true`,此时缺省即后台。显式 `run_in_background: false` 覆盖钉死,强制前台。显式 `run_in_background: true`(或钉死时缺省)则把 child 作为 durable continuable 后台 agent 启动,并立即返回其 `agentId`。
|
|
35
|
+
|
|
36
|
+
### 工具限制消毒与保留名
|
|
37
|
+
|
|
38
|
+
当定义 frontmatter 收窄工具(如 `tools: Read, Task`)时,allow/deny 清单会强制经过 CC→harness 翻译,再对照工具注册表**实时**已知的名集合(`ctx.tools.view(callingAgent).restrictableNames`——已注册与已保留名的并集,在 execute 时按调用 agent 的 scope 读取,因此 standing-scope 上的 MCP 保留名可见)做校验。注册表不认识的名会被丢弃并告警;这里没有静态合法名集合,因此已挂载的 MCP 工具和未来新增的注册行都无需改代码即可通过:
|
|
39
|
+
|
|
40
|
+
- **MCP 公开名。** 精确的 `mcp__<server>__<tool>` 原样保留——必须用该工具的公开名,包括名字被规范化截断/替换时追加的 12 位十六进制确定性 hash 后缀。
|
|
41
|
+
- **server 级 MCP 通配。** `mcp__<server>` 与 `mcp__<server>__*` 都会展开为该 server 已挂载的全部工具(`mcp__<server>__` 前缀),frontmatter 因此不必逐个点名带 hash 的条目也能在 server 发布新工具后继续生效。
|
|
42
|
+
- **裸 `mcp__`**(无 server 段)被丢弃并给出 invalid-wildcard 告警。
|
|
43
|
+
- **自动带上 `ToolSearch`。** 若过滤器带有 `allow` 清单、保留下来的 allow 名中有 MCP 工具、且 `ToolSearch` 工具本身已挂载(可限制),则追加 `ToolSearch`(去重)——否则 child 手握 MCP 名却没有任何加载路径。`ToolSearch` 未挂载时绝不注入。
|
|
44
|
+
- **spawn 时预激活显式列出的延后 MCP 名。** `tools:` 中显式点名、且仍处于延后(未注册)状态的 MCP 名,会在 spawn 时、child 启动之前,经 duck-typed `ctx.toolSearch` seam 激活——前台 collect 与后台两条派发路径都会执行,激活是进程全局的(spawn 之后每个可接纳该工具的 agent 的 schema 都会变大)。server 级通配(`mcp__<server>`、`mcp__<server>__*`)仅用于限制、绝不预激活;被消毒 deny 清单排除或被消毒丢弃的名永不激活,已注册(急加载)的名静默跳过。结果浮现在 Task 结果文本中(`Preloaded deferred tools for child: …`,以及 `Not preloaded: <名>(<原因>)`);未挂载 `toolSearch` 服务时只告警一次、照常 spawn。
|
|
45
|
+
- **未挂载的名被丢弃**,给出标准 `dropping unknown tool name …` 告警——包括未挂载 server 的 MCP 名。
|
|
46
|
+
- **匹配不到任何工具的 allow 清单 = 醒目的 deny-all。** 若过滤器带有 `allow` 清单而消毒后一个名都不剩,产出的过滤器是 `{ allow: [] }`(child 以零工具运行)并告警列出被丢弃的原始名——省略 `allow` 反而会把 child 放宽到全部工具。被清空的 `deny` 清单则直接省略。
|
|
47
|
+
|
|
48
|
+
本包注册内部工具名 `subagent_fork`,并经 `ctx.tools.reserve('subagent')` / `reserve('workflow')` 把这些名放进可限制 universe 而不暴露可见定义(CC frontmatter `Task` 的翻译是 `['subagent', 'subagent_fork']`,故即使 harness spawn 行被禁,`subagent` 也必须保持合法;`workflow` 为延后的 workflow 行保留)。由于消毒对照的是实时注册表而非静态清单,这些保留名和每个静态 CC 名(`read`、`bash` 等)只有在真正被保留/注册时才会存活——在 cc preset 中它们正是如此。定义同时省略 `tools` 与 `disallowedTools` 时不传 `toolFilter`,child 继承父的完整工具面(含 MCP schema)。
|
|
49
|
+
|
|
50
|
+
## Available subagents 系统提示词 section
|
|
51
|
+
|
|
52
|
+
一个全局 section(`cc:subagent-catalog`,order 110)服务所有 agent。其 text 回调通过 assemble scope 拿到组装 agent,推导其 cwd,并渲染:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
## Available subagents
|
|
56
|
+
|
|
57
|
+
- deep-reasoner — reason through hard architecture and design problems
|
|
58
|
+
- fast-worker — execute a pre-approved mechanical plan
|
|
59
|
+
|
|
60
|
+
To delegate to one, pass its name as the `subagent_type` argument of the Task tool.
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
由于 section 文本是同步组装的而发现是异步的,未知工作区的首次组装会显示空,随后 discovery 落地后触发 `system-prompt/change`,重组即显示目录。当工作区未定义任何 agent(或没有可 scope 的 agent)时,section 渲染空串并从提示词中消失。目录只列**文件定义**——刻意**不**把 seam 后端 provider 名(`fork`/`spawn`/`codex`/`claude-code`)当作可寻址的 agent 类型来枚举。
|
|
64
|
+
|
|
65
|
+
## Task child 上的工作区指令
|
|
66
|
+
|
|
67
|
+
harness 的 `agent-instructions` 插件会在**每个**会话(包括 Task child)注入工作区 CLAUDE.md / AGENTS.md 基线,作为一条 `agent-instructions` 来源的 user message。本包挂载一个 `agent/pre-step` 监听器,为被委派的 child(`delegationDepth > 0`)剥离该基线:
|
|
68
|
+
|
|
69
|
+
- 被委派的 child 收到的 enter 批次与待处理 inbox 消息中不再包含 `agent-instructions` 来源的消息;其 persona 仍是 agent 文件的 `systemPrompt`(`general-purpose` 则是部署 persona)。
|
|
70
|
+
- fork child 仍继承父 seed 中已有的 CLAUDE.md——监听器只跳过*全新* child 的扫描,从不改写父历史。
|
|
71
|
+
- 这是对 Claude Code 的**有意偏离**:CC 的自定义 subagent **会**加载 CLAUDE.md(CC 的 Explore/Plan 则跳过)。dsh-cc 对所有 Task child 施加跳过,因为 dsh-cc 仓库的 CLAUDE.md 是编排者策略,而非 worker 契约。
|
|
72
|
+
- 残余: harness 仍会代 child 从磁盘读取指令文件,只是它们不再进入 child 的模型可见批次。
|
|
73
|
+
|
|
74
|
+
## 挂载
|
|
75
|
+
|
|
76
|
+
由 `cc` preset 的 `tool-task` 行(`@dsh-cc/subagent-task`)挂载在 `cc-services` 组内,旁边是提供别名解析器的 `cc-model-routes`(`@dsh-cc/model-aliases`)。cc preset **禁用** harness 的 `tool-subagent` 与 `tool-subagent-fork` 两行以改用本工具,避免 `subagent_fork` 名被重复注册。
|
|
77
|
+
|
|
78
|
+
## 已知限制
|
|
79
|
+
|
|
80
|
+
- **冷恢复丢弃其余 `agentOptions`。** 后台(continuable)派发已存在——`run_in_background: true` 或定义钉 `background: true`——但冷恢复只还原 `persona`/`toolFilter`/模型路由,丢弃其余全部 `agentOptions` 字段(别名标记的 `reasoningEffort`、`maxTokens`)。完整后台契约(父退出 drain、无 `outputFile`、fork + 后台被拒)见 parity matrix。
|
|
81
|
+
- **进程级发现缓存。** 注册表按工作区 root 缓存整个进程生命周期,不监听文件系统。编辑 `.claude/agents` 定义:对缓存条目尚未创建的工作区在下次会话生效,否则在进程重启后生效。基于 mtime 的失效刷为 follow-up。
|
|
82
|
+
- **v1 不做插件 agent 派发。** 只派发 `.claude/agents` 下的文件定义。seam 插件 agent(`AgentProvider`)在 v1 不被 `subagent_type` 寻址(其 start 契约不携带任务正文,且 capability 标志会拒绝 `maxDepth`)——见 parity matrix。
|
|
83
|
+
- **保留类型名。** `general-purpose` 与 `fork` 是哨兵,不是文件类型。工作区文件 `.claude/agents/fork.md` 不可达;`subagent_type: "fork"` 永远表示继承父已完成轮次。
|
|
84
|
+
- **指令文件仍会被扫描。** 剥离发生在 harness `agent-instructions` 插件已从磁盘读取工作区 CLAUDE.md / AGENTS.md 并注入之后;本监听器只把它们挡在 child 的模型可见批次之外,不改 harness 就无法阻止磁盘扫描。fork child 的父 seed 从不改写,seed 中已有的 CLAUDE.md 会被继承。
|
|
85
|
+
|
|
86
|
+
## API
|
|
87
|
+
|
|
88
|
+
- `apply(ctx)` — cordis 插件入口(插件 id `cc-subagent-task`);tools 或 system-prompt seam 任一缺席时也安全。
|
|
89
|
+
- `AgentRegistry`(`./registry`)— 按工作区的定义缓存(`ensure` / `list` / `resolve`),惰性加载 `loadClaudeCodeAgents(root)`(用户层 + 项目层,项目遮蔽用户)。
|
|
90
|
+
- `registerTaskTool` / `TASK_TOOL`(`./tool`)— 注册 `subagent_fork` Task 工具。
|
|
91
|
+
- `mountAgentCatalog` / `CATALOG_SECTION_NAME` / `CATALOG_SECTION_ORDER`(`./catalog`)— 挂载 `Available subagents` section。
|
|
92
|
+
- `mountStripWorkspaceInstructions` / `isDelegated` / `isAgentInstructions`(`./strip-instructions`)— 挂载(或为测试分类)pre-step 剥离监听器,把 harness `agent-instructions` 工作区基线从被委派的 Task child 中移除。
|
|
93
|
+
|
|
94
|
+
## 非目标
|
|
95
|
+
|
|
96
|
+
- 把缺省的 `run_in_background` 视为后台的会话级策略(Claude Code 交互式的 omit=background 规则);dsh-cc 在缺省时保持前台,除非定义钉了 `background: true`。
|
|
97
|
+
- 正在运行的前台 Task 的在途转后台(TUI Ctrl+B)——follow-up,而非本包存在性上的限制。
|
|
98
|
+
- seam 插件 agent 派发。
|
|
99
|
+
- 把 CC frontmatter 的 `permissionMode` / `isolation` / `memory` / `effort` 投影到 child(loader 会解析,v1 不消费)。
|
|
100
|
+
- cc-shell 里的 `registerBaseAgents`(base agent 发现迁至此处;见 cc-shell README)。
|