dsh-subagent-profile 0.3.3 → 0.3.4

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.
@@ -0,0 +1,139 @@
1
+ // lib/core/profile-directory.mjs — 派发方案目录的单一数据源。
2
+ // profileSectionText(模型可见段)与 profileSnapshotOf(决策轨迹记录面)都从
3
+ // 本模块的 profileDirectoryRows 派生,构造保证「模型看到 ≡ 记录面」的 id、顺序与
4
+ // 字段集。未来 F 数据层注入 avg_cost / success_rate 只改这里一处。
5
+ //
6
+ // 仅依赖 lib/core/pure.mjs(tierSortKey);无 @deepseek-ai 依赖,可被 bare-CI
7
+ // 单测直接 import。
8
+
9
+ import { tierSortKey } from './pure.mjs';
10
+
11
+ // 决策输入快照阈值:profiles_snapshot 条目数与 description 截断长度。
12
+ const MAX_PROFILE_SNAPSHOT_ENTRIES = 6;
13
+ const PROFILE_DESC_CHARS = 80;
14
+
15
+ function snapshotEntry(row, maxDesc) {
16
+ const description = typeof row.description === 'string' ? row.description : '';
17
+ return {
18
+ id: row.id,
19
+ ...(description !== '' ? { description: description.length > maxDesc ? `${description.slice(0, maxDesc)}…` : description } : {}),
20
+ ...(typeof row.preset === 'string' && row.preset !== '' ? { preset: row.preset } : {}),
21
+ ...(typeof row.model === 'string' && row.model !== '' ? { model: row.model } : {}),
22
+ ...(typeof row.provider === 'string' && row.provider !== '' ? { provider: row.provider } : {}),
23
+ ...(typeof row.tokenTier === 'string' && row.tokenTier !== '' ? { tokenTier: row.tokenTier } : {}),
24
+ ...(typeof row.avgCost === 'number' && Number.isFinite(row.avgCost) ? { avgCost: row.avgCost } : {}),
25
+ ...(typeof row.successRate === 'number' && Number.isFinite(row.successRate) ? { successRate: row.successRate } : {}),
26
+ };
27
+ }
28
+
29
+ // 模型可见 profile 目录快照:输入为 profileDirectoryRows 的结构化行。description
30
+ // 截断、条目数截到 maxEntries;chosenId 超出 maxEntries 时并入该条并打
31
+ // chosenOutsideSnapshot(37b:截断不得制造审计空洞)。
32
+ export function profileSnapshotOf(profiles, { maxEntries = MAX_PROFILE_SNAPSHOT_ENTRIES, maxDesc = PROFILE_DESC_CHARS, chosenId } = {}) {
33
+ const list = Array.isArray(profiles) ? profiles : [];
34
+ const full = [];
35
+ for (const row of list) {
36
+ if (row === null || typeof row !== 'object' || typeof row.id !== 'string' || row.id === '') continue;
37
+ if (row.enabled === false) continue;
38
+ full.push(snapshotEntry(row, maxDesc));
39
+ }
40
+ const entries = full.slice(0, maxEntries);
41
+ let truncated = full.length > maxEntries;
42
+ if (typeof chosenId === 'string' && chosenId !== '' && chosenId !== '(inline)' && !entries.some((e) => e.id === chosenId)) {
43
+ const chosen = full.find((e) => e.id === chosenId);
44
+ if (chosen !== undefined) {
45
+ entries.push({ ...chosen, chosenOutsideSnapshot: true });
46
+ truncated = true;
47
+ }
48
+ }
49
+ return { entries, truncated, total: full.length };
50
+ }
51
+
52
+ // store 兼容 createProfileStore 返回形态(含 profiles Map);也接受数组(测试与
53
+ // 非标准调用方)。只保留启用且 id 合法的方案;按 tokenTier cheap-first 稳定排序,
54
+ // tier 相同按 id 升序(确定性,不依赖 Map 插入序的跨运行差异)。
55
+ export function profileDirectoryRows(store) {
56
+ const source = store !== null && typeof store === 'object' && store.profiles !== undefined
57
+ ? [...store.profiles.values()]
58
+ : (Array.isArray(store) ? store : []);
59
+ return source
60
+ .filter((p) => p !== null && typeof p === 'object' && typeof p.id === 'string' && p.id !== '' && p.enabled !== false)
61
+ .sort((a, b) => tierSortKey(a.tokenTier) - tierSortKey(b.tokenTier) || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0))
62
+ .map((p) => ({
63
+ id: p.id,
64
+ description: typeof p.description === 'string' ? p.description : '',
65
+ ...(typeof p.preset === 'string' && p.preset !== '' ? { preset: p.preset } : {}),
66
+ ...(typeof p.model === 'string' && p.model !== '' ? { model: p.model } : {}),
67
+ ...(typeof p.provider === 'string' && p.provider !== '' ? { provider: p.provider } : {}),
68
+ ...(typeof p.tokenTier === 'string' && p.tokenTier !== '' ? { tokenTier: p.tokenTier } : {}),
69
+ ...(typeof p.avgCost === 'number' && Number.isFinite(p.avgCost) ? { avgCost: p.avgCost } : {}),
70
+ ...(typeof p.successRate === 'number' && Number.isFinite(p.successRate) ? { successRate: p.successRate } : {}),
71
+ }));
72
+ }
73
+
74
+
75
+ // 从 summaries.json 的 l1/l2 聚合为每个 profile 提取 { avgCost, successRate, n }。
76
+ // 匹配优先级:profile.model → L2 model 轴;profile.preset → L2 preset 轴。多个 L1
77
+ // 组共享同一轴值时按成本与部署量合并(avg_cost = Σestimated_cost / Σpriced;
78
+ // successRate = Σcompleted / Σdeployments)。无数据返回 null,调用方省略显示。
79
+ export function profileStatsFromSummaries(store, summaries) {
80
+ const rows = profileDirectoryRows(store);
81
+ const l2 = summaries !== null && typeof summaries === 'object' && summaries.l2 !== null && typeof summaries.l2 === 'object' ? summaries.l2 : {};
82
+ const byModel = new Map();
83
+ const byPreset = new Map();
84
+ for (const [key, group] of Object.entries(l2)) {
85
+ if (group === null || typeof group !== 'object') continue;
86
+ const modelMatch = /:model:([^|]+)$/.exec(key);
87
+ if (modelMatch) {
88
+ const arr = byModel.get(modelMatch[1]) ?? [];
89
+ arr.push(group);
90
+ byModel.set(modelMatch[1], arr);
91
+ continue;
92
+ }
93
+ const presetMatch = /:preset:([^|]+)$/.exec(key);
94
+ if (presetMatch) {
95
+ const arr = byPreset.get(presetMatch[1]) ?? [];
96
+ arr.push(group);
97
+ byPreset.set(presetMatch[1], arr);
98
+ }
99
+ }
100
+ const merge = (groups) => {
101
+ let deployments = 0;
102
+ let completed = 0;
103
+ let priced = 0;
104
+ let cost = 0;
105
+ for (const g of groups) {
106
+ deployments += Number.isFinite(g.deployments_total) ? g.deployments_total : 0;
107
+ completed += Number.isFinite(g.outcome?.completed) ? g.outcome.completed : 0;
108
+ priced += Number.isFinite(g.cost?.priced) ? g.cost.priced : 0;
109
+ cost += Number.isFinite(g.cost?.estimated_cost) ? g.cost.estimated_cost : 0;
110
+ }
111
+ if (deployments <= 0 && priced <= 0) return null;
112
+ return {
113
+ avgCost: priced > 0 ? Number((cost / priced).toFixed(4)) : null,
114
+ successRate: deployments > 0 ? Number((completed / deployments).toFixed(3)) : null,
115
+ n: deployments,
116
+ };
117
+ };
118
+ const out = new Map();
119
+ for (const row of rows) {
120
+ let stats = null;
121
+ if (typeof row.model === 'string' && row.model !== '') stats = merge(byModel.get(row.model) ?? []);
122
+ if (stats === null && typeof row.preset === 'string' && row.preset !== '') stats = merge(byPreset.get(row.preset) ?? []);
123
+ if (stats !== null) out.set(row.id, stats);
124
+ }
125
+ return out;
126
+ }
127
+
128
+ // 用 stats map 为目录行补 avgCost/successRate(F 数据层 join)。stats 为
129
+ // profileStatsFromSummaries 的返回值;行上已有 avgCost/successRate 时优先保留
130
+ // 显式值(store 侧/测试注入),stats 只补缺失。
131
+ export function applyProfileStats(rows, stats) {
132
+ const map = stats instanceof Map ? stats : new Map(Object.entries(stats ?? {}));
133
+ return rows.map((row) => ({
134
+ ...row,
135
+ ...(row.avgCost === undefined && map.get(row.id)?.avgCost !== null && map.get(row.id)?.avgCost !== undefined ? { avgCost: map.get(row.id).avgCost } : {}),
136
+ ...(row.successRate === undefined && map.get(row.id)?.successRate !== null && map.get(row.id)?.successRate !== undefined ? { successRate: map.get(row.id).successRate } : {}),
137
+ ...(map.get(row.id)?.n !== undefined ? { n: map.get(row.id).n } : {}),
138
+ }));
139
+ }
@@ -154,13 +154,14 @@ async function setupChild(childCtx, { parent, profile, swapPreset, delegated, re
154
154
  return { ...resolved, reasoningEffort: profile.reasoningEffort };
155
155
  });
