hydra-os-cli 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.
Files changed (64) hide show
  1. package/README.md +274 -0
  2. package/dist/app.d.ts +12 -0
  3. package/dist/app.js +127 -0
  4. package/dist/cli.d.ts +13 -0
  5. package/dist/cli.js +177 -0
  6. package/dist/clients/api.d.ts +115 -0
  7. package/dist/clients/api.js +123 -0
  8. package/dist/clients/qdrant.d.ts +39 -0
  9. package/dist/clients/qdrant.js +34 -0
  10. package/dist/clients/temporal.d.ts +37 -0
  11. package/dist/clients/temporal.js +32 -0
  12. package/dist/commands/agent.d.ts +4 -0
  13. package/dist/commands/agent.js +103 -0
  14. package/dist/commands/artifact.d.ts +4 -0
  15. package/dist/commands/artifact.js +42 -0
  16. package/dist/commands/config.d.ts +4 -0
  17. package/dist/commands/config.js +80 -0
  18. package/dist/commands/core.d.ts +4 -0
  19. package/dist/commands/core.js +79 -0
  20. package/dist/commands/index.d.ts +6 -0
  21. package/dist/commands/index.js +20 -0
  22. package/dist/commands/memory.d.ts +4 -0
  23. package/dist/commands/memory.js +24 -0
  24. package/dist/commands/registry.d.ts +23 -0
  25. package/dist/commands/registry.js +23 -0
  26. package/dist/commands/session.d.ts +4 -0
  27. package/dist/commands/session.js +15 -0
  28. package/dist/commands/workflow.d.ts +5 -0
  29. package/dist/commands/workflow.js +301 -0
  30. package/dist/config.d.ts +152 -0
  31. package/dist/config.js +91 -0
  32. package/dist/screens/help.d.ts +5 -0
  33. package/dist/screens/help.js +14 -0
  34. package/dist/screens/main.d.ts +5 -0
  35. package/dist/screens/main.js +5 -0
  36. package/dist/screens/workflow-detail.d.ts +9 -0
  37. package/dist/screens/workflow-detail.js +11 -0
  38. package/dist/screens/workflow-list.d.ts +5 -0
  39. package/dist/screens/workflow-list.js +10 -0
  40. package/dist/sse.d.ts +16 -0
  41. package/dist/sse.js +197 -0
  42. package/dist/store.d.ts +100 -0
  43. package/dist/store.js +64 -0
  44. package/dist/widgets/agent-panel.d.ts +15 -0
  45. package/dist/widgets/agent-panel.js +23 -0
  46. package/dist/widgets/approval-modal.d.ts +16 -0
  47. package/dist/widgets/approval-modal.js +24 -0
  48. package/dist/widgets/artifact-tree.d.ts +14 -0
  49. package/dist/widgets/artifact-tree.js +9 -0
  50. package/dist/widgets/chat-panel.d.ts +10 -0
  51. package/dist/widgets/chat-panel.js +29 -0
  52. package/dist/widgets/header.d.ts +11 -0
  53. package/dist/widgets/header.js +14 -0
  54. package/dist/widgets/health-check.d.ts +15 -0
  55. package/dist/widgets/health-check.js +19 -0
  56. package/dist/widgets/input-bar.d.ts +9 -0
  57. package/dist/widgets/input-bar.js +37 -0
  58. package/dist/widgets/memory-panel.d.ts +11 -0
  59. package/dist/widgets/memory-panel.js +9 -0
  60. package/dist/widgets/status-bar.d.ts +13 -0
  61. package/dist/widgets/status-bar.js +24 -0
  62. package/dist/widgets/timeline.d.ts +26 -0
  63. package/dist/widgets/timeline.js +19 -0
  64. package/package.json +64 -0
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Core commands: /help, /clear, /compact, /doctor
3
+ */
4
+ import { registerCommand, getCommandsByCategory } from "./registry.js";
5
+ export function registerCoreCommands() {
6
+ registerCommand({
7
+ name: "help",
8
+ description: "Show all commands",
9
+ usage: "/help",
10
+ category: "core",
11
+ handler: async ({ store }) => {
12
+ const categories = ["core", "workflow", "agent", "artifact", "memory", "config", "session"];
13
+ const lines = ["Available commands:\n"];
14
+ for (const cat of categories) {
15
+ const cmds = getCommandsByCategory(cat);
16
+ if (cmds.length === 0)
17
+ continue;
18
+ lines.push(` ${cat.toUpperCase()}`);
19
+ for (const cmd of cmds) {
20
+ lines.push(` /${cmd.name.padEnd(12)} ${cmd.description}`);
21
+ }
22
+ lines.push("");
23
+ }
24
+ lines.push("Keyboard shortcuts:");
25
+ lines.push(" Ctrl+P Toggle side panels");
26
+ lines.push(" Ctrl+D Exit");
27
+ store.addMessage({ role: "system", content: lines.join("\n") });
28
+ },
29
+ });
30
+ registerCommand({
31
+ name: "clear",
32
+ description: "Clear chat output",
33
+ usage: "/clear",
34
+ category: "core",
35
+ handler: async ({ store }) => {
36
+ store.clearMessages();
37
+ },
38
+ });
39
+ registerCommand({
40
+ name: "compact",
41
+ description: "Compress conversation context",
42
+ usage: "/compact [focus]",
43
+ category: "core",
44
+ handler: async ({ store }) => {
45
+ store.addMessage({ role: "system", content: "Compact is not yet available (Phase 2)." });
46
+ },
47
+ });
48
+ registerCommand({
49
+ name: "doctor",
50
+ description: "Health check (Temporal, Qdrant, API, workers)",
51
+ usage: "/doctor",
52
+ category: "core",
53
+ handler: async ({ store, api }) => {
54
+ store.addMessage({ role: "system", content: "Running health checks..." });
55
+ try {
56
+ const health = await api.healthCheck();
57
+ const lines = ["Service health:"];
58
+ lines.push(` API: ${health.status ?? "ok"}`);
59
+ if (health.version)
60
+ lines.push(` Version: ${health.version}`);
61
+ // Try to get agents to verify Temporal connectivity
62
+ try {
63
+ const agentsResp = await api.getAgents();
64
+ lines.push(` Temporal: connected (${agentsResp.agents.length} roles)`);
65
+ }
66
+ catch {
67
+ lines.push(" Temporal: unreachable");
68
+ }
69
+ store.addMessage({ role: "system", content: lines.join("\n") });
70
+ store.setApiStatus("connected");
71
+ }
72
+ catch (err) {
73
+ const msg = err instanceof Error ? err.message : String(err);
74
+ store.addMessage({ role: "error", content: `Health check failed: ${msg}` });
75
+ store.setApiStatus("error");
76
+ }
77
+ },
78
+ });
79
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Register all slash commands.
3
+ */
4
+ export declare function registerAllCommands(): void;
5
+ export { getCommand, getAllCommands, getCompletions } from "./registry.js";
6
+ export type { CommandContext, CommandDef } from "./registry.js";
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Register all slash commands.
3
+ */
4
+ import { registerCoreCommands } from "./core.js";
5
+ import { registerWorkflowCommands } from "./workflow.js";
6
+ import { registerAgentCommands } from "./agent.js";
7
+ import { registerArtifactCommands } from "./artifact.js";
8
+ import { registerMemoryCommands } from "./memory.js";
9
+ import { registerConfigCommands } from "./config.js";
10
+ import { registerSessionCommands } from "./session.js";
11
+ export function registerAllCommands() {
12
+ registerCoreCommands();
13
+ registerWorkflowCommands();
14
+ registerAgentCommands();
15
+ registerArtifactCommands();
16
+ registerMemoryCommands();
17
+ registerConfigCommands();
18
+ registerSessionCommands();
19
+ }
20
+ export { getCommand, getAllCommands, getCompletions } from "./registry.js";
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Memory commands: /memory search|add|pin|forget, /decisions
3
+ */
4
+ export declare function registerMemoryCommands(): void;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Memory commands: /memory search|add|pin|forget, /decisions
3
+ */
4
+ import { registerCommand } from "./registry.js";
5
+ export function registerMemoryCommands() {
6
+ registerCommand({
7
+ name: "memory",
8
+ description: "Search, add, pin, or forget memories",
9
+ usage: "/memory <search|add|pin|forget> <args>",
10
+ category: "memory",
11
+ handler: async ({ store }) => {
12
+ store.addMessage({ role: "system", content: "Memory commands are not yet available (Phase 3)." });
13
+ },
14
+ });
15
+ registerCommand({
16
+ name: "decisions",
17
+ description: "Show decisions made in a workflow",
18
+ usage: "/decisions [workflow-id]",
19
+ category: "memory",
20
+ handler: async ({ store }) => {
21
+ store.addMessage({ role: "system", content: "Decisions display is not yet available (Phase 3)." });
22
+ },
23
+ });
24
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Slash command registry.
3
+ * Central registry for all TUI commands with autocomplete support.
4
+ */
5
+ import type { HydraStore } from "../store.js";
6
+ import type { HydraApiClient } from "../clients/api.js";
7
+ export interface CommandContext {
8
+ store: HydraStore;
9
+ api: HydraApiClient;
10
+ args: string[];
11
+ }
12
+ export interface CommandDef {
13
+ name: string;
14
+ description: string;
15
+ usage: string;
16
+ handler: (ctx: CommandContext) => Promise<void>;
17
+ category: "core" | "workflow" | "agent" | "artifact" | "memory" | "config" | "session";
18
+ }
19
+ export declare function registerCommand(def: CommandDef): void;
20
+ export declare function getCommand(name: string): CommandDef | undefined;
21
+ export declare function getAllCommands(): CommandDef[];
22
+ export declare function getCommandsByCategory(category: CommandDef["category"]): CommandDef[];
23
+ export declare function getCompletions(prefix: string): string[];
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Slash command registry.
3
+ * Central registry for all TUI commands with autocomplete support.
4
+ */
5
+ const commands = new Map();
6
+ export function registerCommand(def) {
7
+ commands.set(def.name, def);
8
+ }
9
+ export function getCommand(name) {
10
+ return commands.get(name);
11
+ }
12
+ export function getAllCommands() {
13
+ return Array.from(commands.values());
14
+ }
15
+ export function getCommandsByCategory(category) {
16
+ return getAllCommands().filter((cmd) => cmd.category === category);
17
+ }
18
+ export function getCompletions(prefix) {
19
+ return getAllCommands()
20
+ .map((cmd) => `/${cmd.name}`)
21
+ .filter((name) => name.startsWith(prefix))
22
+ .sort();
23
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Session commands: /session save|load|list|export
3
+ */
4
+ export declare function registerSessionCommands(): void;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Session commands: /session save|load|list|export
3
+ */
4
+ import { registerCommand } from "./registry.js";
5
+ export function registerSessionCommands() {
6
+ registerCommand({
7
+ name: "session",
8
+ description: "Save, load, list, or export sessions",
9
+ usage: "/session <save|load|list|export> [name]",
10
+ category: "session",
11
+ handler: async ({ store }) => {
12
+ store.addMessage({ role: "system", content: "Session management is not yet available (Phase 4)." });
13
+ },
14
+ });
15
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Workflow commands: /start, /status, /list, /approve, /deny, /correct,
3
+ * /pause, /resume, /cancel, /attach, /detach, /history
4
+ */
5
+ export declare function registerWorkflowCommands(): void;
@@ -0,0 +1,301 @@
1
+ /**
2
+ * Workflow commands: /start, /status, /list, /approve, /deny, /correct,
3
+ * /pause, /resume, /cancel, /attach, /detach, /history
4
+ */
5
+ import { randomUUID } from "node:crypto";
6
+ import { registerCommand } from "./registry.js";
7
+ import { subscribeToWorkflow } from "../sse.js";
8
+ function resolveWorkflowId(ctx) {
9
+ const fromArgs = ctx.args[0];
10
+ if (fromArgs)
11
+ return fromArgs;
12
+ const active = ctx.store.activeWorkflowId;
13
+ if (active)
14
+ return active;
15
+ ctx.store.addMessage({ role: "error", content: "No workflow ID specified and no active workflow. Usage: /<command> <workflow-id>" });
16
+ return null;
17
+ }
18
+ export function registerWorkflowCommands() {
19
+ registerCommand({
20
+ name: "start",
21
+ description: "Start a new workflow from natural language",
22
+ usage: "/start <description>",
23
+ category: "workflow",
24
+ handler: async ({ store, api, args }) => {
25
+ const description = args.join(" ").trim();
26
+ if (!description) {
27
+ store.addMessage({ role: "error", content: "Usage: /start <description>" });
28
+ return;
29
+ }
30
+ store.addMessage({ role: "system", content: `Starting workflow: ${description}` });
31
+ try {
32
+ const wfId = `wf-${randomUUID()}`;
33
+ const result = await api.startWorkflow("DynamicWorkflow", wfId, {
34
+ idea: description,
35
+ });
36
+ store.setActiveWorkflowId(result.workflow_id);
37
+ store.addMessage({
38
+ role: "agent",
39
+ content: `Workflow started: ${result.workflow_id}\nRun ID: ${result.run_id}\nUse /status to check progress or /attach ${result.workflow_id} to stream live updates.`,
40
+ agent: "orchestrator",
41
+ });
42
+ }
43
+ catch (err) {
44
+ const msg = err instanceof Error ? err.message : String(err);
45
+ store.addMessage({ role: "error", content: `Failed to start workflow: ${msg}` });
46
+ }
47
+ },
48
+ });
49
+ registerCommand({
50
+ name: "status",
51
+ description: "Show workflow status (defaults to active)",
52
+ usage: "/status [workflow-id]",
53
+ category: "workflow",
54
+ handler: async (ctx) => {
55
+ const wfId = resolveWorkflowId(ctx);
56
+ if (!wfId)
57
+ return;
58
+ try {
59
+ const resp = await ctx.api.getWorkflowStatus(wfId);
60
+ const status = resp.status;
61
+ const lines = [`Workflow: ${wfId}`];
62
+ if (typeof status === "object" && status !== null) {
63
+ const s = status;
64
+ if (s.phase)
65
+ lines.push(`Phase: ${s.phase}`);
66
+ if (s.current_phase)
67
+ lines.push(`Current phase: ${s.current_phase}`);
68
+ if (s.waiting_for_approval)
69
+ lines.push("** Waiting for approval **");
70
+ if (s.total_cost != null)
71
+ lines.push(`Cost: $${Number(s.total_cost).toFixed(4)}`);
72
+ if (s.total_tokens != null)
73
+ lines.push(`Tokens: ${s.total_tokens}`);
74
+ const steps = s.steps;
75
+ if (Array.isArray(steps) && steps.length > 0) {
76
+ lines.push("\nSteps:");
77
+ for (const step of steps) {
78
+ const st = step;
79
+ const icon = st.status === "completed" ? " ✓" : st.status === "running" ? " ⏳" : " ○";
80
+ lines.push(`${icon} ${st.role ?? st.name ?? "step"} [${st.status}]`);
81
+ }
82
+ }
83
+ // Update agent panel
84
+ if (Array.isArray(steps)) {
85
+ ctx.store.setAgents(steps.map((st) => ({
86
+ id: String(st.role ?? ""),
87
+ role_id: String(st.role ?? ""),
88
+ queue: String(st.role ?? ""),
89
+ status: String(st.status === "completed" ? "idle" : st.status === "running" ? "active" : "idle"),
90
+ model: "",
91
+ active_sessions: st.status === "running" ? 1 : 0,
92
+ total_tokens_used: Number(st.tokens ?? 0),
93
+ current_workflow: st.status === "running" ? wfId : null,
94
+ skill_packs: [],
95
+ })));
96
+ }
97
+ }
98
+ else {
99
+ lines.push(`Status: ${JSON.stringify(status)}`);
100
+ }
101
+ ctx.store.addMessage({ role: "system", content: lines.join("\n") });
102
+ }
103
+ catch (err) {
104
+ const msg = err instanceof Error ? err.message : String(err);
105
+ ctx.store.addMessage({ role: "error", content: `Failed to get status: ${msg}` });
106
+ }
107
+ },
108
+ });
109
+ registerCommand({
110
+ name: "list",
111
+ description: "List all workflows",
112
+ usage: "/list",
113
+ category: "workflow",
114
+ handler: async ({ store, api }) => {
115
+ try {
116
+ const tasks = await api.listTasks({ limit: 20 });
117
+ if (tasks.length === 0) {
118
+ store.addMessage({ role: "system", content: "No workflows found." });
119
+ return;
120
+ }
121
+ store.setWorkflows(tasks);
122
+ const lines = ["Workflows:\n"];
123
+ lines.push(" ID | Status | Type | Step");
124
+ lines.push(" " + "-".repeat(80));
125
+ for (const t of tasks) {
126
+ const id = t.workflow_id.slice(0, 28).padEnd(28);
127
+ const status = (t.status ?? "unknown").padEnd(11);
128
+ const type = (t.workflow_type ?? "").slice(0, 16).padEnd(16);
129
+ const step = t.current_step ?? "";
130
+ lines.push(` ${id} | ${status} | ${type} | ${step}`);
131
+ }
132
+ store.addMessage({ role: "system", content: lines.join("\n") });
133
+ }
134
+ catch (err) {
135
+ const msg = err instanceof Error ? err.message : String(err);
136
+ store.addMessage({ role: "error", content: `Failed to list workflows: ${msg}` });
137
+ }
138
+ },
139
+ });
140
+ registerCommand({
141
+ name: "approve",
142
+ description: "Approve pending approval",
143
+ usage: "/approve [workflow-id]",
144
+ category: "workflow",
145
+ handler: async (ctx) => {
146
+ const wfId = resolveWorkflowId(ctx);
147
+ if (!wfId)
148
+ return;
149
+ try {
150
+ await ctx.api.approveWorkflow(wfId, "approved");
151
+ ctx.store.addMessage({ role: "system", content: `Approved workflow: ${wfId}` });
152
+ }
153
+ catch (err) {
154
+ const msg = err instanceof Error ? err.message : String(err);
155
+ ctx.store.addMessage({ role: "error", content: `Failed to approve: ${msg}` });
156
+ }
157
+ },
158
+ });
159
+ registerCommand({
160
+ name: "deny",
161
+ description: "Deny pending approval",
162
+ usage: "/deny [workflow-id]",
163
+ category: "workflow",
164
+ handler: async (ctx) => {
165
+ const wfId = resolveWorkflowId(ctx);
166
+ if (!wfId)
167
+ return;
168
+ const feedback = ctx.args.slice(1).join(" ") || undefined;
169
+ try {
170
+ await ctx.api.approveWorkflow(wfId, "denied", feedback);
171
+ ctx.store.addMessage({ role: "system", content: `Denied workflow: ${wfId}${feedback ? ` (feedback: ${feedback})` : ""}` });
172
+ }
173
+ catch (err) {
174
+ const msg = err instanceof Error ? err.message : String(err);
175
+ ctx.store.addMessage({ role: "error", content: `Failed to deny: ${msg}` });
176
+ }
177
+ },
178
+ });
179
+ registerCommand({
180
+ name: "correct",
181
+ description: "Send correction to current agent",
182
+ usage: "/correct <message>",
183
+ category: "workflow",
184
+ handler: async ({ store }) => {
185
+ store.addMessage({ role: "system", content: "Correct is not yet available (Phase 2)." });
186
+ },
187
+ });
188
+ registerCommand({
189
+ name: "pause",
190
+ description: "Pause a running workflow",
191
+ usage: "/pause [workflow-id]",
192
+ category: "workflow",
193
+ handler: async (ctx) => {
194
+ const wfId = resolveWorkflowId(ctx);
195
+ if (!wfId)
196
+ return;
197
+ try {
198
+ const result = await ctx.api.pauseWorkflow(wfId);
199
+ ctx.store.addMessage({ role: "system", content: `Paused workflow: ${wfId} (${result.status})` });
200
+ }
201
+ catch (err) {
202
+ const msg = err instanceof Error ? err.message : String(err);
203
+ ctx.store.addMessage({ role: "error", content: `Failed to pause: ${msg}` });
204
+ }
205
+ },
206
+ });
207
+ registerCommand({
208
+ name: "resume",
209
+ description: "Resume a paused workflow",
210
+ usage: "/resume [workflow-id]",
211
+ category: "workflow",
212
+ handler: async (ctx) => {
213
+ const wfId = resolveWorkflowId(ctx);
214
+ if (!wfId)
215
+ return;
216
+ try {
217
+ const result = await ctx.api.resumeWorkflow(wfId);
218
+ ctx.store.addMessage({ role: "system", content: `Resumed workflow: ${wfId} (${result.status})` });
219
+ }
220
+ catch (err) {
221
+ const msg = err instanceof Error ? err.message : String(err);
222
+ ctx.store.addMessage({ role: "error", content: `Failed to resume: ${msg}` });
223
+ }
224
+ },
225
+ });
226
+ registerCommand({
227
+ name: "cancel",
228
+ description: "Cancel a workflow (requires confirm)",
229
+ usage: "/cancel confirm [workflow-id]",
230
+ category: "workflow",
231
+ handler: async (ctx) => {
232
+ // Require explicit "confirm" as first arg to prevent accidental cancellation
233
+ if (ctx.args[0] !== "confirm") {
234
+ const wfId = ctx.args[0] ?? ctx.store.activeWorkflowId ?? "<workflow-id>";
235
+ ctx.store.addMessage({
236
+ role: "system",
237
+ content: `This will permanently cancel workflow ${wfId}.\nTo confirm, run: /cancel confirm ${wfId}`,
238
+ });
239
+ return;
240
+ }
241
+ // "confirm" consumed — remaining args are the workflow ID
242
+ const shiftedCtx = { ...ctx, args: ctx.args.slice(1) };
243
+ const wfId = resolveWorkflowId(shiftedCtx);
244
+ if (!wfId)
245
+ return;
246
+ try {
247
+ const result = await ctx.api.cancelWorkflow(wfId);
248
+ ctx.store.addMessage({ role: "system", content: `Cancelled workflow: ${wfId} (${result.status})` });
249
+ if (ctx.store.activeWorkflowId === wfId) {
250
+ ctx.store.setActiveWorkflowId(null);
251
+ ctx.store.setActiveWorkflow(null);
252
+ }
253
+ }
254
+ catch (err) {
255
+ const msg = err instanceof Error ? err.message : String(err);
256
+ ctx.store.addMessage({ role: "error", content: `Failed to cancel: ${msg}` });
257
+ }
258
+ },
259
+ });
260
+ registerCommand({
261
+ name: "attach",
262
+ description: "Attach to a workflow's live stream",
263
+ usage: "/attach <workflow-id>",
264
+ category: "workflow",
265
+ handler: async (ctx) => {
266
+ const wfId = resolveWorkflowId(ctx);
267
+ if (!wfId)
268
+ return;
269
+ ctx.store.setActiveWorkflowId(wfId);
270
+ ctx.store.addMessage({ role: "system", content: `Attaching to workflow: ${wfId}...` });
271
+ const controller = subscribeToWorkflow(ctx.store.apiUrl, wfId, ctx.store);
272
+ ctx.store.addSseController(wfId, controller);
273
+ },
274
+ });
275
+ registerCommand({
276
+ name: "detach",
277
+ description: "Detach from live stream",
278
+ usage: "/detach",
279
+ category: "workflow",
280
+ handler: async ({ store }) => {
281
+ const wfId = store.activeWorkflowId;
282
+ if (wfId) {
283
+ store.removeSseController(wfId);
284
+ store.addMessage({ role: "system", content: `Detached from workflow: ${wfId}` });
285
+ }
286
+ else {
287
+ store.abortAllSse();
288
+ store.addMessage({ role: "system", content: "Detached from all streams." });
289
+ }
290
+ },
291
+ });
292
+ registerCommand({
293
+ name: "history",
294
+ description: "Show full workflow event history",
295
+ usage: "/history [workflow-id]",
296
+ category: "workflow",
297
+ handler: async ({ store }) => {
298
+ store.addMessage({ role: "system", content: "History is not yet available (Phase 2)." });
299
+ },
300
+ });
301
+ }
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Configuration loading and validation for the Hydra TUI.
3
+ *
4
+ * Config file: ~/.hydra/config.yaml
5
+ * Overridable via environment variables.
6
+ */
7
+ import { z } from "zod";
8
+ export declare const TuiConfigSchema: z.ZodObject<{
9
+ temporal: z.ZodDefault<z.ZodObject<{
10
+ address: z.ZodDefault<z.ZodString>;
11
+ namespace: z.ZodDefault<z.ZodString>;
12
+ }, "strip", z.ZodTypeAny, {
13
+ address: string;
14
+ namespace: string;
15
+ }, {
16
+ address?: string | undefined;
17
+ namespace?: string | undefined;
18
+ }>>;
19
+ api: z.ZodDefault<z.ZodObject<{
20
+ url: z.ZodDefault<z.ZodString>;
21
+ }, "strip", z.ZodTypeAny, {
22
+ url: string;
23
+ }, {
24
+ url?: string | undefined;
25
+ }>>;
26
+ qdrant: z.ZodDefault<z.ZodObject<{
27
+ url: z.ZodDefault<z.ZodString>;
28
+ }, "strip", z.ZodTypeAny, {
29
+ url: string;
30
+ }, {
31
+ url?: string | undefined;
32
+ }>>;
33
+ tui: z.ZodDefault<z.ZodObject<{
34
+ theme: z.ZodDefault<z.ZodEnum<["dark", "light", "solarized", "monokai", "hydra"]>>;
35
+ layout: z.ZodDefault<z.ZodEnum<["split", "full"]>>;
36
+ rightPanel: z.ZodDefault<z.ZodBoolean>;
37
+ vimMode: z.ZodDefault<z.ZodBoolean>;
38
+ syntaxHighlighting: z.ZodDefault<z.ZodBoolean>;
39
+ maxHistory: z.ZodDefault<z.ZodNumber>;
40
+ spinnerStyle: z.ZodDefault<z.ZodEnum<["dots", "line", "arc", "bounce"]>>;
41
+ }, "strip", z.ZodTypeAny, {
42
+ maxHistory: number;
43
+ theme: "dark" | "light" | "solarized" | "monokai" | "hydra";
44
+ layout: "split" | "full";
45
+ rightPanel: boolean;
46
+ vimMode: boolean;
47
+ syntaxHighlighting: boolean;
48
+ spinnerStyle: "dots" | "line" | "arc" | "bounce";
49
+ }, {
50
+ maxHistory?: number | undefined;
51
+ theme?: "dark" | "light" | "solarized" | "monokai" | "hydra" | undefined;
52
+ layout?: "split" | "full" | undefined;
53
+ rightPanel?: boolean | undefined;
54
+ vimMode?: boolean | undefined;
55
+ syntaxHighlighting?: boolean | undefined;
56
+ spinnerStyle?: "dots" | "line" | "arc" | "bounce" | undefined;
57
+ }>>;
58
+ workflow: z.ZodDefault<z.ZodObject<{
59
+ defaultModel: z.ZodDefault<z.ZodString>;
60
+ autoApproveReads: z.ZodDefault<z.ZodBoolean>;
61
+ qualityThreshold: z.ZodDefault<z.ZodNumber>;
62
+ costWarning: z.ZodDefault<z.ZodNumber>;
63
+ }, "strip", z.ZodTypeAny, {
64
+ defaultModel: string;
65
+ autoApproveReads: boolean;
66
+ qualityThreshold: number;
67
+ costWarning: number;
68
+ }, {
69
+ defaultModel?: string | undefined;
70
+ autoApproveReads?: boolean | undefined;
71
+ qualityThreshold?: number | undefined;
72
+ costWarning?: number | undefined;
73
+ }>>;
74
+ notifications: z.ZodDefault<z.ZodObject<{
75
+ sound: z.ZodDefault<z.ZodBoolean>;
76
+ desktop: z.ZodDefault<z.ZodBoolean>;
77
+ idleAlert: z.ZodDefault<z.ZodNumber>;
78
+ }, "strip", z.ZodTypeAny, {
79
+ sound: boolean;
80
+ desktop: boolean;
81
+ idleAlert: number;
82
+ }, {
83
+ sound?: boolean | undefined;
84
+ desktop?: boolean | undefined;
85
+ idleAlert?: number | undefined;
86
+ }>>;
87
+ }, "strip", z.ZodTypeAny, {
88
+ workflow: {
89
+ defaultModel: string;
90
+ autoApproveReads: boolean;
91
+ qualityThreshold: number;
92
+ costWarning: number;
93
+ };
94
+ api: {
95
+ url: string;
96
+ };
97
+ temporal: {
98
+ address: string;
99
+ namespace: string;
100
+ };
101
+ qdrant: {
102
+ url: string;
103
+ };
104
+ tui: {
105
+ maxHistory: number;
106
+ theme: "dark" | "light" | "solarized" | "monokai" | "hydra";
107
+ layout: "split" | "full";
108
+ rightPanel: boolean;
109
+ vimMode: boolean;
110
+ syntaxHighlighting: boolean;
111
+ spinnerStyle: "dots" | "line" | "arc" | "bounce";
112
+ };
113
+ notifications: {
114
+ sound: boolean;
115
+ desktop: boolean;
116
+ idleAlert: number;
117
+ };
118
+ }, {
119
+ workflow?: {
120
+ defaultModel?: string | undefined;
121
+ autoApproveReads?: boolean | undefined;
122
+ qualityThreshold?: number | undefined;
123
+ costWarning?: number | undefined;
124
+ } | undefined;
125
+ api?: {
126
+ url?: string | undefined;
127
+ } | undefined;
128
+ temporal?: {
129
+ address?: string | undefined;
130
+ namespace?: string | undefined;
131
+ } | undefined;
132
+ qdrant?: {
133
+ url?: string | undefined;
134
+ } | undefined;
135
+ tui?: {
136
+ maxHistory?: number | undefined;
137
+ theme?: "dark" | "light" | "solarized" | "monokai" | "hydra" | undefined;
138
+ layout?: "split" | "full" | undefined;
139
+ rightPanel?: boolean | undefined;
140
+ vimMode?: boolean | undefined;
141
+ syntaxHighlighting?: boolean | undefined;
142
+ spinnerStyle?: "dots" | "line" | "arc" | "bounce" | undefined;
143
+ } | undefined;
144
+ notifications?: {
145
+ sound?: boolean | undefined;
146
+ desktop?: boolean | undefined;
147
+ idleAlert?: number | undefined;
148
+ } | undefined;
149
+ }>;
150
+ export type TuiConfig = z.infer<typeof TuiConfigSchema>;
151
+ export declare function getEnvOverrides(): Record<string, unknown>;
152
+ export declare function loadConfig(): TuiConfig;