dsh-knj-workflow 2026.9.70 → 2026.9.73
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/lib/client.js +23 -9
- package/lib/index.js +12 -0
- package/lib/orchestrator.js +15 -1
- package/lib/orchestrator.test.js +21 -0
- package/package.json +8 -7
package/lib/client.js
CHANGED
|
@@ -503,6 +503,20 @@ table.knj-tbl{width:100%;border-collapse:collapse;table-layout:fixed}
|
|
|
503
503
|
.knj-archive-list{flex:1;padding:14px 16px;overflow-y:auto}
|
|
504
504
|
.knj-arch-row{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:10px;padding:12px 14px;display:flex;align-items:center;gap:12px;margin-bottom:10px}
|
|
505
505
|
.knj-arch-meta{margin-left:auto;font-size:12px;color:var(--dsw-alias-label-tertiary)}
|
|
506
|
+
/* ===== 流程运行面板:状态对比增强 + 运行中呼吸脉冲 =====
|
|
507
|
+
只对「正在运行」这一主信号加动画(其余状态保持静态),脉冲柔和克制、契合 DSH 原生风格。
|
|
508
|
+
色值为既有语义色(RUN_STATUS/STAGE_META),未新增调色板。 */
|
|
509
|
+
@keyframes knjRunPulse{0%,100%{opacity:.9}50%{opacity:.25}}
|
|
510
|
+
@keyframes knjRunBreath{0%,100%{box-shadow:0 0 0 3px rgba(47,107,255,.22)}50%{box-shadow:0 0 0 9px rgba(47,107,255,.05)}}
|
|
511
|
+
@keyframes knjBarStrip{to{background-position:14px 0}}
|
|
512
|
+
.knj-run-glow{animation:knjRunPulse 2s ease-in-out infinite}
|
|
513
|
+
.knj-node-dot.running{animation:knjRunBreath 1.6s ease-in-out infinite}
|
|
514
|
+
.knj-node-card.running{border-color:#2f6bff;background:var(--dsw-alias-bg-base)}
|
|
515
|
+
.knj-node-card.done{border-color:var(--dsw-alias-state-success-primary)}
|
|
516
|
+
.knj-node-card.pending{border-color:var(--dsw-alias-border-l2);opacity:.85}
|
|
517
|
+
.knj-node-card.failed{border-color:var(--dsw-alias-state-error-primary)}
|
|
518
|
+
.knj-node-card.skipped{opacity:.55}
|
|
519
|
+
.knj-progress.animated>div{background-image:linear-gradient(90deg,var(--dsw-alias-state-business-primary) 0 62%,rgba(47,107,255,.5) 62% 100%);background-size:14px 100%;animation:knjBarStrip .9s linear infinite}
|
|
506
520
|
`;
|
|
507
521
|
|
|
508
522
|
function toast(msg) {
|
|
@@ -1141,7 +1155,7 @@ table.knj-tbl{width:100%;border-collapse:collapse;table-layout:fixed}
|
|
|
1141
1155
|
]),
|
|
1142
1156
|
sec('行为 prompt(task 节点)', [
|
|
1143
1157
|
'本节点让 AI 做什么,写清楚目标和约束。',
|
|
1144
|
-
'可引用:${inputDescription}(任务需求描述)、${inputTitle}(标题)、${上游编码.字段}(上游输出,如 ${analyze.description})、${inputs.参数名}(任务输入)。',
|
|
1158
|
+
'可引用:${inputDescription}(任务需求描述)、${inputTitle}(标题)、${taskId}(任务 id,流程实例唯一标识;同任务续跑/重跑 id 不变,可拼产出路径隔离产物)、${上游编码.字段}(上游输出,如 ${analyze.description})、${inputs.参数名}(任务输入)。',
|
|
1145
1159
|
'执行方式:single 一个 AI 完成;parallel 派多个 AI 并行(结果合并为数组)。',
|
|
1146
1160
|
'最大执行次数:本节点在一轮任务里最多执行几次(默认 3)。驳回重做 / 循环连线会重复执行节点,超过上限本轮失败——自动防死循环,无需其他配置。',
|
|
1147
1161
|
]),
|
|
@@ -1195,7 +1209,7 @@ table.knj-tbl{width:100%;border-collapse:collapse;table-layout:fixed}
|
|
|
1195
1209
|
]),
|
|
1196
1210
|
sec('行为 prompt(task 节点)', [
|
|
1197
1211
|
'本节点让 AI 做什么,写清目标与约束。',
|
|
1198
|
-
'可引用:${inputDescription}(任务需求描述)、${inputTitle}(标题)、${storyCode}(用户故事编码)、${cwd}(任务工作目录)、${inputs.参数名}(任务输入)。',
|
|
1212
|
+
'可引用:${inputDescription}(任务需求描述)、${inputTitle}(标题)、${storyCode}(用户故事编码)、${cwd}(任务工作目录)、${taskId}(任务 id,同任务续跑/重跑 id 不变,产出路径用它拼接可隔离各实例产物)、${inputs.参数名}(任务输入)。',
|
|
1199
1213
|
'运行时每个 task 节点会自动声明任务工作目录(所有文件/命令操作都在其中)。',
|
|
1200
1214
|
'需要 skill 时在 prompt 里直接写「先调用 skill 工具加载 skill「xxx」」。',
|
|
1201
1215
|
'上游输出引用(${上游编码.字段}):',
|
|
@@ -1702,7 +1716,7 @@ table.knj-tbl{width:100%;border-collapse:collapse;table-layout:fixed}
|
|
|
1702
1716
|
fieldLabel('节点编码(id)', '节点唯一标识:下游用 ${编码.字段} 引用(如 ${analyze.description}),网关用字段值做分支判断。修改后 prompt 里旧的 ${旧编码.字段} 引用需手动更新。', '下游用 ${编码.字段} 引用,如 ${analyze.description}'),
|
|
1703
1717
|
react.createElement('input', { className: 'knj-input', style: { marginBottom: 8 }, placeholder: '如:analyze', defaultValue: node.id || '', onBlur: (e) => this.patchNodeId(node.id, e.target.value.trim()) }),
|
|
1704
1718
|
isTask ? react.createElement('div', null,
|
|
1705
|
-
fieldLabel('行为 prompt(主体)', '本节点让 AI 做什么,写清目标与约束。\n可引用:\n${inputDescription}(任务需求描述)\n${inputTitle}(标题)\n${storyCode}(用户故事编码,可选)\n${cwd}(任务工作目录;运行时还会自动向 subagent 声明该目录)\n${inputs.参数名}(任务输入)\n\n上游输出引用(${上游编码.字段}):\n' + this.buildRefsText(node) + '\n\n注意:XOR 分支未执行的节点引用为空;整节点输出用 ${节点id};${ctx.前缀写法仍兼容。', '让 AI 做什么;可引用 ${inputDescription}、${storyCode}、${cwd}、${上游编码.字段}(ⓘ 看完整清单)'),
|
|
1719
|
+
fieldLabel('行为 prompt(主体)', '本节点让 AI 做什么,写清目标与约束。\n可引用:\n${inputDescription}(任务需求描述)\n${inputTitle}(标题)\n${storyCode}(用户故事编码,可选)\n${cwd}(任务工作目录;运行时还会自动向 subagent 声明该目录)\n${taskId}(任务 id,流程实例唯一标识;同任务续跑/重跑 id 不变——产出路径可写 ${cwd}/out/${taskId}/ 按实例隔离产物)\n${inputs.参数名}(任务输入)\n\n上游输出引用(${上游编码.字段}):\n' + this.buildRefsText(node) + '\n\n注意:XOR 分支未执行的节点引用为空;整节点输出用 ${节点id};${ctx.前缀写法仍兼容。', '让 AI 做什么;可引用 ${inputDescription}、${storyCode}、${cwd}、${上游编码.字段}(ⓘ 看完整清单)'),
|
|
1706
1720
|
react.createElement('textarea', { className: 'knj-textarea', style: { minHeight: 140 }, placeholder: '如:根据需求 ${inputDescription} 输出功能描述与验收标准', value: node.body?.prompt || '', onChange: (e) => this.patchNode(node.id, { body: { ...node.body, prompt: e.target.value } }) }),
|
|
1707
1721
|
fieldLabel('执行方式', 'single:一个 AI 完成本阶段,输出单个对象。\nparallel:派多个 AI 并行做同一件事,结果合并为数组(配合「最大执行次数」外的 parallelItems 使用,见输出说明)。', 'single:单个 AI 完成;parallel:多个 AI 并行,结果合并为数组'),
|
|
1708
1722
|
react.createElement('select', { className: 'knj-input', value: node.body?.mode || 'single', onChange: (e) => this.patchNode(node.id, { body: { ...node.body, mode: e.target.value } }) },
|
|
@@ -2893,7 +2907,7 @@ table.knj-tbl{width:100%;border-collapse:collapse;table-layout:fixed}
|
|
|
2893
2907
|
kids.push(react.createElement('rect', { key: 'b', x: n.x - 31, y: n.y - 18, width: 62, height: 36, rx: 18, fill: 'var(--dsw-alias-bg-base)', stroke: isSkipped ? '#b6bdc7' : (status === 'pending' ? '#8b95a5' : c), strokeWidth: 1.4, strokeDasharray: isSkipped ? '4 3' : undefined, opacity: dim }));
|
|
2894
2908
|
kids.push(react.createElement('text', { key: 't', x: n.x, y: n.y + 4, fontSize: 12, textAnchor: 'middle', fill: 'var(--dsw-alias-label-secondary)' }, n.type === 'start' ? '开始' : '结束'));
|
|
2895
2909
|
} else {
|
|
2896
|
-
kids.push(react.createElement('rect', { key: 'b', x: n.x - w / 2, y: n.y - hh / 2, width: w, height: hh, rx: 9, fill: n.type === 'human' ? '#f3efff' : 'var(--dsw-alias-bg-base)', stroke: 'var(--dsw-alias-border-l2)', strokeWidth: 1, opacity: dim }));
|
|
2910
|
+
kids.push(react.createElement('rect', { key: 'b', x: n.x - w / 2, y: n.y - hh / 2, width: w, height: hh, rx: 9, fill: n.type === 'human' ? '#f3efff' : (status === 'running' ? '#e7efff' : status === 'done' ? '#f0faf3' : 'var(--dsw-alias-bg-base)'), stroke: isSkipped ? '#b6bdc7' : (status === 'pending' ? 'var(--dsw-alias-border-l2)' : c), strokeWidth: status === 'running' ? 2.1 : 1, opacity: dim }));
|
|
2897
2911
|
kids.push(react.createElement('rect', { key: 'bar', x: n.x - w / 2 + 1, y: n.y - hh / 2 + 1, width: 3.5, height: hh - 2, rx: 1.75, fill: isSkipped ? '#9aa3af' : c, strokeDasharray: isSkipped ? '3 2' : undefined }));
|
|
2898
2912
|
kids.push(react.createElement('text', { key: 'tt', x: n.x + 5, y: n.y - 1, fontSize: 13, fontWeight: 600, textAnchor: 'middle', fill: 'var(--dsw-alias-label-primary)', style: { userSelect: 'none' } }, (n.title || n.id).length > 11 ? (n.title || n.id).slice(0, 11) + '…' : (n.title || n.id)));
|
|
2899
2913
|
const sub = status === 'running' ? '运行中' : status === 'waiting' ? '等待人工审批' : (status === 'passed' ? '已过' : meta.label);
|
|
@@ -2907,8 +2921,8 @@ table.knj-tbl{width:100%;border-collapse:collapse;table-layout:fixed}
|
|
|
2907
2921
|
else if (status === 'skipped') kids.push(react.createElement('path', { key: 'ic2', d: `M ${ix - 3.2} ${iy} h 6.4`, stroke: '#fff', strokeWidth: 1.6, strokeLinecap: 'round' }));
|
|
2908
2922
|
else if (status === 'waiting') kids.push(react.createElement('circle', { key: 'ic2', cx: ix, cy: iy - 1.5, r: 2.2, fill: 'none', stroke: '#fff', strokeWidth: 1.2 }), react.createElement('path', { key: 'ic3', d: `M ${ix - 3.6} ${iy + 4.6} c 0 -2.1 1.7 -3.1 3.6 -3.1 s 3.6 1 3.6 3.1`, stroke: '#fff', strokeWidth: 1.2, fill: 'none', strokeLinecap: 'round' }));
|
|
2909
2923
|
}
|
|
2910
|
-
// running
|
|
2911
|
-
if (status === 'running') kids.push(react.createElement('
|
|
2924
|
+
// running 光环:贴合节点矩形的呼吸光边(非圆环;仅运行节点=当前主信号上动画)
|
|
2925
|
+
if (status === 'running') kids.push(react.createElement('rect', { key: 'halo', className: 'knj-run-glow', x: n.x - w / 2 - 5, y: n.y - hh / 2 - 5, width: w + 10, height: hh + 10, rx: 13, fill: 'rgba(47,107,255,.1)', stroke: '#2f6bff', strokeWidth: 2.2 }));
|
|
2912
2926
|
}
|
|
2913
2927
|
const isSel = sel;
|
|
2914
2928
|
const hit = react.createElement('rect', { x: n.x - 70, y: n.y - 38, width: 140, height: 76, rx: 12, fill: 'transparent', onClick: (e) => { e.stopPropagation(); this.setState({ graphSel: n.id }); const stage = (this.props.task.stageStates || []).find((x) => x.id === n.id); if (stage && stage.status === 'done' && this.resultFor(n.id) == null) this.loadStageResult(n.id); }, style: { cursor: 'pointer' } });
|
|
@@ -2935,9 +2949,9 @@ table.knj-tbl{width:100%;border-collapse:collapse;table-layout:fixed}
|
|
|
2935
2949
|
: s.status === 'skipped' ? '–'
|
|
2936
2950
|
: s.status === 'failed' ? icon('x')
|
|
2937
2951
|
: (i + 1);
|
|
2938
|
-
return react.createElement('div', { key: s.id, className: 'knj-node-card' },
|
|
2952
|
+
return react.createElement('div', { key: s.id, className: 'knj-node-card' + (isRunning ? ' running' : s.status === 'done' ? ' done' : s.status === 'pending' ? ' pending' : s.status === 'failed' ? ' failed' : s.status === 'skipped' ? ' skipped' : '') },
|
|
2939
2953
|
react.createElement('div', { className: 'knj-node-head', onClick: () => hasDetail && this.toggle(s.id) },
|
|
2940
|
-
react.createElement('div', { className: 'knj-node-dot'
|
|
2954
|
+
react.createElement('div', { className: 'knj-node-dot' + (isRunning ? ' running' : ''), style: { background: meta.color } }, statusIcon),
|
|
2941
2955
|
react.createElement('div', { style: { flex: 1, minWidth: 0 } },
|
|
2942
2956
|
react.createElement('div', { className: 'knj-node-title' }, s.title),
|
|
2943
2957
|
react.createElement('div', { className: 'knj-node-sub' }, dur ? `${dur} · ${meta.label}` : meta.label),
|
|
@@ -3233,7 +3247,7 @@ table.knj-tbl{width:100%;border-collapse:collapse;table-layout:fixed}
|
|
|
3233
3247
|
task.model ? react.createElement('span', { className: 'knj-badge', style: { background: '#5b6472' }, title: '该任务固定的执行模型(创建时指定)' }, task.model) : null,
|
|
3234
3248
|
),
|
|
3235
3249
|
// 整体进度条 + 摘要
|
|
3236
|
-
react.createElement('div', { className: 'knj-progress', style: { width: '100%', marginTop: 12 } },
|
|
3250
|
+
react.createElement('div', { className: 'knj-progress' + (task.status === 'running' ? ' animated' : ''), style: { width: '100%', marginTop: 12 } },
|
|
3237
3251
|
react.createElement('div', { style: { width: pct + '%' } }),
|
|
3238
3252
|
),
|
|
3239
3253
|
react.createElement('div', { className: 'sub', style: { marginTop: 4 } }, `进度 ${pct}% · 完成 ${doneCount}/${relevant.length} 阶段${steps.length - relevant.length ? `(跳过 ${steps.length - relevant.length})` : ''}`),
|
package/lib/index.js
CHANGED
|
@@ -627,6 +627,18 @@ export class WorkflowBridge {
|
|
|
627
627
|
// sessionIds 无限增长(每次续跑 +N 条重复 id)
|
|
628
628
|
const ids = s.sessionIds || [];
|
|
629
629
|
if (!ids.includes(childId)) s.sessionIds = [...ids, childId];
|
|
630
|
+
// 真实执行信号:主体 subagent 启动 = 本节点正在跑。多轮复用同一节点时
|
|
631
|
+
// (如人工驳回 → fix 重做 → 再驳回 → fix 再重做),上一轮 done 会挡死状态:
|
|
632
|
+
// onPhase 只把 pending/skipped→running,onAgentEnd 只把 running→done,
|
|
633
|
+
// done 阶段被再次执行时永远停留在旧 done/旧 finishedAt(task-mtu18nd3 实测:
|
|
634
|
+
// 显示 fix 已完成 12:06,实际 checkpoint 12:31 才落盘)。这里以 agent-start
|
|
635
|
+
// 为唯一事实源强制置回 running:清 finishedAt、刷新 startedAt 为本轮纪元。
|
|
636
|
+
if (s.status !== 'running') {
|
|
637
|
+
s.status = 'running';
|
|
638
|
+
s.startedAt = nowIso();
|
|
639
|
+
s.finishedAt = undefined;
|
|
640
|
+
s.error = undefined;
|
|
641
|
+
}
|
|
630
642
|
}
|
|
631
643
|
}
|
|
632
644
|
}).catch(() => {});
|
package/lib/orchestrator.js
CHANGED
|
@@ -36,6 +36,12 @@ let humanFeedback = null; // 人工意见:注入去向目标节点(仅一
|
|
|
36
36
|
// 直接走其最后去向(目标已在 initialResults 则被 skipSet 跳过;否则正常执行)。
|
|
37
37
|
// 没有它,两个顺序 human 的任务会在 H1/H2 之间无限振荡(H2 的决策被 H1 的重新暂停吞掉)。
|
|
38
38
|
const decidedMap = args.decided || {};
|
|
39
|
+
// 本轮已放行过一次去向的 human(消费当前决策 / 重放历史决策都算放行)。
|
|
40
|
+
// 去向把流程带回同一个 human(如驳回 → fix → submit → 同一 human 的回环)时,再次到达
|
|
41
|
+
// = 新一轮审批,必须暂停等人工,不能再用 decidedMap 里的旧决策放行第二次——
|
|
42
|
+
// 否则 fix/submit 被反复重执行直到 maxRuns 超限报错,人工节点永远无法重新触发
|
|
43
|
+
// (task-mttp8q71/task-mttz5ok7 实测:驳回后 fix/submit 空转 → 任务卡 running/失败)。
|
|
44
|
+
const humanReleased = new Set();
|
|
39
45
|
|
|
40
46
|
/** 节点最大执行次数:显式配置 maxRuns 优先,默认 3(首次 + 最多 2 次重跑)。 */
|
|
41
47
|
function maxRunsOf(node) {
|
|
@@ -182,7 +188,11 @@ const BUILTIN_ACTIONS = {
|
|
|
182
188
|
function getCtx() {
|
|
183
189
|
// 任务级变量:inputDescription(新建任务需求描述)、inputTitle(标题)、storyCode(用户故事编码)、
|
|
184
190
|
// cwd(工作目录)、inputs(参数映射)并列,工作流任意 prompt/hook 参数可引用。
|
|
191
|
+
// taskId = task.id(流程实例唯一标识;同任务 resume/rerun 不变)——节点产出文件路径可用它拼接,
|
|
192
|
+
// 让不同任务实例的产物互相隔离(等价写法 ${task.id})。
|
|
185
193
|
return {
|
|
194
|
+
task: { id: task.id },
|
|
195
|
+
taskId: task.id,
|
|
186
196
|
inputs: args.inputs || {},
|
|
187
197
|
inputDescription: task.description || '',
|
|
188
198
|
inputTitle: task.title || '',
|
|
@@ -351,12 +361,16 @@ async function executeUntil(nodeId, joinId) {
|
|
|
351
361
|
const route = matchRoute(node, decision.value);
|
|
352
362
|
if (decision.feedback) humanFeedback = decision.feedback;
|
|
353
363
|
skipSet.delete(route.to); // 去向目标应重新执行(接受人工意见),避免被断点跳过
|
|
364
|
+
humanReleased.add(node.id); // 本 walk 已放行过一次 → 回访即暂停(新一轮审批)
|
|
354
365
|
current = route.to;
|
|
355
|
-
} else if (decidedMap[node.id]) {
|
|
366
|
+
} else if (decidedMap[node.id] && !humanReleased.has(node.id)) {
|
|
356
367
|
// 历史决策重放:这个 human 已审批过(如顺序两个 human,后一个决策触发 resume 重走图)。
|
|
357
368
|
// 直接走最后去向:目标已在 initialResults → skipSet 跳过;未执行过 → 正常执行。
|
|
358
369
|
// 不注入意见(当初决策后的执行已带过意见)。
|
|
370
|
+
// 每个 human 每轮 walk 只重放一次:去向若把流程带回同一 human(驳回回环),
|
|
371
|
+
// 第二次到达意味着要重新审批,直接暂停而不是再次放行旧决策(见 humanReleased 注释)。
|
|
359
372
|
const route = matchRoute(node, decidedMap[node.id]);
|
|
373
|
+
humanReleased.add(node.id);
|
|
360
374
|
current = route.to;
|
|
361
375
|
} else {
|
|
362
376
|
return { ok: true, current: null, paused: true, pausedAt: node.id };
|
package/lib/orchestrator.test.js
CHANGED
|
@@ -694,6 +694,27 @@ test('orchestrator: 用户故事编码 storyCode 可引用(${storyCode})', a
|
|
|
694
694
|
assert.ok(!capturedPrompt.includes('${storyCode}'), capturedPrompt);
|
|
695
695
|
});
|
|
696
696
|
|
|
697
|
+
test('orchestrator: task.id 可引用(${taskId} 与 ${task.id}),可拼产出路径隔离实例产物', async () => {
|
|
698
|
+
const wf = {
|
|
699
|
+
id: 'wf-taskid', nodes: [
|
|
700
|
+
{ id: 'start', type: 'start' },
|
|
701
|
+
{ id: 'a', type: 'task', title: 'A', inputs: [], body: { prompt: '产物目录:${cwd}/out/${taskId}/,别名:${task.id}', mode: 'single', output: {} } },
|
|
702
|
+
{ id: 'end', type: 'end' },
|
|
703
|
+
],
|
|
704
|
+
edges: [{ from: 'start', to: 'a' }, { from: 'a', to: 'end' }],
|
|
705
|
+
};
|
|
706
|
+
let capturedPrompt = null;
|
|
707
|
+
const { result } = await runOrchestrator(wf, (label, prompt) => {
|
|
708
|
+
if (label === 'A') capturedPrompt = prompt;
|
|
709
|
+
return { ok: true };
|
|
710
|
+
}, { task: { id: 'task-mt1uc64i', title: 'T', taskDir: '.tasks/task-mt1uc64i', cwd: 'D:/ws/proj' } });
|
|
711
|
+
// 两种写法都解析为 task.id,拼接出的产出路径按实例隔离
|
|
712
|
+
assert.ok(capturedPrompt.includes('产物目录:D:/ws/proj/out/task-mt1uc64i/'), capturedPrompt);
|
|
713
|
+
assert.ok(capturedPrompt.includes('别名:task-mt1uc64i'), capturedPrompt);
|
|
714
|
+
assert.ok(!capturedPrompt.includes('${task'), capturedPrompt);
|
|
715
|
+
assert.equal(result.current, 'end');
|
|
716
|
+
});
|
|
717
|
+
|
|
697
718
|
test('orchestrator: human reject 带 feedback → rejectTo 节点 prompt 含人工意见', async () => {
|
|
698
719
|
let capturedPrompt = null;
|
|
699
720
|
const { result, agentCalls } = await runOrchestrator(humanWorkflow(), (label, prompt) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-knj-workflow",
|
|
3
|
-
"version": "2026.9.
|
|
3
|
+
"version": "2026.9.73",
|
|
4
4
|
"description": "KNJ 开发任务编排插件:配置驱动的工作流 + 开发任务管理 + 可视化阶段进度(DeepSeek Harness)",
|
|
5
5
|
"author": "knj",
|
|
6
6
|
"license": "MIT",
|
|
@@ -37,12 +37,13 @@
|
|
|
37
37
|
],
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
40
|
-
"@deepseek-ai/dsh-agent": "0.1.2-rc.1",
|
|
41
|
-
"@deepseek-ai/dsh-commands": "0.1.2-rc.1",
|
|
42
|
-
"@deepseek-ai/dsh-host-webserver": "0.1.2-rc.1",
|
|
43
|
-
"@deepseek-ai/dsh-session": "0.1.2-rc.1",
|
|
44
|
-
"@deepseek-ai/dsh-tools": "0.1.2-rc.1",
|
|
45
|
-
"@deepseek-ai/dsh-workflow": "0.1.2-rc.1"
|
|
40
|
+
"@deepseek-ai/dsh-agent": ">=0.1.1-rc.2 <0.1.2-0 || >=0.1.2-rc.1 <0.1.3-0",
|
|
41
|
+
"@deepseek-ai/dsh-commands": ">=0.1.1-rc.2 <0.1.2-0 || >=0.1.2-rc.1 <0.1.3-0",
|
|
42
|
+
"@deepseek-ai/dsh-host-webserver": ">=0.1.1-rc.2 <0.1.2-0 || >=0.1.2-rc.1 <0.1.3-0",
|
|
43
|
+
"@deepseek-ai/dsh-session": ">=0.1.1-rc.2 <0.1.2-0 || >=0.1.2-rc.1 <0.1.3-0",
|
|
44
|
+
"@deepseek-ai/dsh-tools": ">=0.1.1-rc.2 <0.1.2-0 || >=0.1.2-rc.1 <0.1.3-0",
|
|
45
|
+
"@deepseek-ai/dsh-workflow": ">=0.1.1-rc.2 <0.1.2-0 || >=0.1.2-rc.1 <0.1.3-0",
|
|
46
|
+
"@deepseek-ai/schemastery": ">=3.18.0 <4.0.0"
|
|
46
47
|
},
|
|
47
48
|
"devDependencies": {
|
|
48
49
|
"@deepseek-ai/cordis": "4.0.1",
|