@aiwayds/dsh-tui-pi 0.1.1 → 0.4.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/README.md +175 -41
- package/lib/agent-manager.d.ts +125 -0
- package/lib/agent-manager.js +298 -0
- package/lib/agent-manager.js.map +1 -0
- package/lib/agents.d.ts +30 -0
- package/lib/agents.js +489 -0
- package/lib/agents.js.map +1 -0
- package/lib/append-system.d.ts +2 -0
- package/lib/append-system.js +1 -1
- package/lib/append-system.js.map +1 -1
- package/lib/dsh-events.d.ts +12 -0
- package/lib/editor.d.ts +58 -0
- package/lib/editor.js +92 -0
- package/lib/editor.js.map +1 -1
- package/lib/footer.d.ts +46 -0
- package/lib/footer.js +65 -0
- package/lib/footer.js.map +1 -1
- package/lib/hotkeys.d.ts +93 -0
- package/lib/hotkeys.js +305 -0
- package/lib/hotkeys.js.map +1 -0
- package/lib/index.js +342 -61
- package/lib/index.js.map +1 -1
- package/lib/keymap.d.ts +243 -0
- package/lib/keymap.js +245 -0
- package/lib/keymap.js.map +1 -0
- package/lib/live-widgets.d.ts +59 -49
- package/lib/live-widgets.js +174 -117
- package/lib/live-widgets.js.map +1 -1
- package/lib/panels.d.ts +177 -0
- package/lib/panels.js +331 -0
- package/lib/panels.js.map +1 -0
- package/lib/selectors.d.ts +12 -1
- package/lib/selectors.js +1 -1
- package/lib/selectors.js.map +1 -1
- package/lib/session.d.ts +25 -0
- package/lib/session.js +173 -12
- package/lib/session.js.map +1 -1
- package/lib/settings.d.ts +1 -2
- package/lib/subagent-policy.d.ts +88 -0
- package/lib/subagent-policy.js +189 -0
- package/lib/subagent-policy.js.map +1 -0
- package/lib/subagent-viewer.d.ts +49 -0
- package/lib/subagent-viewer.js +523 -0
- package/lib/subagent-viewer.js.map +1 -0
- package/lib/theme/index.js +4 -0
- package/lib/theme/index.js.map +1 -1
- package/lib/theme/palette.d.ts +21 -3
- package/lib/theme/palette.js +27 -6
- package/lib/theme/palette.js.map +1 -1
- package/lib/theme-settings.d.ts +71 -9
- package/lib/theme-settings.js +145 -21
- package/lib/theme-settings.js.map +1 -1
- package/lib/tui.d.ts +23 -9
- package/lib/tui.js +110 -7
- package/lib/tui.js.map +1 -1
- package/package.json +3 -4
- package/patches/@earendil-works__pi-tui.patch +206 -2
- package/scripts/dev-install.mjs +87 -0
- package/scripts/link-dsh-closure.mjs +85 -0
- package/templates/agents/ArtyDuck.md +11 -0
- package/templates/agents/oldfox.md +33 -0
- package/templates/agents/workhorse.md +34 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subagent policy for the TUI.
|
|
3
|
+
*
|
|
4
|
+
* Three knobs, all read live from the `dsh-tui` settings section at every
|
|
5
|
+
* decision point — no watcher needed (the /settings browser hot-applies, so
|
|
6
|
+
* the next guard execution / turn count reads the new value):
|
|
7
|
+
* - `maxAgents` caps concurrent live children. A `tools.guard` registered on
|
|
8
|
+
* the plugin root ctx denies model-facing spawn tools once the bridge's
|
|
9
|
+
* live child count meets the cap. Registered globally, every agent in the
|
|
10
|
+
* process obeys — this TUI's session and any delegation nesting. The
|
|
11
|
+
* workflow/ralph fan-out bypasses the tool pipeline (its worker thread
|
|
12
|
+
* spawns through the subagent provider directly), so a `subagent/start`
|
|
13
|
+
* listener prunes any newcomer that slips past the guard.
|
|
14
|
+
* - `disableSubagent` disables the plain native `subagent` tool: its calls
|
|
15
|
+
* are denied for every agent (and it is hidden from the main agent's
|
|
16
|
+
* catalog), so delegation goes through registered agent definitions
|
|
17
|
+
* (`~/.dsh/agents/*.md` via the registry's `use_agent`). `subagent_fork`,
|
|
18
|
+
* `workflow` and `ralph` stay available.
|
|
19
|
+
* - `maxRounds` caps a child's completed turns: on the bridge's `onTurnCount`
|
|
20
|
+
* the policy injects one plugin-sourced user message telling the child to
|
|
21
|
+
* wrap up. Queued as the child's next turn, it never interrupts work
|
|
22
|
+
* already underway.
|
|
23
|
+
*/
|
|
24
|
+
import { createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
25
|
+
import { SessionId } from '@deepseek-ai/dsh-session';
|
|
26
|
+
import { readSubagentLimits } from "./theme-settings.js";
|
|
27
|
+
/**
|
|
28
|
+
* Tool names the maxAgents guard intercepts: the native subagent tool, the
|
|
29
|
+
* one-shot fork variant, the workflow fan-out entrypoint, its ralph-loop
|
|
30
|
+
* sibling, and registry plugins' `use_agent`.
|
|
31
|
+
*/
|
|
32
|
+
export const SPAWN_TOOLS = [
|
|
33
|
+
'subagent',
|
|
34
|
+
'subagent_fork',
|
|
35
|
+
'workflow',
|
|
36
|
+
'ralph',
|
|
37
|
+
'use_agent',
|
|
38
|
+
];
|
|
39
|
+
/**
|
|
40
|
+
* The native plain one-shot spawn tool - the only spawn tool `disableSubagent`
|
|
41
|
+
* fences. Deliberately a single name: the TUI's user delegates through
|
|
42
|
+
* registered agents (`~/.dsh/agents/*.md` via `use_agent`) and wants ONLY the
|
|
43
|
+
* plain `subagent` tool off; `subagent_fork` (fork a running session),
|
|
44
|
+
* `workflow` and `ralph` (fan-out loops) stay available.
|
|
45
|
+
*/
|
|
46
|
+
export const NATIVE_SPAWN_TOOLS = [
|
|
47
|
+
'subagent',
|
|
48
|
+
];
|
|
49
|
+
/**
|
|
50
|
+
* Hide the plain `subagent` tool from ONE agent's tool catalog (best-effort).
|
|
51
|
+
* The disableSubagent guard DENIES calls at execution; this additionally
|
|
52
|
+
* makes the tool INVISIBLE to the model, so the agent sees the registered
|
|
53
|
+
* `use_agent` as its delegation entry and never attempts the fenced tool.
|
|
54
|
+
*
|
|
55
|
+
* `tools.restrict` requires a scoped context (it throws on a plain plugin
|
|
56
|
+
* ctx) - the agent setup passes its scoped `agentCtx`, exactly the surface
|
|
57
|
+
* dsh-subagent uses for `deep: 0` leaves. Best-effort by design: an absent
|
|
58
|
+
* tools service, or a restrict failure (an unknown tool name in this
|
|
59
|
+
* profile, a transient registration race), degrades silently - the live
|
|
60
|
+
* disableSubagent guard remains the enforcement backstop, so the fence is
|
|
61
|
+
* NEVER weaker for hiding. Restriction is a creation-time snapshot: a
|
|
62
|
+
* disableSubagent toggle takes effect for agents created afterwards (the
|
|
63
|
+
* guard, being live, applies immediately in both directions).
|
|
64
|
+
*/
|
|
65
|
+
export function installSpawnToolFence(agentCtx) {
|
|
66
|
+
const tools = agentCtx.get('tools');
|
|
67
|
+
if (tools?.restrict === undefined)
|
|
68
|
+
return;
|
|
69
|
+
try {
|
|
70
|
+
tools.restrict({ deny: [...NATIVE_SPAWN_TOOLS] });
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// Cosmetic hide only - never fail the agent setup over it. The guard
|
|
74
|
+
// below still denies the subagent tool at execution time.
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/** Injected into a child that reached `maxRounds` — wrap up and report back. */
|
|
78
|
+
export const SUMMARY_MESSAGE = '总结和结束这个任务,汇报情况。';
|
|
79
|
+
/**
|
|
80
|
+
* Install the subagent policy on the plugin root ctx.
|
|
81
|
+
*
|
|
82
|
+
* @param ctx - plugin context. The settings-service lookup inside the helpers
|
|
83
|
+
* is defensive: a settings-less deployment resolves the defaults, so the
|
|
84
|
+
* policy still enforces its documented caps.
|
|
85
|
+
* @param state - the host's live view (bridge.getLiveChildren /
|
|
86
|
+
* bridge.getTurnCount). The guard and the round injection read it at every
|
|
87
|
+
* decision — no snapshot, no watch.
|
|
88
|
+
* @returns the policy handle wired to the bridge's `onTurnCount`.
|
|
89
|
+
*/
|
|
90
|
+
export function applySubagentPolicy(ctx, state) {
|
|
91
|
+
const disposers = [];
|
|
92
|
+
const injected = new Set();
|
|
93
|
+
// maxAgents guard: global (plugin root ctx), every spawn-tool call is
|
|
94
|
+
// denied while live children are at the cap. Zero disables the guard.
|
|
95
|
+
// The cap is approximate, not a hard admission lock: a burst of parallel
|
|
96
|
+
// spawn calls can briefly overshoot before the bridge's firehose discovery
|
|
97
|
+
// counts the newcomers — the subagent/start backstop below prunes the
|
|
98
|
+
// overshoot, and the next spawn's guard reads the caught-up count.
|
|
99
|
+
//
|
|
100
|
+
// disableSubagent fence: the plain native `subagent` tool is denied
|
|
101
|
+
// outright (checked before the cap - a tool violation is the reason even
|
|
102
|
+
// when the cap would also deny). `use_agent`, the fork/workflow/ralph
|
|
103
|
+
// variants and every non-spawn tool pass through to the cap check below.
|
|
104
|
+
const tools = ctx.get('tools');
|
|
105
|
+
if (tools?.guard !== undefined) {
|
|
106
|
+
disposers.push(tools.guard((exec) => {
|
|
107
|
+
if (!SPAWN_TOOLS.includes(exec.name))
|
|
108
|
+
return undefined;
|
|
109
|
+
if (readSubagentLimits(ctx).disableSubagent && NATIVE_SPAWN_TOOLS.includes(exec.name)) {
|
|
110
|
+
return `Tool "subagent" is disabled here - delegation goes through registered agents. `
|
|
111
|
+
+ 'Dispatch the work through the use_agent tool with one of the registered agent names instead.';
|
|
112
|
+
}
|
|
113
|
+
const maxAgents = readSubagentLimits(ctx).maxAgents;
|
|
114
|
+
if (maxAgents <= 0)
|
|
115
|
+
return undefined;
|
|
116
|
+
const live = state.getLive();
|
|
117
|
+
if (live.length < maxAgents)
|
|
118
|
+
return undefined;
|
|
119
|
+
const running = live.map((agent) => agent.label).join(', ');
|
|
120
|
+
return `Agent limit reached (${live.length}/${maxAgents}): ${running} still running — wait for one to finish or use list_agents before spawning more.`;
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
// Workflow/ralph backstop: the worker thread fans children out through the
|
|
124
|
+
// subagent provider, never through the tool pipeline — the only leak past
|
|
125
|
+
// the guard. Prune a newcomer whose start overshoots the cap. The event is
|
|
126
|
+
// foreign to this bundle's type environment (`@deepseek-ai/dsh-subagent` is
|
|
127
|
+
// not installed), so the subscription rides the base event bus rather than
|
|
128
|
+
// the typed `ctx.on`.
|
|
129
|
+
const eventDisposer = ctx.events.on('subagent/start', (info) => {
|
|
130
|
+
if (info?.id === undefined)
|
|
131
|
+
return;
|
|
132
|
+
const maxAgents = readSubagentLimits(ctx).maxAgents;
|
|
133
|
+
if (maxAgents <= 0)
|
|
134
|
+
return;
|
|
135
|
+
// Exclude the newcomer itself: whether or not its own session events
|
|
136
|
+
// have reached the bridge's count yet (the subagent/start notification
|
|
137
|
+
// and the child's first firehose event race), the child is pruned only
|
|
138
|
+
// when the OTHER live children already fill the cap — a legitimate
|
|
139
|
+
// Nth-at-cap child is never cancelled on either ordering.
|
|
140
|
+
const live = state.getLive().filter(view => view.childId !== String(info.id));
|
|
141
|
+
if (live.length < maxAgents)
|
|
142
|
+
return;
|
|
143
|
+
ctx.agents.get(info.id)?.cancel({
|
|
144
|
+
kind: 'hook',
|
|
145
|
+
reason: 'over the dsh-tui maxAgents policy cap — prune a fan-out child',
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
disposers.push(eventDisposer);
|
|
149
|
+
/**
|
|
150
|
+
* Bridge turn-count sink: inject the summary message exactly once per
|
|
151
|
+
* child, at the first turn that reaches a positive `maxRounds`. A missing
|
|
152
|
+
* agent (cold, or transiently unregistered) is skipped silently; a settled
|
|
153
|
+
* child is skipped too — injecting into a finished one would wake it for a
|
|
154
|
+
* pointless wrap-up round (continuable children that resume later get their
|
|
155
|
+
* chance on the next counted turn). Repeated injections are impossible by
|
|
156
|
+
* construction (the set is only written on success).
|
|
157
|
+
*/
|
|
158
|
+
function onTurnCount(childId, count) {
|
|
159
|
+
if (injected.has(childId))
|
|
160
|
+
return;
|
|
161
|
+
const maxRounds = readSubagentLimits(ctx).maxRounds;
|
|
162
|
+
if (maxRounds <= 0)
|
|
163
|
+
return;
|
|
164
|
+
if (count < maxRounds)
|
|
165
|
+
return;
|
|
166
|
+
if (state.isSettled(childId))
|
|
167
|
+
return;
|
|
168
|
+
const agent = ctx.agents.get(SessionId(childId));
|
|
169
|
+
if (agent === undefined)
|
|
170
|
+
return;
|
|
171
|
+
injected.add(childId);
|
|
172
|
+
agent.followup(createUserMessage({
|
|
173
|
+
content: [{ type: 'text', text: SUMMARY_MESSAGE }],
|
|
174
|
+
source: { kind: 'plugin', plugin: 'dsh-tui-pi' },
|
|
175
|
+
}));
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
onTurnCount,
|
|
179
|
+
dispose() {
|
|
180
|
+
for (const dispose of disposers.splice(0)) {
|
|
181
|
+
try {
|
|
182
|
+
dispose();
|
|
183
|
+
}
|
|
184
|
+
catch { /* contained */ }
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=subagent-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subagent-policy.js","sourceRoot":"","sources":["../src/subagent-policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The subagent viewer — the Ctrl+G surface. Two levels, both on the shared
|
|
3
|
+
* PanelHost overlay (80%): a SelectList picker over the bridge's child views,
|
|
4
|
+
* then a live transcript panel for one child's buffered event log.
|
|
5
|
+
*
|
|
6
|
+
* Picker rows (running first, then the five most recent settled) carry the
|
|
7
|
+
* full picture of a delegation: status icon, label, delegation mode, rounds
|
|
8
|
+
* against the policy cap (`maxRounds` from `readSubagentLimits`, only shown
|
|
9
|
+
* when > 0), token spend (k) and elapsed time. Settled rows read as faded
|
|
10
|
+
* because their status icon and the muted description column mark the outcome.
|
|
11
|
+
*
|
|
12
|
+
* Transcript panel: one human-readable line per buffered SessionEvent
|
|
13
|
+
* (user/assistant messages, tool calls + truncated results, turns, descriptor,
|
|
14
|
+
* todos). The log is a capped per-child ring buffer (2000 events); a dropped
|
|
15
|
+
* head is reported at the top. While the panel is open a ~300ms timer rebuilds
|
|
16
|
+
* the lines from the bridge and re-renders, and the view follows the tail like
|
|
17
|
+
* a ScrollView follow:'end' (an explicit scroll-up detaches; reaching the
|
|
18
|
+
* bottom re-attaches). Esc closes, or a deliberate double-`x` within
|
|
19
|
+
* `DOUBLE_PRESS_MS`.
|
|
20
|
+
*/
|
|
21
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
22
|
+
import { type SelectItem, type TUI } from '@earendil-works/pi-tui';
|
|
23
|
+
import type { AgentView } from './dsh-events.ts';
|
|
24
|
+
import type { DshSessionBridge } from './session.ts';
|
|
25
|
+
import { type TuiTheme } from './theme/index.ts';
|
|
26
|
+
/**
|
|
27
|
+
* The picker rows: running children first (the live items the key is for),
|
|
28
|
+
* then the five most recent settled ones (newest settle first). Each row
|
|
29
|
+
* reads `⠋ label [mode] · rounds N[/max]` with the token spend and elapsed
|
|
30
|
+
* seconds in the muted description column.
|
|
31
|
+
*/
|
|
32
|
+
export declare function pickerItems(views: readonly AgentView[], getTurnCount: (childId: string) => number, maxRounds: number): SelectItem[];
|
|
33
|
+
/**
|
|
34
|
+
* The next selected index after a picker items swap, preserving the selection
|
|
35
|
+
* by item value. `previous === undefined` (no selection yet) starts at 0; a
|
|
36
|
+
* value that dropped off the new list (e.g. a settled child fell out of the
|
|
37
|
+
* recent-settled cap) clamps to the last row rather than resetting the user
|
|
38
|
+
* to the top. Pure and exported for the regression test.
|
|
39
|
+
*/
|
|
40
|
+
export declare function nextSelectedIndex(items: readonly SelectItem[], previous: string | undefined): number;
|
|
41
|
+
/**
|
|
42
|
+
* Open the subagent picker / viewer. A SelectList of the bridge's child views
|
|
43
|
+
* (running first, then the five recent settled) opens; Enter opens a
|
|
44
|
+
* live-refreshing transcript panel for that child. An empty list (no running,
|
|
45
|
+
* no settled) closes immediately. Focus returns to `restoreFocus` on close;
|
|
46
|
+
* the promise settles when the viewer closes (value is meaningless — index.ts
|
|
47
|
+
* never branches on it).
|
|
48
|
+
*/
|
|
49
|
+
export declare function openSubagentViewer(ctx: Context, tui: TUI, theme: TuiTheme, bridge: DshSessionBridge, restoreFocus: () => void): Promise<void>;
|