156
156
  }
157
- // ⑥ Descriptor append inside the child's first turn(M4:descriptor 非空才 append)。
157
+ // ⑥ Descriptor append inside the child's first turn(descriptor 存在才 append;
158
+ // 核心注入的是对象(snapshotJsonValue 快照),早期版本为字符串,故只判存在不判类型)。
158
159
  let appended = false;
159
160
  childCtx.on('agent/pre-step', async ({ agent }, next) => {
160
161
  const decision = await next();
161
162
  if (!appended && decision.kind === 'enter') {
162
163
  appended = true;
163
- if (typeof request.descriptor === 'string' && request.descriptor !== '') agent.session.append('subagent/descriptor', request.descriptor);
164
+ if (request.descriptor !== undefined && request.descriptor !== null) agent.session.append('subagent/descriptor', request.descriptor);
164
165
  }
165
166
  return decision;
166
167
  });
@@ -166,7 +166,7 @@ function persistProfiles(state, logger) {
166
166
  }
167
167
 
168
168
  // 插件开关态(state.json):enabled(默认开,禁用即关派发工具)+ evolutionAdvice
169
- // (只读建议注入,默认关,需显式开)+ escapeEnabled(逃生舱放行,默认关——信任
169
+ // (派发优化建议注入,默认关,需显式开)+ escapeEnabled(逃生舱放行,默认关——信任
170
170
  // 底板,仅设置页显式 opt-in 可放开)。三开关共用同一 state.json,读写整份对象
