@elinpf/dsh-ops-tool-trace 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4 @@
1
+ title: "@elinpf/dsh-ops-tool-trace"
2
+ description:
3
+ zh: "运维模式调查树工具 — 用扩散-收敛树替代 todo_write"
4
+ en: "Investigation tree tool for ops mode — replaces todo_write with a diverge-converge tree"
package/README.md ADDED
@@ -0,0 +1,46 @@
1
+ # @elinpf/dsh-ops-tool-trace
2
+
3
+ An investigation tree tool for DeepSeek Harness ops mode — replaces `todo_write` with a diverge-converge tree of steps, milestones, dead ends, and a resolved terminal.
4
+
5
+ ## What it does
6
+
7
+ Agent-driven investigation tracking: the agent maintains a tree of investigation steps via the `todo_tree` model tool. Each call appends an incremental event to the session log; a session projection folds these into the current tree state; the client renders a git-graph-style flat list with colored lanes, expandable rows, and status glyphs.
8
+
9
+ - **8 actions**: `create_tree`, `add_step`, `add_milestone`, `start`, `complete`, `abandon`, `resolve`, `note`
10
+ - **6 statuses**: `goal`, `pending`, `in_progress`, `done`, `dead_end`, `resolved`
11
+ - **Dead ends are not deleted** — they stay on the tree as part of the exploration record
12
+ - **Branch** with `branch=true` to explore side paths in parallel lanes
13
+ - Every call returns the full tree + a status summary (advisor, not gatekeeper)
14
+
15
+ ## Installation
16
+
17
+ Add to `dsh-web-app` dependencies and reference in the ops preset's `agent.cordis.yml`:
18
+
19
+ ```yaml
20
+ - id: tool-ops-trace
21
+ name: '@elinpf/dsh-ops-tool-trace'
22
+ ```
23
+
24
+ ## Model Experience
25
+
26
+ ### todo_tree tool
27
+
28
+ #### What the model sees
29
+
30
+ A tool description explaining the 8 actions and when to use each. A system prompt section with usage guidance.
31
+
32
+ #### Token effect
33
+
34
+ Tool schema + description (~200 tokens). System prompt section (~300 tokens).
35
+
36
+ #### KV Cache effect
37
+
38
+ Stable across turns — tool description and prompt section are static.
39
+
40
+ ## Known Limitations and Deferred Work
41
+
42
+ - No cross-session continuity (v1: one tree per session)
43
+ - No human editing (pure agent-driven)
44
+ - Lane/depth computed client-side (layout is derived, not stored)
45
+ - Subagents cannot directly write to the tree — main agent must relay their results
46
+ - No replay/timeline scrub UI (events are in the session log, but no dedicated timeline view)
package/README.zh.md ADDED
@@ -0,0 +1,46 @@
1
+ # @elinpf/dsh-ops-tool-trace
2
+
3
+ 运维模式调查树工具 — 用扩散-收敛树替代 `todo_write`,记录步骤、里程碑、死胡同和已解决终端。
4
+
5
+ ## 功能
6
+
7
+ Agent 驱动的调查跟踪:agent 通过 `todo_tree` 模型工具维护调查步骤树。每次调用向会话日志追加增量事件;session projection 将事件 fold 成当前树状态;client 渲染 git-graph 风格的扁平列表,带彩色轨道线、可展开行和状态图标。
8
+
9
+ - **8 个动作**:`create_tree`、`add_step`、`add_milestone`、`start`、`complete`、`abandon`、`resolve`、`note`
10
+ - **6 种状态**:`goal`、`pending`、`in_progress`、`done`、`dead_end`、`resolved`
11
+ - **死胡同不删除** — 保留在树上作为探索记录
12
+ - **分支**:`branch=true` 在并行轨道探索侧路径
13
+ - 每次调用返回完整树 + 状态摘要(顾问,非守门员)
14
+
15
+ ## 安装
16
+
17
+ 添加到 `dsh-web-app` 依赖,并在 ops preset 的 `agent.cordis.yml` 中引用:
18
+
19
+ ```yaml
20
+ - id: tool-ops-trace
21
+ name: '@elinpf/dsh-ops-tool-trace'
22
+ ```
23
+
24
+ ## 模型体验
25
+
26
+ ### todo_tree 工具
27
+
28
+ #### 模型看到什么
29
+
30
+ 工具描述(8 个动作及使用时机)+ 系统提示词 section(使用指南)。
31
+
32
+ #### Token 影响
33
+
34
+ 工具 schema + 描述(约 200 token)+ 系统提示词 section(约 300 token)。
35
+
36
+ #### KV Cache 影响
37
+
38
+ 跨轮次稳定 — 工具描述和提示词 section 是静态的。
39
+
40
+ ## 已知限制和待办事项
41
+
42
+ - 无跨会话连续性(v1:一个会话一棵树)
43
+ - 无人工编辑(纯 agent 驱动)
44
+ - lane/depth 在 client 侧计算(布局是派生的,不存储)
45
+ - 子 agent 不能直接写树 — 主 agent 需代为操作
46
+ - 无回放/时间轴 UI(事件在会话日志中,但无专门时间线视图)
@@ -0,0 +1 @@
1
+ []
@@ -0,0 +1,65 @@
1
+ /**
2
+ * The trace doctrine — one home per sentence.
3
+ *
4
+ * The same handful of ideas (what the tree is, the trigger-node rule, the
5
+ * hypothesis form, where the full doc lives) used to be re-phrased in every
6
+ * prompt surface: the tool description, the parameter descriptions, the
7
+ * system-prompt core, the help text, and the reminder messages. They drifted
8
+ * in wording if not in content. Now each canonical sentence lives here once
9
+ * and the surfaces compose from it — same words everywhere, so the model
10
+ * gets one consistent vocabulary to anchor on.
11
+ *
12
+ * Surfaces deliberately keep their own granularity: the tool description is
13
+ * a one-liner, the system prompt carries the minimal core, and HELP_TEXT is
14
+ * the full reference. Progressive disclosure is the point; duplication is not.
15
+ *
16
+ * @module @elinpf/dsh-ops-tool-trace/doctrine
17
+ */
18
+ /** What the tree is, in one line. */
19
+ export declare const TREE_ONE_LINER = "\u7EF4\u62A4\u4E8B\u4EF6\u6392\u67E5\u7684\u8C03\u67E5\u6811: goal \u2192 milestone(\u5F85\u9A8C\u8BC1\u5047\u8BBE) \u2192 step(\u9A8C\u8BC1\u52A8\u4F5C)";
20
+ /** The question behind every parent_id decision. Also quoted verbatim by the
21
+ * nesting reminder. */
22
+ export declare const TRIGGER_NODE_QUESTION = "\u6211\u4E3A\u4EC0\u4E48\u73B0\u5728\u8981\u505A\u8FD9\u4E2A\u52A8\u4F5C?";
23
+ /** The trigger-node mapping: where a new node hangs, by what triggered it. */
24
+ export declare const TRIGGER_NODE_MAPPING = "\u8DDF\u8FDB\u67D0 step \u7684\u53D1\u73B0 \u2192 \u6302\u90A3\u4E2A step; \u9A8C\u8BC1\u67D0\u5047\u8BBE \u2192 \u6302\u8BE5 milestone; \u9876\u5C42\u5047\u8BBE \u2192 \"goal\"";
25
+ /** The full trigger-node rule, one line (system-prompt core + parent_id
26
+ * parameter description). */
27
+ export declare const TRIGGER_NODE_RULE = "parent_id \u7684\u552F\u4E00\u89C4\u5219 \u2014 \u6211\u4E3A\u4EC0\u4E48\u73B0\u5728\u8981\u505A\u8FD9\u4E2A\u52A8\u4F5C? \u8DDF\u8FDB\u67D0 step \u7684\u53D1\u73B0 \u2192 \u6302\u90A3\u4E2A step; \u9A8C\u8BC1\u67D0\u5047\u8BBE \u2192 \u6302\u8BE5 milestone; \u9876\u5C42\u5047\u8BBE \u2192 \"goal\"\u3002";
28
+ /** A milestone must be writable in this form, or it is not a hypothesis. */
29
+ export declare const HYPOTHESIS_FORM = "\"\u6211\u6000\u7591 X, \u56E0\u4E3A\u770B\u5230\u4E86 Y\"";
30
+ /**
31
+ * Hard-gate error for resolve on the goal while nodes are still undecided
32
+ * (not done / not dead_end). Lists the undecided nodes and points at the
33
+ * two ways forward: decide them (complete/abandon), or force — the explicit
34
+ * escape hatch for abandoning an investigation mid-way.
35
+ */
36
+ export declare function resolveGateError(undecided: Array<{
37
+ id: string;
38
+ status: string;
39
+ }>): string;
40
+ /** Where the full documentation lives. */
41
+ export declare const HELP_POINTER = "\u5B8C\u6574\u7528\u6CD5\u4E0E\u7EAA\u5F8B: \u8C03 `trace` action=help\u3002";
42
+ /**
43
+ * Soft hint for add_step: the parent is a milestone that already has
44
+ * completed steps with findings, so the new step may belong under one of
45
+ * those steps (drill-down) instead of flat under the milestone. A hint,
46
+ * never a rejection — flat-hanging is sometimes right. Fires ONCE per tree
47
+ * (latched in the tool); the pre-step nesting reminder is the backstop.
48
+ */
49
+ export declare function milestoneFollowUpHint(doneStepIds: string[]): string;
50
+ /** One-liner for the tool registry description. */
51
+ export declare const TOOL_DESCRIPTION = "\u7EF4\u62A4\u4E8B\u4EF6\u6392\u67E5\u7684\u8C03\u67E5\u6811: goal \u2192 milestone(\u5F85\u9A8C\u8BC1\u5047\u8BBE) \u2192 step(\u9A8C\u8BC1\u52A8\u4F5C)\u3002\u6BCF\u4E2A\u8282\u70B9\u7684 parent_id \u662F\u5B83\u7684\u89E6\u53D1\u8282\u70B9\u2014\u2014\u8BA9\u4F60\u6B64\u523B\u60F3\u505A\u8FD9\u4E2A\u52A8\u4F5C\u7684\u90A3\u4E2A\u8282\u70B9\u3002\u5B8C\u6574\u7528\u6CD5\u4E0E\u7EAA\u5F8B: \u8C03 `trace` action=help\u3002";
52
+ /**
53
+ * Minimal always-on core for the system prompt (registered through
54
+ * ops-prompts as a methodology section). The full doc is progressively
55
+ * disclosed through the `help` action; reminders deliver individual rules
56
+ * just-in-time.
57
+ */
58
+ export declare const STATIC_PROMPT: string;
59
+ /**
60
+ * Full usage documentation, progressively disclosed: the system prompt only
61
+ * carries the minimal core plus a pointer; the model pulls this via
62
+ * `trace` action=help when it needs the details.
63
+ */
64
+ export declare const HELP_TEXT: string;
65
+ //# sourceMappingURL=doctrine.d.ts.map
package/lib/index.d.ts ADDED
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Ops-trace: an investigation tree tool that replaces `todo_write` in the ops preset.
3
+ *
4
+ * Agent-driven, append-only event log, tree + unique resolved convergence terminal.
5
+ * See `.scratch/ops-trace/research/` for the full design.
6
+ *
7
+ * @module @elinpf/dsh-ops-tool-trace
8
+ */
9
+ import z from '@deepseek-ai/schemastery';
10
+ import { z as zod } from 'zod';
11
+ import type { Context } from '@deepseek-ai/cordis';
12
+ import type { OpsPromptsHandle } from '@elinpf/dsh-ops-prompts';
13
+ declare module '@deepseek-ai/cordis' {
14
+ interface Context {
15
+ opsPrompts?: OpsPromptsHandle;
16
+ sessionProjections?: {
17
+ register(def: {
18
+ key: string;
19
+ schema: unknown;
20
+ init: () => ForestState | null;
21
+ apply: (state: ForestState | null, event: FoldEvent) => ForestState | null;
22
+ view: (state: ForestState | null) => ForestState | null;
23
+ stateVersion: number;
24
+ }): () => void;
25
+ snapshot(session: {
26
+ id: string;
27
+ }): {
28
+ values: {
29
+ trace?: ForestState | null;
30
+ };
31
+ };
32
+ };
33
+ }
34
+ }
35
+ import type { ForestState } from './types.js';
36
+ declare const name = "ops-trace";
37
+ declare const inject: string[];
38
+ /**
39
+ * Schemastery configuration for the ops-trace tool consumer.
40
+ */
41
+ declare const Config: z<Schemastery.ObjectS<{
42
+ /** Idle reminder: nudge after this many steps without a trace update (default 5). */
43
+ idleReminderGapSteps: z<number, number>;
44
+ /** Idle reminder backoff ceiling (steps): the refire gap doubles per fire up to this cap (default 40). */
45
+ idleReminderBackoffCeilingSteps: z<number, number>;
46
+ /** Nesting reminder: fires when this many steps hang flat under milestones with nothing deeper (default 3). */
47
+ nestingReminderFlatSteps: z<number, number>;
48
+ }>, Schemastery.ObjectT<{
49
+ /** Idle reminder: nudge after this many steps without a trace update (default 5). */
50
+ idleReminderGapSteps: z<number, number>;
51
+ /** Idle reminder backoff ceiling (steps): the refire gap doubles per fire up to this cap (default 40). */
52
+ idleReminderBackoffCeilingSteps: z<number, number>;
53
+ /** Nesting reminder: fires when this many steps hang flat under milestones with nothing deeper (default 3). */
54
+ nestingReminderFlatSteps: z<number, number>;
55
+ }>>;
56
+ /**
57
+ * Fold one tool/call event into tree state (pure function, allocation-fresh).
58
+ * The projection reads tool/call events where name === 'trace' and
59
+ * parses the arguments JSON to reconstruct the tree.
60
+ * No custom session event types are needed — tool/call is a known type.
61
+ */
62
+ /** Minimal event shape that foldEvent reads from the session log. */
63
+ export interface FoldEvent {
64
+ type: string;
65
+ data: {
66
+ name?: string;
67
+ turn?: number;
68
+ step?: number;
69
+ arguments?: string;
70
+ };
71
+ }
72
+ declare function foldEvent(state: ForestState | null, event: FoldEvent): ForestState | null;
73
+ export declare const treeNodeSchema: zod.ZodObject<{
74
+ id: zod.ZodString;
75
+ title: zod.ZodString;
76
+ status: zod.ZodEnum<{
77
+ goal: "goal";
78
+ pending: "pending";
79
+ in_progress: "in_progress";
80
+ done: "done";
81
+ dead_end: "dead_end";
82
+ resolved: "resolved";
83
+ }>;
84
+ parent: zod.ZodNullable<zod.ZodString>;
85
+ turns: zod.ZodArray<zod.ZodNumber>;
86
+ summary: zod.ZodNullable<zod.ZodString>;
87
+ detail: zod.ZodNullable<zod.ZodString>;
88
+ caused_by: zod.ZodArray<zod.ZodString>;
89
+ }, zod.core.$strip>;
90
+ /**
91
+ * JSON-schema shape of one node, for the tool's output contract. The third
92
+ * declaration of the node shape (after the TreeNode interface and
93
+ * treeNodeSchema above) — its status enum derives from NODE_STATUSES, and
94
+ * tests/contract.spec.ts asserts all three field sets agree.
95
+ */
96
+ export declare const treeNodeJsonSchema: {
97
+ readonly type: "object";
98
+ readonly additionalProperties: false;
99
+ readonly properties: {
100
+ readonly id: {
101
+ readonly type: "string";
102
+ readonly required: true;
103
+ };
104
+ readonly title: {
105
+ readonly type: "string";
106
+ readonly required: true;
107
+ };
108
+ readonly status: {
109
+ readonly type: "string";
110
+ readonly required: true;
111
+ readonly enum: readonly ["goal", "pending", "in_progress", "done", "dead_end", "resolved"];
112
+ };
113
+ readonly parent: {
114
+ readonly required: true;
115
+ readonly oneOf: readonly [{
116
+ readonly type: "string";
117
+ }, {
118
+ readonly type: "null";
119
+ }];
120
+ };
121
+ readonly turns: {
122
+ readonly type: "array";
123
+ readonly required: true;
124
+ readonly items: {
125
+ readonly type: "number";
126
+ };
127
+ };
128
+ readonly summary: {
129
+ readonly required: true;
130
+ readonly oneOf: readonly [{
131
+ readonly type: "string";
132
+ }, {
133
+ readonly type: "null";
134
+ }];
135
+ };
136
+ readonly detail: {
137
+ readonly required: true;
138
+ readonly oneOf: readonly [{
139
+ readonly type: "string";
140
+ }, {
141
+ readonly type: "null";
142
+ }];
143
+ };
144
+ readonly caused_by: {
145
+ readonly type: "array";
146
+ readonly required: true;
147
+ readonly items: {
148
+ readonly type: "string";
149
+ };
150
+ };
151
+ };
152
+ };
153
+ declare const traceProjectionSchema: zod.ZodUnion<readonly [zod.ZodObject<{
154
+ trees: zod.ZodArray<zod.ZodObject<{
155
+ nodes: zod.ZodArray<zod.ZodObject<{
156
+ id: zod.ZodString;
157
+ title: zod.ZodString;
158
+ status: zod.ZodEnum<{
159
+ goal: "goal";
160
+ pending: "pending";
161
+ in_progress: "in_progress";
162
+ done: "done";
163
+ dead_end: "dead_end";
164
+ resolved: "resolved";
165
+ }>;
166
+ parent: zod.ZodNullable<zod.ZodString>;
167
+ turns: zod.ZodArray<zod.ZodNumber>;
168
+ summary: zod.ZodNullable<zod.ZodString>;
169
+ detail: zod.ZodNullable<zod.ZodString>;
170
+ caused_by: zod.ZodArray<zod.ZodString>;
171
+ }, zod.core.$strip>>;
172
+ resolved: zod.ZodBoolean;
173
+ }, zod.core.$strip>>;
174
+ }, zod.core.$strip>, zod.ZodNull]>;
175
+ /**
176
+ * The shared projection definition, registered host-plane by ops-trace-ui
177
+ * (the panel's package) and consumed here through snapshots. One home for
178
+ * key/schema/fold/stateVersion so the two packages can never drift apart.
179
+ */
180
+ export declare const traceProjection: {
181
+ key: string;
182
+ schema: zod.ZodUnion<readonly [zod.ZodObject<{
183
+ trees: zod.ZodArray<zod.ZodObject<{
184
+ nodes: zod.ZodArray<zod.ZodObject<{
185
+ id: zod.ZodString;
186
+ title: zod.ZodString;
187
+ status: zod.ZodEnum<{
188
+ goal: "goal";
189
+ pending: "pending";
190
+ in_progress: "in_progress";
191
+ done: "done";
192
+ dead_end: "dead_end";
193
+ resolved: "resolved";
194
+ }>;
195
+ parent: zod.ZodNullable<zod.ZodString>;
196
+ turns: zod.ZodArray<zod.ZodNumber>;
197
+ summary: zod.ZodNullable<zod.ZodString>;
198
+ detail: zod.ZodNullable<zod.ZodString>;
199
+ caused_by: zod.ZodArray<zod.ZodString>;
200
+ }, zod.core.$strip>>;
201
+ resolved: zod.ZodBoolean;
202
+ }, zod.core.$strip>>;
203
+ }, zod.core.$strip>, zod.ZodNull]>;
204
+ init: () => ForestState | null;
205
+ apply: typeof foldEvent;
206
+ view: (s: ForestState | null) => ForestState | null;
207
+ stateVersion: number;
208
+ };
209
+ declare function apply(ctx: Context, config: {
210
+ idleReminderGapSteps: number;
211
+ idleReminderBackoffCeilingSteps: number;
212
+ nestingReminderFlatSteps: number;
213
+ }): void;
214
+ export { Config, apply, inject, name, foldEvent, traceProjectionSchema };
215
+ //# sourceMappingURL=index.d.ts.map