@duckmind/dm-darwin-arm64 0.13.6 → 0.13.8
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/dm +0 -0
- package/extensions/.dm-extensions.json +26 -2
- package/extensions/dm-phone/README.md +23 -0
- package/extensions/dm-phone/index.ts +12 -0
- package/extensions/dm-phone/node_modules/.package-lock.json +29 -0
- package/extensions/dm-phone/node_modules/ws/LICENSE +20 -0
- package/extensions/dm-phone/node_modules/ws/README.md +548 -0
- package/extensions/dm-phone/node_modules/ws/browser.js +8 -0
- package/extensions/dm-phone/node_modules/ws/index.js +22 -0
- package/extensions/dm-phone/node_modules/ws/lib/buffer-util.js +131 -0
- package/extensions/dm-phone/node_modules/ws/lib/constants.js +19 -0
- package/extensions/dm-phone/node_modules/ws/lib/event-target.js +292 -0
- package/extensions/dm-phone/node_modules/ws/lib/extension.js +203 -0
- package/extensions/dm-phone/node_modules/ws/lib/limiter.js +55 -0
- package/extensions/dm-phone/node_modules/ws/lib/permessage-deflate.js +528 -0
- package/extensions/dm-phone/node_modules/ws/lib/receiver.js +706 -0
- package/extensions/dm-phone/node_modules/ws/lib/sender.js +602 -0
- package/extensions/dm-phone/node_modules/ws/lib/stream.js +161 -0
- package/extensions/dm-phone/node_modules/ws/lib/subprotocol.js +62 -0
- package/extensions/dm-phone/node_modules/ws/lib/validation.js +152 -0
- package/extensions/dm-phone/node_modules/ws/lib/websocket-server.js +554 -0
- package/extensions/dm-phone/node_modules/ws/lib/websocket.js +1393 -0
- package/extensions/dm-phone/node_modules/ws/package.json +70 -0
- package/extensions/dm-phone/node_modules/ws/wrapper.mjs +21 -0
- package/extensions/dm-phone/package-lock.json +66 -0
- package/extensions/dm-phone/package.json +35 -0
- package/extensions/dm-phone/phone-session-pool.ts +8 -0
- package/extensions/dm-phone/public/app/attachments.js +233 -0
- package/extensions/dm-phone/public/app/autocomplete-controller.js +81 -0
- package/extensions/dm-phone/public/app/autocomplete.js +135 -0
- package/extensions/dm-phone/public/app/bindings.js +178 -0
- package/extensions/dm-phone/public/app/command-catalog.js +76 -0
- package/extensions/dm-phone/public/app/commands.js +370 -0
- package/extensions/dm-phone/public/app/constants.js +60 -0
- package/extensions/dm-phone/public/app/formatters.js +131 -0
- package/extensions/dm-phone/public/app/handlers.js +442 -0
- package/extensions/dm-phone/public/app/main.js +6 -0
- package/extensions/dm-phone/public/app/markdown.js +105 -0
- package/extensions/dm-phone/public/app/messages.js +418 -0
- package/extensions/dm-phone/public/app/sheet-actions.js +113 -0
- package/extensions/dm-phone/public/app/sheet-navigation.js +19 -0
- package/extensions/dm-phone/public/app/sheets-view.js +272 -0
- package/extensions/dm-phone/public/app/state.js +95 -0
- package/extensions/dm-phone/public/app/tool-rendering.js +562 -0
- package/extensions/dm-phone/public/app/transport.js +176 -0
- package/extensions/dm-phone/public/app/ui.js +409 -0
- package/extensions/dm-phone/public/app.js +1 -0
- package/extensions/dm-phone/public/icon.svg +15 -0
- package/extensions/dm-phone/public/index.html +147 -0
- package/extensions/dm-phone/public/manifest.webmanifest +17 -0
- package/extensions/dm-phone/public/styles.css +1139 -0
- package/extensions/dm-phone/public/sw.js +78 -0
- package/extensions/dm-phone/src/extension/phone-args.ts +121 -0
- package/extensions/dm-phone/src/extension/phone-paths.ts +250 -0
- package/extensions/dm-phone/src/extension/phone-quota.ts +188 -0
- package/extensions/dm-phone/src/extension/phone-runtime.ts +154 -0
- package/extensions/dm-phone/src/extension/phone-server-runtime.ts +1217 -0
- package/extensions/dm-phone/src/extension/phone-sessions.ts +139 -0
- package/extensions/dm-phone/src/extension/phone-static.ts +30 -0
- package/extensions/dm-phone/src/extension/phone-tailscale.ts +148 -0
- package/extensions/dm-phone/src/extension/phone-theme.ts +85 -0
- package/extensions/dm-phone/src/extension/register-phone-child-extension.ts +112 -0
- package/extensions/dm-phone/src/extension/register-phone-extension.ts +106 -0
- package/extensions/dm-phone/src/extension/types.ts +73 -0
- package/extensions/dm-phone/src/session-pool/parent-session-worker.ts +881 -0
- package/extensions/dm-phone/src/session-pool/session-pool.ts +470 -0
- package/extensions/dm-phone/src/session-pool/session-worker.ts +734 -0
- package/extensions/dm-phone/src/session-pool/types.ts +105 -0
- package/extensions/dm-phone/src/session-pool/utils.ts +23 -0
- package/extensions/dm-subagents/agent-management.ts +15 -6
- package/extensions/dm-subagents/agent-manager-detail.ts +12 -2
- package/extensions/dm-subagents/agent-manager-edit.ts +75 -23
- package/extensions/dm-subagents/agent-manager-list.ts +9 -2
- package/extensions/dm-subagents/agent-manager.ts +199 -11
- package/extensions/dm-subagents/agents.ts +315 -20
- package/extensions/dm-ultrathink/README.md +5 -0
- package/extensions/dm-ultrathink/src/naming.ts +75 -3
- package/package.json +1 -1
|
@@ -3,7 +3,15 @@ import * as path from "node:path";
|
|
|
3
3
|
import type { Theme } from "@mariozechner/pi-coding-agent";
|
|
4
4
|
import type { Component, TUI } from "@mariozechner/pi-tui";
|
|
5
5
|
import { matchesKey, truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
|
|
6
|
-
import
|
|
6
|
+
import {
|
|
7
|
+
buildBuiltinOverrideConfig,
|
|
8
|
+
discoverAgentsAll,
|
|
9
|
+
removeBuiltinAgentOverride,
|
|
10
|
+
saveBuiltinAgentOverride,
|
|
11
|
+
type AgentConfig,
|
|
12
|
+
type BuiltinAgentOverrideBase,
|
|
13
|
+
type ChainConfig,
|
|
14
|
+
} from "./agents.ts";
|
|
7
15
|
import { serializeAgent } from "./agent-serializer.ts";
|
|
8
16
|
import { TEMPLATE_ITEMS, type AgentTemplate, type TemplateItem } from "./agent-templates.ts";
|
|
9
17
|
import { parseChain, serializeChain } from "./chain-serializer.ts";
|
|
@@ -11,7 +19,7 @@ import { renderList, handleListInput, type ListAgent, type ListState, type ListA
|
|
|
11
19
|
import { createParallelState, handleParallelInput, renderParallel, formatParallelTitle, type ParallelState, type AgentOption } from "./agent-manager-parallel.ts";
|
|
12
20
|
import { renderDetail, handleDetailInput, renderTaskInput, type DetailState, type DetailAction } from "./agent-manager-detail.ts";
|
|
13
21
|
import { renderChainDetail, handleChainDetailInput, type ChainDetailAction, type ChainDetailState } from "./agent-manager-chain-detail.ts";
|
|
14
|
-
import { createEditState, handleEditInput, renderEdit, type EditScreen, type EditState, type ModelInfo, type SkillInfo } from "./agent-manager-edit.ts";
|
|
22
|
+
import { createEditState, handleEditInput, renderEdit, type EditField, type EditScreen, type EditState, type ModelInfo, type SkillInfo } from "./agent-manager-edit.ts";
|
|
15
23
|
import { createEditorState, ensureCursorVisible, getCursorDisplayPos, handleEditorInput, renderEditor, wrapText } from "./text-editor.ts";
|
|
16
24
|
import type { TextEditorState } from "./text-editor.ts";
|
|
17
25
|
import { loadRunsForAgent } from "./run-history.ts";
|
|
@@ -24,14 +32,39 @@ export type ManagerResult =
|
|
|
24
32
|
| { action: "launch-chain"; chain: ChainConfig; task: string; skipClarify?: boolean }
|
|
25
33
|
| undefined;
|
|
26
34
|
|
|
27
|
-
export interface AgentData { builtin: AgentConfig[]; user: AgentConfig[]; project: AgentConfig[]; chains: ChainConfig[]; userDir: string; projectDir: string | null; cwd: string; }
|
|
28
|
-
type ManagerScreen = "list" | "detail" | "chain-detail" | "edit" | "edit-field" | "edit-prompt" | "task-input" | "confirm-delete" | "name-input" | "chain-edit" | "template-select" | "parallel-builder";
|
|
35
|
+
export interface AgentData { builtin: AgentConfig[]; user: AgentConfig[]; project: AgentConfig[]; chains: ChainConfig[]; userDir: string; projectDir: string | null; userSettingsPath: string; projectSettingsPath: string | null; cwd: string; }
|
|
36
|
+
type ManagerScreen = "list" | "detail" | "chain-detail" | "edit" | "edit-field" | "edit-prompt" | "task-input" | "confirm-delete" | "name-input" | "chain-edit" | "template-select" | "parallel-builder" | "override-scope";
|
|
29
37
|
interface AgentEntry { id: string; kind: "agent"; config: AgentConfig; isNew: boolean; }
|
|
30
38
|
interface ChainEntry { id: string; kind: "chain"; config: ChainConfig; }
|
|
31
39
|
interface NameInputState { mode: "new-agent" | "clone-agent" | "clone-chain" | "new-chain"; editor: TextEditorState; scope: "user" | "project"; allowProject: boolean; sourceId?: string; template?: AgentTemplate; error?: string; }
|
|
32
40
|
interface StatusMessage { text: string; type: "error" | "info"; }
|
|
41
|
+
interface OverrideScopeState { selectedScope: "user" | "project"; allowProject: boolean; }
|
|
33
42
|
|
|
34
|
-
|
|
43
|
+
const BUILTIN_OVERRIDE_FIELDS: EditField[] = ["model", "fallbackModels", "thinking", "tools", "skills", "prompt"];
|
|
44
|
+
|
|
45
|
+
function cloneConfig(config: AgentConfig): AgentConfig {
|
|
46
|
+
return {
|
|
47
|
+
...config,
|
|
48
|
+
tools: config.tools ? [...config.tools] : undefined,
|
|
49
|
+
mcpDirectTools: config.mcpDirectTools ? [...config.mcpDirectTools] : undefined,
|
|
50
|
+
skills: config.skills ? [...config.skills] : undefined,
|
|
51
|
+
fallbackModels: config.fallbackModels ? [...config.fallbackModels] : undefined,
|
|
52
|
+
defaultReads: config.defaultReads ? [...config.defaultReads] : undefined,
|
|
53
|
+
extraFields: config.extraFields ? { ...config.extraFields } : undefined,
|
|
54
|
+
override: config.override
|
|
55
|
+
? {
|
|
56
|
+
...config.override,
|
|
57
|
+
base: {
|
|
58
|
+
...config.override.base,
|
|
59
|
+
fallbackModels: config.override.base.fallbackModels ? [...config.override.base.fallbackModels] : undefined,
|
|
60
|
+
skills: config.override.base.skills ? [...config.override.base.skills] : undefined,
|
|
61
|
+
tools: config.override.base.tools ? [...config.override.base.tools] : undefined,
|
|
62
|
+
mcpDirectTools: config.override.base.mcpDirectTools ? [...config.override.base.mcpDirectTools] : undefined,
|
|
63
|
+
},
|
|
64
|
+
}
|
|
65
|
+
: undefined,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
35
68
|
function cloneChainConfig(config: ChainConfig): ChainConfig { return { ...config, steps: config.steps.map((step) => ({ ...step, reads: Array.isArray(step.reads) ? [...step.reads] : step.reads, skills: Array.isArray(step.skills) ? [...step.skills] : step.skills })), extraFields: config.extraFields ? { ...config.extraFields } : undefined }; }
|
|
36
69
|
function slugTemplateName(name: string): string { return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, ""); }
|
|
37
70
|
function nextSelectableIndex(items: TemplateItem[], current: number, direction: 1 | -1): number { let next = current + direction; while (next >= 0 && next < items.length && items[next]!.type === "separator") next += direction; if (next < 0 || next >= items.length) return current; return next; }
|
|
@@ -60,6 +93,8 @@ export class AgentManagerComponent implements Component {
|
|
|
60
93
|
private taskBackScreen: ManagerScreen = "list";
|
|
61
94
|
private templateCursor = 0;
|
|
62
95
|
private statusMessage?: StatusMessage;
|
|
96
|
+
private overrideScopeState: OverrideScopeState | null = null;
|
|
97
|
+
private builtinOverrideScope: "user" | "project" | null = null;
|
|
63
98
|
private nextId = 1;
|
|
64
99
|
private tui: TUI;
|
|
65
100
|
private theme: Theme;
|
|
@@ -86,15 +121,57 @@ export class AgentManagerComponent implements Component {
|
|
|
86
121
|
|
|
87
122
|
private getAgentEntry(id: string | null): AgentEntry | undefined { if (!id) return undefined; return this.agents.find((entry) => entry.id === id); }
|
|
88
123
|
private getChainEntry(id: string | null): ChainEntry | undefined { if (!id) return undefined; return this.chains.find((entry) => entry.id === id); }
|
|
89
|
-
private listAgents(): ListAgent[] { const a = this.agents.map((entry) => ({ id: entry.id, name: entry.config.name, description: entry.config.description, model: entry.config.model, source: entry.config.source, kind: "agent" as const })); const c = this.chains.map((entry) => ({ id: entry.id, name: entry.config.name, description: entry.config.description, source: entry.config.source, kind: "chain" as const, stepCount: entry.config.steps.length })); return [...a, ...c]; }
|
|
124
|
+
private listAgents(): ListAgent[] { const a = this.agents.map((entry) => ({ id: entry.id, name: entry.config.name, description: entry.config.description, model: entry.config.model, source: entry.config.source, overrideScope: entry.config.override?.scope, kind: "agent" as const })); const c = this.chains.map((entry) => ({ id: entry.id, name: entry.config.name, description: entry.config.description, source: entry.config.source, kind: "chain" as const, stepCount: entry.config.steps.length })); return [...a, ...c]; }
|
|
90
125
|
private clearStatus(): void { this.statusMessage = undefined; }
|
|
91
126
|
|
|
127
|
+
private resolveBuiltinOverrideBase(entry: AgentEntry): BuiltinAgentOverrideBase {
|
|
128
|
+
if (entry.config.override) return entry.config.override.base;
|
|
129
|
+
return {
|
|
130
|
+
model: entry.config.model,
|
|
131
|
+
fallbackModels: entry.config.fallbackModels ? [...entry.config.fallbackModels] : undefined,
|
|
132
|
+
thinking: entry.config.thinking,
|
|
133
|
+
systemPrompt: entry.config.systemPrompt,
|
|
134
|
+
skills: entry.config.skills ? [...entry.config.skills] : undefined,
|
|
135
|
+
tools: entry.config.tools ? [...entry.config.tools] : undefined,
|
|
136
|
+
mcpDirectTools: entry.config.mcpDirectTools ? [...entry.config.mcpDirectTools] : undefined,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private refreshAgentData(agentName?: string, chainName?: string): void {
|
|
141
|
+
this.agentData = { ...discoverAgentsAll(this.agentData.cwd), cwd: this.agentData.cwd };
|
|
142
|
+
this.nextId = 1;
|
|
143
|
+
this.loadEntries();
|
|
144
|
+
if (agentName) {
|
|
145
|
+
const entry = this.agents.find((candidate) => candidate.config.name === agentName);
|
|
146
|
+
this.currentAgentId = entry?.id ?? null;
|
|
147
|
+
}
|
|
148
|
+
if (chainName) {
|
|
149
|
+
const entry = this.chains.find((candidate) => candidate.config.name === chainName);
|
|
150
|
+
this.currentChainId = entry?.id ?? null;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
92
154
|
private removeAgentEntry(entry: AgentEntry): void { this.agents = this.agents.filter((e) => e.id !== entry.id); this.listState.selected = this.listState.selected.filter((id) => id !== entry.id); }
|
|
93
155
|
private removeChainEntry(entry: ChainEntry): void { this.chains = this.chains.filter((e) => e.id !== entry.id); }
|
|
94
156
|
|
|
95
157
|
private enterDetail(entry: AgentEntry): void { this.currentAgentId = entry.id; this.detailState = { resolved: true, scrollOffset: 0, recentRuns: loadRunsForAgent(entry.config.name).slice(0, 5) }; this.screen = "detail"; }
|
|
96
158
|
private enterChainDetail(entry: ChainEntry): void { this.currentChainId = entry.id; this.chainDetailState = { scrollOffset: 0 }; this.screen = "chain-detail"; }
|
|
97
|
-
private enterEdit(entry: AgentEntry): void { this.currentAgentId = entry.id; this.editState = createEditState(entry.config, entry.isNew, this.models, this.skills); this.screen = "edit"; }
|
|
159
|
+
private enterEdit(entry: AgentEntry): void { this.currentAgentId = entry.id; this.builtinOverrideScope = null; this.editState = createEditState(entry.config, entry.isNew, this.models, this.skills); this.screen = "edit"; }
|
|
160
|
+
private enterBuiltinOverrideScope(entry: AgentEntry): void {
|
|
161
|
+
this.currentAgentId = entry.id;
|
|
162
|
+
this.overrideScopeState = { selectedScope: this.agentData.projectSettingsPath ? "project" : "user", allowProject: Boolean(this.agentData.projectSettingsPath) };
|
|
163
|
+
this.screen = "override-scope";
|
|
164
|
+
}
|
|
165
|
+
private enterBuiltinOverrideEdit(entry: AgentEntry, scope: "user" | "project"): void {
|
|
166
|
+
this.currentAgentId = entry.id;
|
|
167
|
+
this.builtinOverrideScope = scope;
|
|
168
|
+
this.editState = createEditState(entry.config, false, this.models, this.skills, {
|
|
169
|
+
fields: BUILTIN_OVERRIDE_FIELDS,
|
|
170
|
+
title: `Builtin Override: ${entry.config.name} [${scope}]`,
|
|
171
|
+
overrideBase: this.resolveBuiltinOverrideBase(entry),
|
|
172
|
+
});
|
|
173
|
+
this.screen = "edit";
|
|
174
|
+
}
|
|
98
175
|
private enterParallelBuilder(ids: string[]): void {
|
|
99
176
|
const names = ids.map((id) => this.getAgentEntry(id)?.config.name).filter((n): n is string => Boolean(n));
|
|
100
177
|
if (names.length === 0) return;
|
|
@@ -127,6 +204,27 @@ export class AgentManagerComponent implements Component {
|
|
|
127
204
|
|
|
128
205
|
private saveEdit(): boolean {
|
|
129
206
|
const edit = this.editState; if (!edit) return false; const entry = this.getAgentEntry(this.currentAgentId); if (!entry) return false;
|
|
207
|
+
if (entry.config.source === "builtin") {
|
|
208
|
+
const scope = entry.config.override?.scope ?? this.builtinOverrideScope;
|
|
209
|
+
if (!scope) { edit.error = "Choose where to store the override first."; return false; }
|
|
210
|
+
try {
|
|
211
|
+
const override = buildBuiltinOverrideConfig(this.resolveBuiltinOverrideBase(entry), edit.draft);
|
|
212
|
+
if (override) {
|
|
213
|
+
saveBuiltinAgentOverride(this.agentData.cwd, entry.config.name, scope, override);
|
|
214
|
+
} else {
|
|
215
|
+
removeBuiltinAgentOverride(this.agentData.cwd, entry.config.name, scope);
|
|
216
|
+
}
|
|
217
|
+
this.refreshAgentData(entry.config.name);
|
|
218
|
+
this.builtinOverrideScope = null;
|
|
219
|
+
this.editState = null;
|
|
220
|
+
const refreshed = this.getAgentEntry(this.currentAgentId);
|
|
221
|
+
if (refreshed) this.enterDetail(refreshed);
|
|
222
|
+
return true;
|
|
223
|
+
} catch (err) {
|
|
224
|
+
edit.error = err instanceof Error ? err.message : "Failed to save builtin override.";
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
130
228
|
if (!edit.draft.name || !edit.draft.description) { edit.error = "Name and description are required."; return false; }
|
|
131
229
|
let filePath = entry.config.filePath;
|
|
132
230
|
if (entry.isNew) {
|
|
@@ -140,6 +238,24 @@ export class AgentManagerComponent implements Component {
|
|
|
140
238
|
catch (err) { edit.error = err instanceof Error ? err.message : "Failed to save agent."; return false; }
|
|
141
239
|
}
|
|
142
240
|
|
|
241
|
+
private removeBuiltinOverride(): boolean {
|
|
242
|
+
const edit = this.editState; if (!edit) return false; const entry = this.getAgentEntry(this.currentAgentId); if (!entry || entry.config.source !== "builtin") return false;
|
|
243
|
+
const scope = entry.config.override?.scope ?? this.builtinOverrideScope;
|
|
244
|
+
if (!scope) { edit.error = "No builtin override to remove."; return false; }
|
|
245
|
+
try {
|
|
246
|
+
removeBuiltinAgentOverride(this.agentData.cwd, entry.config.name, scope);
|
|
247
|
+
this.refreshAgentData(entry.config.name);
|
|
248
|
+
this.builtinOverrideScope = null;
|
|
249
|
+
this.editState = null;
|
|
250
|
+
const refreshed = this.getAgentEntry(this.currentAgentId);
|
|
251
|
+
if (refreshed) this.enterDetail(refreshed);
|
|
252
|
+
return true;
|
|
253
|
+
} catch (err) {
|
|
254
|
+
edit.error = err instanceof Error ? err.message : "Failed to remove builtin override.";
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
143
259
|
private saveChainEdit(): boolean {
|
|
144
260
|
const state = this.chainEditState; const entry = this.getChainEntry(this.currentChainId); if (!state || !entry) return false;
|
|
145
261
|
try { const parsed = parseChain(state.editor.buffer, entry.config.source, entry.config.filePath); fs.writeFileSync(entry.config.filePath, serializeChain(parsed), "utf-8"); entry.config = parsed; state.error = undefined; return true; }
|
|
@@ -159,6 +275,46 @@ export class AgentManagerComponent implements Component {
|
|
|
159
275
|
}
|
|
160
276
|
}
|
|
161
277
|
|
|
278
|
+
private handleOverrideScopeInput(data: string): void {
|
|
279
|
+
const state = this.overrideScopeState;
|
|
280
|
+
const entry = this.getAgentEntry(this.currentAgentId);
|
|
281
|
+
if (!state || !entry) {
|
|
282
|
+
this.screen = "detail";
|
|
283
|
+
this.tui.requestRender();
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c")) {
|
|
288
|
+
this.overrideScopeState = null;
|
|
289
|
+
this.enterDetail(entry);
|
|
290
|
+
this.tui.requestRender();
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (matchesKey(data, "tab") || matchesKey(data, "up") || matchesKey(data, "down")) {
|
|
295
|
+
if (state.allowProject) state.selectedScope = state.selectedScope === "user" ? "project" : "user";
|
|
296
|
+
this.tui.requestRender();
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (data === "u") {
|
|
301
|
+
state.selectedScope = "user";
|
|
302
|
+
this.tui.requestRender();
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (data === "p" && state.allowProject) {
|
|
307
|
+
state.selectedScope = "project";
|
|
308
|
+
this.tui.requestRender();
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (!matchesKey(data, "return")) return;
|
|
313
|
+
this.overrideScopeState = null;
|
|
314
|
+
this.enterBuiltinOverrideEdit(entry, state.selectedScope);
|
|
315
|
+
this.tui.requestRender();
|
|
316
|
+
}
|
|
317
|
+
|
|
162
318
|
private handleNameInput(data: string): void {
|
|
163
319
|
const state = this.nameInputState; if (!state) return; state.error = undefined;
|
|
164
320
|
const canToggleScope = state.allowProject;
|
|
@@ -219,6 +375,27 @@ export class AgentManagerComponent implements Component {
|
|
|
219
375
|
lines.push(renderFooter(" [enter] continue [esc] cancel ", w, this.theme)); return lines;
|
|
220
376
|
}
|
|
221
377
|
|
|
378
|
+
private renderOverrideScope(w: number): string[] {
|
|
379
|
+
const state = this.overrideScopeState;
|
|
380
|
+
const entry = this.getAgentEntry(this.currentAgentId);
|
|
381
|
+
if (!state || !entry) return [];
|
|
382
|
+
const lines: string[] = [];
|
|
383
|
+
lines.push(renderHeader(` Create Override: ${entry.config.name} `, w, this.theme));
|
|
384
|
+
lines.push(row("", w, this.theme));
|
|
385
|
+
lines.push(row(` ${this.theme.fg("dim", "Where should this builtin override live?")}`, w, this.theme));
|
|
386
|
+
lines.push(row("", w, this.theme));
|
|
387
|
+
const userLine = state.selectedScope === "user" ? this.theme.fg("accent", "▸ user") : " user";
|
|
388
|
+
lines.push(row(` ${userLine}${this.theme.fg("dim", ` ${this.agentData.userSettingsPath}`)}`, w, this.theme));
|
|
389
|
+
if (state.allowProject) {
|
|
390
|
+
const projectPath = this.agentData.projectSettingsPath ?? ".dm/settings.json";
|
|
391
|
+
const projectLine = state.selectedScope === "project" ? this.theme.fg("accent", "▸ project") : " project";
|
|
392
|
+
lines.push(row(` ${projectLine}${this.theme.fg("dim", ` ${projectPath}`)}`, w, this.theme));
|
|
393
|
+
}
|
|
394
|
+
while (lines.length < 8) lines.push(row("", w, this.theme));
|
|
395
|
+
lines.push(renderFooter(" [enter] continue [↑↓/tab] choose [esc] cancel ", w, this.theme));
|
|
396
|
+
return lines;
|
|
397
|
+
}
|
|
398
|
+
|
|
222
399
|
private renderTemplateSelect(w: number): string[] {
|
|
223
400
|
const lines: string[] = []; lines.push(renderHeader(" Select Template ", w, this.theme)); lines.push(row("", w, this.theme));
|
|
224
401
|
const innerW = w - 2; const viewport = 12; const start = Math.max(0, Math.min(this.templateCursor - Math.floor(viewport / 2), Math.max(0, TEMPLATE_ITEMS.length - viewport))); const visible = TEMPLATE_ITEMS.slice(start, start + viewport);
|
|
@@ -261,6 +438,7 @@ export class AgentManagerComponent implements Component {
|
|
|
261
438
|
switch (this.screen) {
|
|
262
439
|
case "list": { const action = handleListInput(this.listState, this.listAgents(), data); if (action) this.handleListAction(action); this.tui.requestRender(); return; }
|
|
263
440
|
case "template-select": this.handleTemplateSelectInput(data); return;
|
|
441
|
+
case "override-scope": this.handleOverrideScopeInput(data); return;
|
|
264
442
|
case "detail": {
|
|
265
443
|
const entry = this.getAgentEntry(this.currentAgentId); if (!entry) { this.screen = "list"; this.tui.requestRender(); return; }
|
|
266
444
|
const action = handleDetailInput(this.detailState, data); if (action) this.handleDetailAction(action, entry); this.tui.requestRender(); return;
|
|
@@ -337,6 +515,7 @@ export class AgentManagerComponent implements Component {
|
|
|
337
515
|
if (!this.editState) { this.screen = "list"; this.tui.requestRender(); return; }
|
|
338
516
|
const result = handleEditInput(this.screen as EditScreen, this.editState, data, this.overlayWidth, this.models, this.skills);
|
|
339
517
|
if (result?.action === "discard") { this.handleEditDiscard(); return; }
|
|
518
|
+
if (result?.action === "delete") { this.removeBuiltinOverride(); this.tui.requestRender(); return; }
|
|
340
519
|
if (result?.action === "save") { const ok = this.saveEdit(); if (ok) { const entry = this.getAgentEntry(this.currentAgentId); if (entry) this.enterDetail(entry); } this.tui.requestRender(); return; }
|
|
341
520
|
if (result?.nextScreen) this.screen = result.nextScreen; this.tui.requestRender(); return;
|
|
342
521
|
}
|
|
@@ -344,9 +523,9 @@ export class AgentManagerComponent implements Component {
|
|
|
344
523
|
}
|
|
345
524
|
|
|
346
525
|
private handleEditDiscard(): void {
|
|
347
|
-
const entry = this.getAgentEntry(this.currentAgentId); if (!entry) { this.screen = "list"; this.editState = null; this.tui.requestRender(); return; }
|
|
348
|
-
if (entry.isNew) { this.removeAgentEntry(entry); this.editState = null; this.screen = "list"; this.tui.requestRender(); return; }
|
|
349
|
-
this.editState = null; this.enterDetail(entry); this.tui.requestRender();
|
|
526
|
+
const entry = this.getAgentEntry(this.currentAgentId); if (!entry) { this.screen = "list"; this.editState = null; this.builtinOverrideScope = null; this.tui.requestRender(); return; }
|
|
527
|
+
if (entry.isNew) { this.removeAgentEntry(entry); this.editState = null; this.builtinOverrideScope = null; this.screen = "list"; this.tui.requestRender(); return; }
|
|
528
|
+
this.editState = null; this.builtinOverrideScope = null; this.enterDetail(entry); this.tui.requestRender();
|
|
350
529
|
}
|
|
351
530
|
|
|
352
531
|
private isBuiltin(id: string): boolean { const a = this.getAgentEntry(id); return a?.config.source === "builtin"; }
|
|
@@ -365,7 +544,15 @@ export class AgentManagerComponent implements Component {
|
|
|
365
544
|
|
|
366
545
|
private handleDetailAction(action: DetailAction, entry: AgentEntry): void {
|
|
367
546
|
if (action.type === "back") { this.screen = "list"; return; }
|
|
368
|
-
if (action.type === "edit") {
|
|
547
|
+
if (action.type === "edit") {
|
|
548
|
+
if (entry.config.source === "builtin") {
|
|
549
|
+
if (entry.config.override) this.enterBuiltinOverrideEdit(entry, entry.config.override.scope);
|
|
550
|
+
else this.enterBuiltinOverrideScope(entry);
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
this.enterEdit(entry);
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
369
556
|
if (action.type === "launch") { this.enterTaskInput([entry.id], "detail"); return; }
|
|
370
557
|
}
|
|
371
558
|
|
|
@@ -380,6 +567,7 @@ export class AgentManagerComponent implements Component {
|
|
|
380
567
|
switch (this.screen) {
|
|
381
568
|
case "list": return renderList(this.listState, this.listAgents(), w, this.theme, this.statusMessage);
|
|
382
569
|
case "template-select": return this.renderTemplateSelect(w);
|
|
570
|
+
case "override-scope": return this.renderOverrideScope(w);
|
|
383
571
|
case "detail": { const entry = this.getAgentEntry(this.currentAgentId); if (!entry) return renderList(this.listState, this.listAgents(), w, this.theme, this.statusMessage); return renderDetail(this.detailState, entry.config, this.agentData.cwd, w, this.theme); }
|
|
384
572
|
case "chain-detail": { const entry = this.getChainEntry(this.currentChainId); if (!entry) return renderList(this.listState, this.listAgents(), w, this.theme, this.statusMessage); return renderChainDetail(this.chainDetailState, entry.config, w, this.theme); }
|
|
385
573
|
case "edit": case "edit-field": case "edit-prompt": return this.editState ? renderEdit(this.screen as EditScreen, this.editState, w, this.theme) : [];
|