171
171
  // 以互不覆盖;缺失文件回退默认值(全新部署),损坏文件 fail-closed(三开关全关,
172
172
  // 绝不静默回退 enabled:true —— 安全禁用会被撤销),内存态仍驱动本进程。
@@ -0,0 +1,172 @@
1
+ // lib/core/reminder-store.mjs — 提醒系统 host 侧 store + 审计同源。
2
+ // 一条提醒 = 一条治理审计记录(经 audit 钩子写入 governance-audit.jsonl,与 [6] 审计
3
+ // 同源);每个用户动作(采纳/忽略/拒绝/关闭)与「标记已读」都追加审计留痕。P0 三要件:
4
+ // severity 上色(P0 由 client 用错误色渲染)、常驻至已读(unread 标记,绝不自动消失)、
5
+ // 带 session 标识(sessionId 字段;全局异常显式 null,client 标注「全局」)。
6
+ // 隐私红线:只落结构字段(severity/kind/title/detail/sessionId/时间戳)与「未采纳」
7
+ // 条目的展示字段(子会话 id/模式、prompt 摘要 ≤200 字符、结算摘要结构、估算成本)。
8
+ // prompt 摘要不存原文,结算摘要无子输出正文;其余提醒类不携带这些字段(null)。
9
+ // 落盘 subagent-evolution/reminders.json(原子写 tmp+rename;损坏/形状不符
10
+ // fail-soft 从空起步)。import-free(仅 node 内置),可被裸 CI 单测。
11
+
12
+ import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
13
+ import { dirname, join } from 'node:path';
14
+
15
+ const SEVERITIES = new Set(['P0', 'P1', 'P2']);
16
+ const MAX_REMINDERS = 200;
17
+
18
+ function isRecordShape(rec) {
19
+ return rec !== null && typeof rec === 'object' && typeof rec.id === 'string'
20
+ && typeof rec.severity === 'string' && typeof rec.kind === 'string'
21
+ && typeof rec.title === 'string' && typeof rec.detail === 'string';
22
+ }
23
+
24
+ // 结算摘要形状守卫(宽松):只接受非数组对象,具体字段逐个归一。
25
+ function isSettleShape(value) {
26
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
27
+ }
28
+
29
+ function normalizeSettled(value) {
30
+ if (!isSettleShape(value)) return null;
31
+ return {
32
+ stopReason: typeof value.stopReason === 'string' ? value.stopReason : '',
33
+ elapsedMs: Number.isFinite(value.elapsedMs) ? value.elapsedMs : null,
34
+ ...(Number.isFinite(value.childTotalTokens) ? { childTotalTokens: value.childTotalTokens } : {}),
35
+ ...(isSettleShape(value.childUsage) ? { childUsage: value.childUsage } : {}),
36
+ ...(typeof value.childSessionId === 'string' && value.childSessionId !== '' ? { childSessionId: value.childSessionId } : {}),
37
+ };
38
+ }
39
+
40
+ function loadState(stateFile, state, warn) {
41
+ if (stateFile === undefined) return;
42
+ try {
43
+ if (!existsSync(stateFile)) return;
44
+ const parsed = JSON.parse(readFileSync(stateFile, 'utf8'));
45
+ if (parsed === null || typeof parsed !== 'object' || parsed.v !== 1 || !Array.isArray(parsed.reminders)) {
46
+ warn('reminder store: 提醒文件版本或形状不符,从空状态起步');
47
+ return;
48
+ }
49
+ for (const raw of parsed.reminders) {
50
+ if (!isRecordShape(raw)) continue;
51
+ state.reminders.push({
52
+ id: raw.id,
53
+ severity: SEVERITIES.has(raw.severity) ? raw.severity : 'P2',
54
+ kind: raw.kind,
55
+ title: raw.title,
56
+ detail: raw.detail,
57
+ sessionId: typeof raw.sessionId === 'string' && raw.sessionId !== '' ? raw.sessionId : null,
58
+ childId: typeof raw.childId === 'string' && raw.childId !== '' ? raw.childId : null,
59
+ childSessionId: typeof raw.childSessionId === 'string' && raw.childSessionId !== '' ? raw.childSessionId : null,
60
+ childMode: typeof raw.childMode === 'string' && raw.childMode !== '' ? raw.childMode : null,
61
+ promptExcerpt: typeof raw.promptExcerpt === 'string' ? raw.promptExcerpt : '',
62
+ settled: normalizeSettled(raw.settled),
63
+ costEstimated: Number.isFinite(raw.costEstimated) ? raw.costEstimated : null,
64
+ unread: raw.unread !== false,
65
+ createdAt: Number.isFinite(raw.createdAt) ? raw.createdAt : 0,
66
+ action: typeof raw.action === 'string' ? raw.action : null,
67
+ actedAt: Number.isFinite(raw.actedAt) ? raw.actedAt : null,
68
+ });
69
+ }
70
+ } catch (error) {
71
+ warn('reminder store: 提醒文件读取失败,从空状态起步(' + (error instanceof Error ? error.message : String(error)) + ')');
72
+ }
73
+ }
74
+
75
+ function persistState(stateFile, state, warn) {
76
+ if (stateFile === undefined) return;
77
+ const tmp = stateFile + '.tmp';
78
+ try {
79
+ mkdirSync(dirname(stateFile), { recursive: true });
80
+ writeFileSync(tmp, JSON.stringify({ v: 1, reminders: state.reminders }, null, 2), 'utf8');
81
+ renameSync(tmp, stateFile);
82
+ } catch (error) {
83
+ try { rmSync(tmp, { force: true }); } catch { /* best effort */ }
84
+ warn('reminder store: 提醒文件写入失败(' + (error instanceof Error ? error.message : String(error)) + ')');
85
+ }
86
+ }
87
+
88
+ function auditReminder(audit, kind, reminder, action) {
89
+ audit({
90
+ kind,
91
+ reminderId: reminder.id,
92
+ severity: reminder.severity,
93
+ reminderKind: reminder.kind,
94
+ ...(reminder.sessionId !== null ? { sessionId: reminder.sessionId } : {}),
95
+ ...(action !== undefined ? { action } : {}),
96
+ });
97
+ }
98
+
99
+ // 产生一条提醒:severity 非法回退 P2;空 sessionId 归一 null(全局)。「未采纳」
100
+ // 条目额外携带子会话 id/模式、prompt 摘要(≤200 字符再截一次防超)、结算摘要与估算
101
+ // 成本;其余提醒类这些字段为空/null。创建即审计。
102
+ function recordReminder(state, persist, audit, { severity, kind, title, detail, sessionId, childId, childSessionId, childMode, promptExcerpt, settled, costEstimated }) {
103
+ const reminder = {
104
+ id: 'r-' + Date.now() + '-' + Math.random().toString(36).slice(2, 8),
105
+ severity: SEVERITIES.has(severity) ? severity : 'P2',
106
+ kind: typeof kind === 'string' && kind !== '' ? kind : 'event',
107
+ title: typeof title === 'string' ? title : '',
108
+ detail: typeof detail === 'string' ? detail : '',
109
+ sessionId: typeof sessionId === 'string' && sessionId !== '' ? sessionId : null,
110
+ childId: typeof childId === 'string' && childId !== '' ? childId : null,
111
+ childSessionId: typeof childSessionId === 'string' && childSessionId !== '' ? childSessionId : null,
112
+ childMode: typeof childMode === 'string' && childMode !== '' ? childMode : null,
113
+ promptExcerpt: typeof promptExcerpt === 'string' ? promptExcerpt.slice(0, 200) : '',
114
+ settled: normalizeSettled(settled),
115
+ costEstimated: Number.isFinite(costEstimated) ? costEstimated : null,
116
+ unread: true,
117
+ createdAt: Date.now(),
118
+ action: null,
119
+ actedAt: null,
120
+ };
121
+ state.reminders.push(reminder);
122
+ if (state.reminders.length > state.maxReminders) state.reminders.shift();
123
+ persist();
124
+ auditReminder(audit, 'reminder-created', reminder);
125
+ return reminder;
126
+ }
127
+
128
+ // 标记已读(unread=false):P0 角标常驻至已读的「已读」动作,逐条留痕。
129
+ function ackReminders(state, persist, audit, ids) {
130
+ const list = Array.isArray(ids) ? ids : [];
131
+ const acked = [];
132
+ for (const reminder of state.reminders) {
133
+ if (reminder.unread !== true || !list.includes(reminder.id)) continue;
134
+ reminder.unread = false;
135
+ acked.push(reminder.id);
136
+ auditReminder(audit, 'reminder-acked', reminder);
137
+ }
138
+ if (acked.length > 0) persist();
139
+ return acked;
140
+ }
141
+
142
+ // 用户动作(采纳/忽略/拒绝/关闭):互斥终态 + 审计留痕(关闭留痕要求)。
143
+ function actOnReminder(state, persist, audit, id, action) {
144
+ const reminder = state.reminders.find((r) => r.id === id);
145
+ if (reminder === undefined) return false;
146
+ if (action !== 'adopt' && action !== 'ignore' && action !== 'reject' && action !== 'dismiss') return false;
147
+ reminder.action = action;
148
+ reminder.actedAt = Date.now();
149
+ reminder.unread = false;
150
+ persist();
151
+ auditReminder(audit, 'reminder-action', reminder, action);
152
+ return true;
153
+ }
154
+
155
+ function listReminders(state, unreadOnly) {
156
+ const all = [...state.reminders].reverse();
157
+ return unreadOnly ? all.filter((r) => r.unread === true) : all;
158
+ }
159
+
160
+ export function createReminderStore({ dshHome, audit = () => {}, warn = () => {}, maxReminders = MAX_REMINDERS } = {}) {
161
+ const state = { reminders: [], maxReminders: Number.isFinite(maxReminders) && maxReminders > 0 ? maxReminders : MAX_REMINDERS };
162
+ const stateFile = dshHome !== undefined && dshHome !== '' ? join(dshHome, 'subagent-evolution', 'reminders.json') : undefined;
163
+ loadState(stateFile, state, warn);
164
+ const persist = () => persistState(stateFile, state, warn);
165
+ return {
166
+ record: (entry) => recordReminder(state, persist, audit, entry),
167
+ ack: (ids) => ackReminders(state, persist, audit, ids),
168
+ actOn: (id, action) => actOnReminder(state, persist, audit, id, action),
169
+ list: ({ unreadOnly = false } = {}) => listReminders(state, unreadOnly),
170
+ unreadCount: () => state.reminders.filter((r) => r.unread === true).length,
171
+ };
172
+ }
@@ -191,6 +191,16 @@ function readPackageVersion(pkg) {
191
191
  }
192
192
  }
193
193
 
194
+ // 读本插件自身 package.json version(fail-soft 'unknown'),供维护区显示当前版本。
195
+ function readOwnPluginVersion() {
196
+ try {
197
+ const manifest = requirePkg('../../package.json');
198
+ return typeof manifest.version === 'string' && manifest.version !== '' ? manifest.version : 'unknown';
199
+ } catch {
200
+ return 'unknown';
201
+ }
202
+ }
203
+
194
204
  // 极简 semver 比较:major.minor.patch + 可选 `-预发布` 段(覆盖 peerDependencies
195
205
  // 范围判断所需)。预发布 < 正式版;预发布段逐段比较,纯数字段按数值、否则按字典序
196
206
  // (`0.1.0-rc.10` > `0.1.0-rc.6`)。
@@ -249,7 +259,7 @@ export function detectVersions(reader = readPackageVersion) {
249
259
  warnings.push(`@deepseek-ai/${pkg} 版本 ${version} 超出 peerDependencies 范围(>=${PEER_MIN} <${PEER_MAX}),派发行为可能与预期不符`);
250
260
  }
251
261
  }
252
- return { versions, warnings };
262
+ return { versions, warnings, pluginVersion: readOwnPluginVersion() };
253
263
  }
254
264
 
255
265
  // 仅供测试访问本地降级实现(包导入在这里可解析,真函数胜出;`__fallbacks`
package/package.json CHANGED
@@ -1,82 +1,82 @@
1
- {
2
- "name": "dsh-subagent-profile",
3
- "version": "0.3.3",
4
- "description": "Dispatch one-shot subtasks to derived subagents with per-task overrides (preset/model/provider/reasoningEffort/persona/tool whitelist), a runtime-derived cost guard, a subagent-profiles service, observability metadata, and a web-GUI settings page plus a dispatch tool-call card.",
5
- "repository": {
6
- "type": "git",
7
- "url": "git+https://github.com/muzyLink/dsh-subagent-profile.git"
8
- },
9
- "type": "module",
10
- "main": "index.mjs",
11
- "exports": {
12
- ".": "./index.mjs",
13
- "./client": "./lib/client.js",
14
- "./package.json": "./package.json"
15
- },
16
- "files": [
17
- "index.mjs",
18
- "lib",
19
- "cordis.patch.yml",
20
- "presets",
21
- "docs/screenshots",
22
- "README.md",
23
- "README.zh.md"
24
- ],
25
- "dsh": {
26
- "bundle": {
27
- "patch": "./cordis.patch.yml"
28
- },
29
- "client": {
30
- "inject": [],
31
- "platform": "web"
32
- }
33
- },
34
- "peerDependencies": {
35
- "@deepseek-ai/dsh-agent": ">=0.1.0-rc.6 <0.2.0",
36
- "@deepseek-ai/dsh-llm": ">=0.1.0-rc.6 <0.2.0",
37
- "@deepseek-ai/dsh-subagent": ">=0.1.0-rc.6 <0.2.0",
38
- "@deepseek-ai/dsh-tools": ">=0.1.0-rc.6 <0.2.0"
39
- },
40
- "peerDependenciesMeta": {
41
- "@deepseek-ai/dsh-agent": {
42
- "optional": true
43
- },
44
- "@deepseek-ai/dsh-subagent": {
45
- "optional": true
46
- },
47
- "@deepseek-ai/dsh-llm": {
48
- "optional": true
49
- },
50
- "@deepseek-ai/dsh-tools": {
51
- "optional": true
52
- }
53
- },
54
- "devDependencies": {
55
- "@deepseek-ai/dsh-agent": "0.1.0-rc.8",
56
- "@deepseek-ai/dsh-llm": "0.1.0-rc.8",
57
- "@deepseek-ai/dsh-subagent": "0.1.0-rc.8",
58
- "@deepseek-ai/dsh-tools": "0.1.0-rc.8",
59
- "@eslint/js": "^10.0.1",
60
- "eslint": "^10.9.0"
61
- },
62
- "engines": {
63
- "node": "^22.19.0 || >=24"
64
- },
65
- "publishConfig": {
66
- "access": "public"
67
- },
68
- "keywords": [
69
- "deepseek-harness",
70
- "dsh",
71
- "subagent",
72
- "dispatch",
73
- "profiles"
74
- ],
75
- "license": "MIT",
76
- "scripts": {
77
- "test": "node --test \"test/**/*.test.mjs\"",
78
- "test:bare": "node --test test/pure.test.mjs test/input-schema.test.mjs test/catalog-integrity.test.mjs",
79
- "preflight": "node scripts/preflight.mjs",
80
- "leak-scan": "node scripts/leak-scan.mjs"
81
- }
82
- }
1
+ {
2
+ "name": "dsh-subagent-profile",
3
+ "version": "0.3.4",
4
+ "description": "DeepSeek Harness 子 Agent 派发插件:按任务为子代理选模型、推理强度与工具范围,常用组合存成命名方案随时复用;内置安全检查、成本估算与节省分析、完整决策台账。",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/muzyLink/dsh-subagent-profile.git"
8
+ },
9
+ "type": "module",
10
+ "main": "index.mjs",
11
+ "scripts": {
12
+ "test": "node --test \"test/**/*.test.mjs\"",
13
+ "test:bare": "node --test test/pure.test.mjs test/input-schema.test.mjs test/catalog-integrity.test.mjs",
14
+ "preflight": "node scripts/preflight.mjs",
15
+ "leak-scan": "node scripts/leak-scan.mjs"
16
+ },
17
+ "exports": {
18
+ ".": "./index.mjs",
19
+ "./client": "./lib/client.js",
20
+ "./package.json": "./package.json"
21
+ },
22
+ "files": [
23
+ "index.mjs",
24
+ "lib",
25
+ "cordis.patch.yml",
26
+ "presets",
27
+ "docs/screenshots",
28
+ "README.md",
29
+ "README.zh.md"
30
+ ],
31
+ "dsh": {
32
+ "bundle": {
33
+ "patch": "./cordis.patch.yml"
34
+ },
35
+ "client": {
36
+ "inject": [],
37
+ "platform": "web"
38
+ }
39
+ },
40
+ "peerDependencies": {
41
+ "@deepseek-ai/dsh-agent": ">=0.1.0-rc.6 <0.2.0",
42
+ "@deepseek-ai/dsh-llm": ">=0.1.0-rc.6 <0.2.0",
43
+ "@deepseek-ai/dsh-subagent": ">=0.1.0-rc.6 <0.2.0",
44
+ "@deepseek-ai/dsh-tools": ">=0.1.0-rc.6 <0.2.0"
45
+ },
46
+ "peerDependenciesMeta": {
47
+ "@deepseek-ai/dsh-agent": {
48
+ "optional": true
49
+ },
50
+ "@deepseek-ai/dsh-subagent": {
51
+ "optional": true
52
+ },
53
+ "@deepseek-ai/dsh-llm": {
54
+ "optional": true
55
+ },
56
+ "@deepseek-ai/dsh-tools": {
57
+ "optional": true
58
+ }
59
+ },
60
+ "devDependencies": {
61
+ "@deepseek-ai/dsh-agent": "0.1.0-rc.8",
62
+ "@deepseek-ai/dsh-llm": "0.1.0-rc.8",
63
+ "@deepseek-ai/dsh-subagent": "0.1.0-rc.8",
64
+ "@deepseek-ai/dsh-tools": "0.1.0-rc.8",
65
+ "@eslint/js": "^10.0.1",
66
+ "eslint": "^10.9.0"
67
+ },
68
+ "engines": {
69
+ "node": "^22.19.0 || >=24"
70
+ },
71
+ "publishConfig": {
72
+ "access": "public"
73
+ },
74
+ "keywords": [
75
+ "deepseek-harness",
76
+ "dsh",
77
+ "subagent",
78
+ "dispatch",
79
+ "profiles"
80
+ ],
81
+ "license": "MIT"
82
+ }