zoe-agent 0.3.1

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 (267) hide show
  1. package/CHANGELOG.md +154 -0
  2. package/LICENSE +96 -0
  3. package/README.md +568 -0
  4. package/dist/adapters/cli/agent.d.ts +59 -0
  5. package/dist/adapters/cli/agent.js +232 -0
  6. package/dist/adapters/cli/bootstrap.d.ts +25 -0
  7. package/dist/adapters/cli/bootstrap.js +204 -0
  8. package/dist/adapters/cli/commands/build-registry.d.ts +14 -0
  9. package/dist/adapters/cli/commands/build-registry.js +88 -0
  10. package/dist/adapters/cli/commands/clear.d.ts +7 -0
  11. package/dist/adapters/cli/commands/clear.js +10 -0
  12. package/dist/adapters/cli/commands/compact.d.ts +13 -0
  13. package/dist/adapters/cli/commands/compact.js +96 -0
  14. package/dist/adapters/cli/commands/exit.d.ts +7 -0
  15. package/dist/adapters/cli/commands/exit.js +9 -0
  16. package/dist/adapters/cli/commands/gateway.d.ts +7 -0
  17. package/dist/adapters/cli/commands/gateway.js +152 -0
  18. package/dist/adapters/cli/commands/help.d.ts +9 -0
  19. package/dist/adapters/cli/commands/help.js +12 -0
  20. package/dist/adapters/cli/commands/models.d.ts +10 -0
  21. package/dist/adapters/cli/commands/models.js +32 -0
  22. package/dist/adapters/cli/commands/registry.d.ts +70 -0
  23. package/dist/adapters/cli/commands/registry.js +111 -0
  24. package/dist/adapters/cli/commands/settings-utils.d.ts +38 -0
  25. package/dist/adapters/cli/commands/settings-utils.js +182 -0
  26. package/dist/adapters/cli/commands/settings.d.ts +9 -0
  27. package/dist/adapters/cli/commands/settings.js +395 -0
  28. package/dist/adapters/cli/commands/skills.d.ts +7 -0
  29. package/dist/adapters/cli/commands/skills.js +21 -0
  30. package/dist/adapters/cli/config-loader.d.ts +27 -0
  31. package/dist/adapters/cli/config-loader.js +48 -0
  32. package/dist/adapters/cli/docker-utils.d.ts +37 -0
  33. package/dist/adapters/cli/docker-utils.js +90 -0
  34. package/dist/adapters/cli/index.d.ts +2 -0
  35. package/dist/adapters/cli/index.js +88 -0
  36. package/dist/adapters/cli/repl.d.ts +22 -0
  37. package/dist/adapters/cli/repl.js +256 -0
  38. package/dist/adapters/cli/setup.d.ts +19 -0
  39. package/dist/adapters/cli/setup.js +613 -0
  40. package/dist/adapters/cli/system-prompts.d.ts +56 -0
  41. package/dist/adapters/cli/system-prompts.js +131 -0
  42. package/dist/adapters/cli/tui/app.d.ts +58 -0
  43. package/dist/adapters/cli/tui/app.js +314 -0
  44. package/dist/adapters/cli/tui/components/assistant-message.d.ts +5 -0
  45. package/dist/adapters/cli/tui/components/assistant-message.js +9 -0
  46. package/dist/adapters/cli/tui/components/autocomplete.d.ts +19 -0
  47. package/dist/adapters/cli/tui/components/autocomplete.js +75 -0
  48. package/dist/adapters/cli/tui/components/command-palette.d.ts +15 -0
  49. package/dist/adapters/cli/tui/components/command-palette.js +50 -0
  50. package/dist/adapters/cli/tui/components/diff-viewer.d.ts +5 -0
  51. package/dist/adapters/cli/tui/components/diff-viewer.js +109 -0
  52. package/dist/adapters/cli/tui/components/error-message.d.ts +5 -0
  53. package/dist/adapters/cli/tui/components/error-message.js +8 -0
  54. package/dist/adapters/cli/tui/components/footer.d.ts +20 -0
  55. package/dist/adapters/cli/tui/components/footer.js +19 -0
  56. package/dist/adapters/cli/tui/components/goal-status.d.ts +12 -0
  57. package/dist/adapters/cli/tui/components/goal-status.js +22 -0
  58. package/dist/adapters/cli/tui/components/info-message.d.ts +5 -0
  59. package/dist/adapters/cli/tui/components/info-message.js +8 -0
  60. package/dist/adapters/cli/tui/components/logo-banner.d.ts +7 -0
  61. package/dist/adapters/cli/tui/components/logo-banner.js +33 -0
  62. package/dist/adapters/cli/tui/components/markdown.d.ts +9 -0
  63. package/dist/adapters/cli/tui/components/markdown.js +92 -0
  64. package/dist/adapters/cli/tui/components/message-area.d.ts +19 -0
  65. package/dist/adapters/cli/tui/components/message-area.js +55 -0
  66. package/dist/adapters/cli/tui/components/permission-prompt.d.ts +13 -0
  67. package/dist/adapters/cli/tui/components/permission-prompt.js +32 -0
  68. package/dist/adapters/cli/tui/components/prompt-area.d.ts +22 -0
  69. package/dist/adapters/cli/tui/components/prompt-area.js +68 -0
  70. package/dist/adapters/cli/tui/components/text-input.d.ts +27 -0
  71. package/dist/adapters/cli/tui/components/text-input.js +142 -0
  72. package/dist/adapters/cli/tui/components/tool-call-block.d.ts +11 -0
  73. package/dist/adapters/cli/tui/components/tool-call-block.js +68 -0
  74. package/dist/adapters/cli/tui/components/user-message.d.ts +5 -0
  75. package/dist/adapters/cli/tui/components/user-message.js +8 -0
  76. package/dist/adapters/cli/tui/diff/file-write-meta.d.ts +11 -0
  77. package/dist/adapters/cli/tui/diff/file-write-meta.js +11 -0
  78. package/dist/adapters/cli/tui/diff/line-diff.d.ts +17 -0
  79. package/dist/adapters/cli/tui/diff/line-diff.js +44 -0
  80. package/dist/adapters/cli/tui/feed-serializer.d.ts +29 -0
  81. package/dist/adapters/cli/tui/feed-serializer.js +70 -0
  82. package/dist/adapters/cli/tui/file-index.d.ts +8 -0
  83. package/dist/adapters/cli/tui/file-index.js +41 -0
  84. package/dist/adapters/cli/tui/hooks/use-agent.d.ts +54 -0
  85. package/dist/adapters/cli/tui/hooks/use-agent.js +177 -0
  86. package/dist/adapters/cli/tui/hooks/use-feed.d.ts +16 -0
  87. package/dist/adapters/cli/tui/hooks/use-feed.js +25 -0
  88. package/dist/adapters/cli/tui/hooks/use-file-watcher.d.ts +10 -0
  89. package/dist/adapters/cli/tui/hooks/use-file-watcher.js +43 -0
  90. package/dist/adapters/cli/tui/hooks/use-keybindings.d.ts +16 -0
  91. package/dist/adapters/cli/tui/hooks/use-keybindings.js +25 -0
  92. package/dist/adapters/cli/tui/hooks/use-theme.d.ts +8 -0
  93. package/dist/adapters/cli/tui/hooks/use-theme.js +12 -0
  94. package/dist/adapters/cli/tui/index.d.ts +19 -0
  95. package/dist/adapters/cli/tui/index.js +206 -0
  96. package/dist/adapters/cli/tui/ink-reset.d.ts +29 -0
  97. package/dist/adapters/cli/tui/ink-reset.js +57 -0
  98. package/dist/adapters/cli/tui/layout.d.ts +15 -0
  99. package/dist/adapters/cli/tui/layout.js +15 -0
  100. package/dist/adapters/cli/tui/logo/gradient.d.ts +11 -0
  101. package/dist/adapters/cli/tui/logo/gradient.js +31 -0
  102. package/dist/adapters/cli/tui/overlays/help-dialog.d.ts +4 -0
  103. package/dist/adapters/cli/tui/overlays/help-dialog.js +26 -0
  104. package/dist/adapters/cli/tui/overlays/model-selector.d.ts +14 -0
  105. package/dist/adapters/cli/tui/overlays/model-selector.js +43 -0
  106. package/dist/adapters/cli/tui/overlays/session-selector.d.ts +35 -0
  107. package/dist/adapters/cli/tui/overlays/session-selector.js +162 -0
  108. package/dist/adapters/cli/tui/overlays/settings-overlay.d.ts +24 -0
  109. package/dist/adapters/cli/tui/overlays/settings-overlay.js +126 -0
  110. package/dist/adapters/cli/tui/session-export.d.ts +21 -0
  111. package/dist/adapters/cli/tui/session-export.js +63 -0
  112. package/dist/adapters/cli/tui/theme.d.ts +23 -0
  113. package/dist/adapters/cli/tui/theme.js +22 -0
  114. package/dist/adapters/cli/tui/types.d.ts +52 -0
  115. package/dist/adapters/cli/tui/types.js +12 -0
  116. package/dist/adapters/sdk/agent.d.ts +20 -0
  117. package/dist/adapters/sdk/agent.js +356 -0
  118. package/dist/adapters/sdk/http.d.ts +43 -0
  119. package/dist/adapters/sdk/http.js +61 -0
  120. package/dist/adapters/sdk/index.d.ts +58 -0
  121. package/dist/adapters/sdk/index.js +209 -0
  122. package/dist/adapters/sdk/settings.d.ts +18 -0
  123. package/dist/adapters/sdk/settings.js +57 -0
  124. package/dist/adapters/sdk/tools.d.ts +7 -0
  125. package/dist/adapters/sdk/tools.js +13 -0
  126. package/dist/adapters/server/auth.d.ts +53 -0
  127. package/dist/adapters/server/auth.js +168 -0
  128. package/dist/adapters/server/index.d.ts +40 -0
  129. package/dist/adapters/server/index.js +255 -0
  130. package/dist/adapters/server/rest-gateway.d.ts +13 -0
  131. package/dist/adapters/server/rest-gateway.js +218 -0
  132. package/dist/adapters/server/rest.d.ts +37 -0
  133. package/dist/adapters/server/rest.js +341 -0
  134. package/dist/adapters/server/server-core.d.ts +55 -0
  135. package/dist/adapters/server/server-core.js +121 -0
  136. package/dist/adapters/server/session-store.d.ts +81 -0
  137. package/dist/adapters/server/session-store.js +272 -0
  138. package/dist/adapters/server/settings-handlers.d.ts +24 -0
  139. package/dist/adapters/server/settings-handlers.js +360 -0
  140. package/dist/adapters/server/standalone.d.ts +19 -0
  141. package/dist/adapters/server/standalone.js +113 -0
  142. package/dist/adapters/server/websocket.d.ts +26 -0
  143. package/dist/adapters/server/websocket.js +68 -0
  144. package/dist/adapters/server/ws-handlers.d.ts +32 -0
  145. package/dist/adapters/server/ws-handlers.js +523 -0
  146. package/dist/adapters/server/ws-types.d.ts +304 -0
  147. package/dist/adapters/server/ws-types.js +7 -0
  148. package/dist/core/agent-loop.d.ts +68 -0
  149. package/dist/core/agent-loop.js +423 -0
  150. package/dist/core/config.d.ts +115 -0
  151. package/dist/core/config.js +189 -0
  152. package/dist/core/errors.d.ts +58 -0
  153. package/dist/core/errors.js +88 -0
  154. package/dist/core/hooks.d.ts +35 -0
  155. package/dist/core/hooks.js +49 -0
  156. package/dist/core/index.d.ts +23 -0
  157. package/dist/core/index.js +29 -0
  158. package/dist/core/message-convert.d.ts +41 -0
  159. package/dist/core/message-convert.js +94 -0
  160. package/dist/core/middleware/auth.d.ts +24 -0
  161. package/dist/core/middleware/auth.js +28 -0
  162. package/dist/core/middleware/logging.d.ts +23 -0
  163. package/dist/core/middleware/logging.js +28 -0
  164. package/dist/core/middleware/rate-limit.d.ts +27 -0
  165. package/dist/core/middleware/rate-limit.js +38 -0
  166. package/dist/core/middleware/semantic-tools.d.ts +10 -0
  167. package/dist/core/middleware/semantic-tools.js +43 -0
  168. package/dist/core/middleware.d.ts +48 -0
  169. package/dist/core/middleware.js +38 -0
  170. package/dist/core/permission.d.ts +25 -0
  171. package/dist/core/permission.js +50 -0
  172. package/dist/core/provider-config.d.ts +129 -0
  173. package/dist/core/provider-config.js +273 -0
  174. package/dist/core/provider-env.d.ts +39 -0
  175. package/dist/core/provider-env.js +142 -0
  176. package/dist/core/provider-resolver.d.ts +12 -0
  177. package/dist/core/provider-resolver.js +12 -0
  178. package/dist/core/session-store.d.ts +75 -0
  179. package/dist/core/session-store.js +245 -0
  180. package/dist/core/settings-manager.d.ts +57 -0
  181. package/dist/core/settings-manager.js +359 -0
  182. package/dist/core/settings-schema.d.ts +38 -0
  183. package/dist/core/settings-schema.js +171 -0
  184. package/dist/core/skill-catalog.d.ts +6 -0
  185. package/dist/core/skill-catalog.js +17 -0
  186. package/dist/core/skill-invoker.d.ts +127 -0
  187. package/dist/core/skill-invoker.js +182 -0
  188. package/dist/core/stream-accumulator.d.ts +21 -0
  189. package/dist/core/stream-accumulator.js +51 -0
  190. package/dist/core/stream-manager.d.ts +58 -0
  191. package/dist/core/stream-manager.js +212 -0
  192. package/dist/core/tool-executor.d.ts +84 -0
  193. package/dist/core/tool-executor.js +256 -0
  194. package/dist/core/types.d.ts +259 -0
  195. package/dist/core/types.js +11 -0
  196. package/dist/gateway/gateway.d.ts +52 -0
  197. package/dist/gateway/gateway.js +537 -0
  198. package/dist/gateway/index.d.ts +21 -0
  199. package/dist/gateway/index.js +31 -0
  200. package/dist/gateway/openapi-importer.d.ts +15 -0
  201. package/dist/gateway/openapi-importer.js +66 -0
  202. package/dist/gateway/semantic-scorer.d.ts +7 -0
  203. package/dist/gateway/semantic-scorer.js +24 -0
  204. package/dist/gateway/settings-adapter.d.ts +49 -0
  205. package/dist/gateway/settings-adapter.js +137 -0
  206. package/dist/gateway/tool-factory.d.ts +9 -0
  207. package/dist/gateway/tool-factory.js +414 -0
  208. package/dist/gateway/types.d.ts +68 -0
  209. package/dist/gateway/types.js +7 -0
  210. package/dist/models-catalog.js +46 -0
  211. package/dist/providers/anthropic.d.ts +22 -0
  212. package/dist/providers/anthropic.js +148 -0
  213. package/dist/providers/factory.d.ts +10 -0
  214. package/dist/providers/factory.js +25 -0
  215. package/dist/providers/openai.d.ts +15 -0
  216. package/dist/providers/openai.js +71 -0
  217. package/dist/providers/types.d.ts +48 -0
  218. package/dist/providers/types.js +1 -0
  219. package/dist/skills/args.d.ts +37 -0
  220. package/dist/skills/args.js +99 -0
  221. package/dist/skills/index.d.ts +11 -0
  222. package/dist/skills/index.js +23 -0
  223. package/dist/skills/loader.d.ts +3 -0
  224. package/dist/skills/loader.js +59 -0
  225. package/dist/skills/parser.d.ts +7 -0
  226. package/dist/skills/parser.js +152 -0
  227. package/dist/skills/registry.d.ts +13 -0
  228. package/dist/skills/registry.js +74 -0
  229. package/dist/skills/resolver.d.ts +19 -0
  230. package/dist/skills/resolver.js +116 -0
  231. package/dist/skills/types.d.ts +74 -0
  232. package/dist/skills/types.js +50 -0
  233. package/dist/tools/browser.d.ts +2 -0
  234. package/dist/tools/browser.js +68 -0
  235. package/dist/tools/core.d.ts +20 -0
  236. package/dist/tools/core.js +244 -0
  237. package/dist/tools/email.d.ts +2 -0
  238. package/dist/tools/email.js +61 -0
  239. package/dist/tools/image.d.ts +2 -0
  240. package/dist/tools/image.js +257 -0
  241. package/dist/tools/index.d.ts +2 -0
  242. package/dist/tools/index.js +88 -0
  243. package/dist/tools/interface.d.ts +22 -0
  244. package/dist/tools/interface.js +1 -0
  245. package/dist/tools/notify.d.ts +2 -0
  246. package/dist/tools/notify.js +100 -0
  247. package/dist/tools/prompt-optimizer.d.ts +2 -0
  248. package/dist/tools/prompt-optimizer.js +65 -0
  249. package/dist/tools/screenshot.d.ts +2 -0
  250. package/dist/tools/screenshot.js +184 -0
  251. package/dist/tools/search.d.ts +2 -0
  252. package/dist/tools/search.js +78 -0
  253. package/dist/tools/todos.d.ts +10 -0
  254. package/dist/tools/todos.js +50 -0
  255. package/package.json +119 -0
  256. package/skills/docker-ops/SKILL.md +329 -0
  257. package/skills/k8s-deploy/SKILL.md +397 -0
  258. package/skills/log-analyzer/SKILL.md +331 -0
  259. package/skills/speckit-analyze/SKILL.md +260 -0
  260. package/skills/speckit-checklist/SKILL.md +374 -0
  261. package/skills/speckit-clarify/SKILL.md +286 -0
  262. package/skills/speckit-constitution/SKILL.md +157 -0
  263. package/skills/speckit-implement/SKILL.md +224 -0
  264. package/skills/speckit-plan/SKILL.md +171 -0
  265. package/skills/speckit-specify/SKILL.md +346 -0
  266. package/skills/speckit-tasks/SKILL.md +215 -0
  267. package/skills/speckit-taskstoissues/SKILL.md +107 -0
@@ -0,0 +1,96 @@
1
+ /**
2
+ * /compact command handler for Zoe CLI.
3
+ *
4
+ * Summarizes the conversation to reduce token usage while preserving
5
+ * key context needed to continue the session.
6
+ *
7
+ * Aliases: /compress
8
+ *
9
+ * Uses an `ora` spinner (stdout), so it is marked `interactive` and the TUI
10
+ * defers it — run it in the readline REPL.
11
+ */
12
+ import chalk from 'chalk';
13
+ import ora from 'ora';
14
+ import { runAgentLoop } from '../../../core/agent-loop.js';
15
+ import { generateId, now } from '../../../core/message-convert.js';
16
+ import { createHookExecutor } from '../../../core/hooks.js';
17
+ import { buildSystemPrompt } from '../system-prompts.js';
18
+ export const compactHandler = async (ctx) => {
19
+ const { agent, args } = ctx;
20
+ const spinner = ora('Compacting...').start();
21
+ try {
22
+ const allMessages = agent.getMessages();
23
+ // Separate system prompt from conversation messages
24
+ const systemMessage = allMessages.find((m) => m.role === 'system');
25
+ const conversationMessages = allMessages.filter((m) => m.role !== 'system');
26
+ if (conversationMessages.length === 0) {
27
+ return { output: chalk.yellow('Nothing to compact — conversation is empty.') };
28
+ }
29
+ // Build the summarization instruction
30
+ const focusHint = args.trim();
31
+ const summaryInstruction = `Summarize this conversation concisely. Preserve key decisions, code changes, and context needed to continue.${focusHint ? ` ${focusHint}` : ''}`;
32
+ // Create a temporary messages array for the summarization call
33
+ const summaryMessages = [
34
+ {
35
+ id: generateId(),
36
+ role: 'system',
37
+ content: summaryInstruction,
38
+ timestamp: now(),
39
+ },
40
+ // Flatten all non-system messages into a single user message for context
41
+ {
42
+ id: generateId(),
43
+ role: 'user',
44
+ content: conversationMessages
45
+ .map((m) => `[${m.role}]: ${m.content}`)
46
+ .join('\n\n'),
47
+ timestamp: now(),
48
+ },
49
+ ];
50
+ let result;
51
+ try {
52
+ result = await runAgentLoop({
53
+ provider: agent.getProvider(),
54
+ model: agent.getModel(),
55
+ messages: summaryMessages,
56
+ toolDefs: [], // no tools during summarization
57
+ maxSteps: 1,
58
+ hooks: createHookExecutor(),
59
+ });
60
+ }
61
+ catch (error) {
62
+ return { output: chalk.red(`Compaction failed: ${error.message}`) };
63
+ }
64
+ if (result.error) {
65
+ return { output: chalk.red(`Compaction failed: ${result.error.message}`) };
66
+ }
67
+ // Extract the summary text from the result messages
68
+ const assistantMessage = result.messages.find((m) => m.role === 'assistant');
69
+ const summaryText = assistantMessage?.content ?? 'Conversation history was compacted.';
70
+ // Replace agent messages: [system_prompt, summary]
71
+ const newMessages = systemMessage
72
+ ? [systemMessage]
73
+ : [
74
+ {
75
+ id: generateId(),
76
+ role: 'system',
77
+ content: buildSystemPrompt(),
78
+ timestamp: now(),
79
+ },
80
+ ];
81
+ newMessages.push({
82
+ id: generateId(),
83
+ role: 'assistant',
84
+ content: `[Conversation Summary]\n${summaryText}`,
85
+ timestamp: now(),
86
+ });
87
+ agent.setMessages(newMessages);
88
+ return { output: chalk.green('Conversation compacted. Token usage reduced.') };
89
+ }
90
+ catch (error) {
91
+ return { output: chalk.red(`Compaction error: ${error.message}`) };
92
+ }
93
+ finally {
94
+ spinner.stop();
95
+ }
96
+ };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * /exit command handler for Zoe CLI.
3
+ *
4
+ * Aliases: /quit
5
+ */
6
+ import type { CommandHandler } from './registry.js';
7
+ export declare const exitHandler: CommandHandler;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * /exit command handler for Zoe CLI.
3
+ *
4
+ * Aliases: /quit
5
+ */
6
+ import chalk from 'chalk';
7
+ export const exitHandler = async () => {
8
+ return { exit: true, output: chalk.cyan('Goodbye!') };
9
+ };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Zoe CLI — /gateway slash command
3
+ *
4
+ * Full management commands for the gateway subsystem.
5
+ * Receives the MCPGateway instance from the REPL when gateway is enabled.
6
+ */
7
+ export declare function createGatewayCommandHandler(gatewayInstance: any): (args: string) => Promise<string>;
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Zoe CLI — /gateway slash command
3
+ *
4
+ * Full management commands for the gateway subsystem.
5
+ * Receives the MCPGateway instance from the REPL when gateway is enabled.
6
+ */
7
+ import chalk from 'chalk';
8
+ export function createGatewayCommandHandler(gatewayInstance) {
9
+ return async (args) => {
10
+ if (!gatewayInstance) {
11
+ return chalk.yellow('Gateway is not enabled. Set gateway.enabled=true in settings and restart.');
12
+ }
13
+ const parts = args.trim().split(/\s+/);
14
+ const subcommand = parts[0] ?? 'help';
15
+ switch (subcommand) {
16
+ case 'help':
17
+ return [
18
+ 'Gateway management commands:',
19
+ ' /gateway list - List all targets and their status',
20
+ ' /gateway add <name> <json> - Register a new target (JSON config)',
21
+ ' /gateway remove <name> - Unregister a target',
22
+ ' /gateway toggle <name> - Toggle a target on/off',
23
+ ' /gateway routes - List routing rules',
24
+ ' /gateway routes add <pattern> <target> [priority] - Add route',
25
+ ' /gateway routes remove <pattern> <target> - Remove route',
26
+ ' /gateway credentials - List credential keys',
27
+ ' /gateway credentials set <key> <value> - Set a credential',
28
+ ' /gateway audit [target] [limit] - View audit logs',
29
+ ' /gateway usage - Show usage stats',
30
+ ].join('\n');
31
+ case 'list': {
32
+ const targets = gatewayInstance.getTargets();
33
+ const entries = Object.entries(targets);
34
+ if (entries.length === 0)
35
+ return 'No gateway targets registered.';
36
+ return entries.map(([name, t]) => {
37
+ const status = t.enabled ? chalk.green('enabled') : chalk.red('disabled');
38
+ if (t.kind === 'mcp') {
39
+ const tools = t.capabilities?.tools?.length ?? 0;
40
+ return ` ${name} (${status}, MCP/${t.transport}): ${tools} tools — ${t.description}`;
41
+ }
42
+ return ` ${name} (${status}, REST ${t.baseUrl}): ${t.operations.length} ops — ${t.description}`;
43
+ }).join('\n');
44
+ }
45
+ case 'add': {
46
+ const name = parts[1];
47
+ const jsonStr = parts.slice(2).join(' ');
48
+ if (!name || !jsonStr)
49
+ return 'Usage: /gateway add <name> <json-config>';
50
+ let target;
51
+ try {
52
+ target = JSON.parse(jsonStr);
53
+ }
54
+ catch {
55
+ return 'Error: Invalid JSON configuration.';
56
+ }
57
+ if (!['mcp', 'rest'].includes(target.kind)) {
58
+ return 'Error: config.kind must be "mcp" or "rest".';
59
+ }
60
+ target.enabled = true;
61
+ try {
62
+ await gatewayInstance.registerTarget(name, target, true);
63
+ return `Target "${name}" registered.`;
64
+ }
65
+ catch (e) {
66
+ return `Error: ${e.message}`;
67
+ }
68
+ }
69
+ case 'remove': {
70
+ const name = parts[1];
71
+ if (!name)
72
+ return 'Usage: /gateway remove <name>';
73
+ const ok = await gatewayInstance.unregisterTarget(name);
74
+ return ok ? `Target "${name}" removed.` : `Target "${name}" not found.`;
75
+ }
76
+ case 'toggle': {
77
+ const name = parts[1];
78
+ if (!name)
79
+ return 'Usage: /gateway toggle <name>';
80
+ const targets = gatewayInstance.getTargets();
81
+ const current = targets[name];
82
+ if (!current)
83
+ return `Target "${name}" not found.`;
84
+ const newState = !current.enabled;
85
+ const ok = await gatewayInstance.toggleTarget(name, newState);
86
+ return ok ? `Target "${name}" ${newState ? 'enabled' : 'disabled'}.` : `Failed to toggle "${name}".`;
87
+ }
88
+ case 'routes': {
89
+ const routesSub = parts[1];
90
+ if (routesSub === 'add') {
91
+ const pattern = parts[2];
92
+ const target = parts[3];
93
+ const priority = parseInt(parts[4] ?? '0', 10);
94
+ if (!pattern || !target)
95
+ return 'Usage: /gateway routes add <pattern> <target> [priority]';
96
+ await gatewayInstance.addRoute(pattern, target, priority);
97
+ return `Route added: "${pattern}" -> ${target} (priority ${priority}).`;
98
+ }
99
+ if (routesSub === 'remove') {
100
+ const pattern = parts[2];
101
+ const target = parts[3];
102
+ if (!pattern || !target)
103
+ return 'Usage: /gateway routes remove <pattern> <target>';
104
+ await gatewayInstance.removeRoute(pattern, target);
105
+ return `Route removed: "${pattern}" -> ${target}.`;
106
+ }
107
+ // List routes
108
+ const routes = gatewayInstance.getRoutes();
109
+ if (routes.length === 0)
110
+ return 'No routing rules configured.';
111
+ return routes.map((r) => ` "${r.pattern}" -> ${r.target} (priority ${r.priority})`).join('\n');
112
+ }
113
+ case 'credentials': {
114
+ const credSub = parts[1];
115
+ if (credSub === 'set') {
116
+ const key = parts[2];
117
+ const value = parts.slice(3).join(' ');
118
+ if (!key || !value)
119
+ return 'Usage: /gateway credentials set <key> <value>';
120
+ await gatewayInstance.setCredential(key, value);
121
+ return `Credential "${key}" set.`;
122
+ }
123
+ // List credential keys
124
+ const keys = gatewayInstance.listCredentialKeys();
125
+ if (keys.length === 0)
126
+ return 'No credentials stored.';
127
+ return `Stored credential keys:\n ${keys.join('\n ')}`;
128
+ }
129
+ case 'audit': {
130
+ const targetFilter = parts[1];
131
+ const limit = parseInt(parts[2] ?? '10', 10);
132
+ const logs = gatewayInstance.getAuditLogs(targetFilter && !targetFilter.match(/^\d+$/) ? targetFilter : undefined, limit);
133
+ if (logs.length === 0)
134
+ return 'No audit logs found.';
135
+ return logs.map((l) => {
136
+ const ts = new Date(l.timestamp).toISOString();
137
+ const status = l.success ? 'OK' : 'FAIL';
138
+ return ` [${ts}] ${l.agent} -> ${l.target} ${l.operation} (${status}, ${l.durationMs}ms)`;
139
+ }).join('\n');
140
+ }
141
+ case 'usage': {
142
+ const summary = gatewayInstance.getUsageSummary();
143
+ const entries = Object.entries(summary);
144
+ if (entries.length === 0)
145
+ return 'No gateway usage recorded.';
146
+ return entries.map(([name, stats]) => ` ${name}: ${stats.calls} calls, ${stats.errors} errors`).join('\n');
147
+ }
148
+ default:
149
+ return `Unknown gateway subcommand: ${subcommand}. Type /gateway help for available commands.`;
150
+ }
151
+ };
152
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * `/help` slash command handler.
3
+ *
4
+ * Displays available commands and loaded skills.
5
+ * Use `--all` to include hidden commands and aliases.
6
+ */
7
+ import type { CommandHandler, CommandRegistry } from './registry.js';
8
+ import type { SkillRegistry } from '../../../skills/types.js';
9
+ export declare function createHelpHandler(registry: CommandRegistry, skillRegistry?: SkillRegistry | null): CommandHandler;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * `/help` slash command handler.
3
+ *
4
+ * Displays available commands and loaded skills.
5
+ * Use `--all` to include hidden commands and aliases.
6
+ */
7
+ export function createHelpHandler(registry, skillRegistry) {
8
+ return async (ctx) => {
9
+ const showAll = ctx.args.trim() === '--all';
10
+ return { output: registry.help(showAll, skillRegistry ?? ctx.agent.getSkillRegistry()) };
11
+ };
12
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Zoe CLI — /models Command Handler
3
+ *
4
+ * In non-interactive mode, lists configured providers (returns output).
5
+ * In interactive mode, launches the provider/model wizard (owns stdin) — the
6
+ * TUI defers this command.
7
+ */
8
+ import { Agent } from '../agent.js';
9
+ import type { CommandHandler } from './registry.js';
10
+ export declare function modelsHandler(agent: Agent, config: any, activeProviderType: string): CommandHandler;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Zoe CLI — /models Command Handler
3
+ *
4
+ * In non-interactive mode, lists configured providers (returns output).
5
+ * In interactive mode, launches the provider/model wizard (owns stdin) — the
6
+ * TUI defers this command.
7
+ */
8
+ import chalk from 'chalk';
9
+ import { handleModelsCommand } from '../setup.js';
10
+ import { isNonInteractive } from '../docker-utils.js';
11
+ export function modelsHandler(agent, config, activeProviderType) {
12
+ const handler = async () => {
13
+ if (isNonInteractive()) {
14
+ const configured = Object.keys(config.models || {}).filter((k) => config.models?.[k]?.apiKey);
15
+ if (configured.length === 0) {
16
+ return { output: chalk.yellow('No providers configured. Set API key env vars to add providers.') };
17
+ }
18
+ const lines = [chalk.bold.cyan('Configured Providers:')];
19
+ for (const p of configured) {
20
+ const model = config.models?.[p]?.model || 'unknown';
21
+ const marker = p === activeProviderType ? chalk.green(' (active)') : '';
22
+ lines.push(` ${p} (${model})${marker}`);
23
+ }
24
+ lines.push(chalk.dim('\nUse --provider <name> flag or LLM_PROVIDER env var to switch.'));
25
+ return { output: lines.join('\n') };
26
+ }
27
+ // Interactive wizard — owns stdout/stdin; the TUI defers this command.
28
+ await handleModelsCommand(agent, config, activeProviderType);
29
+ return {};
30
+ };
31
+ return handler;
32
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Slash Command Registry for Zoe CLI.
3
+ *
4
+ * Flat namespace of `/command` handlers with alias support.
5
+ *
6
+ * Consistent contract: every handler returns a `CommandResult` describing what
7
+ * to render (`output`) and whether to terminate (`exit`). Handlers never write
8
+ * to stdout directly — the adapter renders the result (readline prints it; the
9
+ * TUI appends it to the feed). Lookup order: exact match → alias → skill
10
+ * invocation → unknown.
11
+ *
12
+ * `interactive` marks handlers that take over stdin/stdout themselves (inquirer
13
+ * wizards, ora spinners). They keep working in the readline REPL but cannot run
14
+ * under the TUI's stdin ownership — the TUI defers them.
15
+ */
16
+ import type { Agent } from '../agent.js';
17
+ import type { SkillRegistry } from '../../../skills/types.js';
18
+ export interface CommandContext {
19
+ agent: Agent;
20
+ args: string;
21
+ config: any;
22
+ }
23
+ /**
24
+ * A handler's outcome. `output` is the text the adapter renders (undefined if
25
+ * the handler produced none). `exit` signals the session should terminate.
26
+ */
27
+ export interface CommandResult {
28
+ output?: string;
29
+ exit?: boolean;
30
+ }
31
+ export type CommandHandler = (ctx: CommandContext) => Promise<CommandResult>;
32
+ export interface CommandEntry {
33
+ name: string;
34
+ handler: CommandHandler;
35
+ description: string;
36
+ aliases: string[];
37
+ hidden?: boolean;
38
+ /** Handler owns stdin/stdout (inquirer/ora) — TUI-deferred, readline-only. */
39
+ interactive?: boolean;
40
+ }
41
+ export type DispatchStatus = 'handled' | 'fallthrough' | 'exit';
42
+ export interface DispatchResult {
43
+ status: DispatchStatus;
44
+ output?: string;
45
+ }
46
+ export declare class CommandRegistry {
47
+ private commands;
48
+ private aliasMap;
49
+ register(name: string, handler: CommandHandler, options: {
50
+ description: string;
51
+ aliases?: string[];
52
+ hidden?: boolean;
53
+ interactive?: boolean;
54
+ }): void;
55
+ /** Resolve a raw input string to its command entry (exact or alias), or null. */
56
+ resolveCommand(input: string): CommandEntry | null;
57
+ /**
58
+ * Dispatch a raw user input string. Handlers return their output; the caller
59
+ * renders it. Returns `fallthrough` for non-commands and unmatched skills.
60
+ */
61
+ dispatch(input: string, ctx: CommandContext, skillRegistry: SkillRegistry | null): Promise<DispatchResult>;
62
+ /**
63
+ * Generate help text.
64
+ * @param showAll If true, include hidden commands and aliases.
65
+ * @param skillRegistry If provided, list loaded skills.
66
+ */
67
+ help(showAll?: boolean, skillRegistry?: SkillRegistry | null): string;
68
+ /** Get all registered command entries. */
69
+ getAll(): CommandEntry[];
70
+ }
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Slash Command Registry for Zoe CLI.
3
+ *
4
+ * Flat namespace of `/command` handlers with alias support.
5
+ *
6
+ * Consistent contract: every handler returns a `CommandResult` describing what
7
+ * to render (`output`) and whether to terminate (`exit`). Handlers never write
8
+ * to stdout directly — the adapter renders the result (readline prints it; the
9
+ * TUI appends it to the feed). Lookup order: exact match → alias → skill
10
+ * invocation → unknown.
11
+ *
12
+ * `interactive` marks handlers that take over stdin/stdout themselves (inquirer
13
+ * wizards, ora spinners). They keep working in the readline REPL but cannot run
14
+ * under the TUI's stdin ownership — the TUI defers them.
15
+ */
16
+ import chalk from 'chalk';
17
+ // ── Registry ───────────────────────────────────────────────────────────
18
+ export class CommandRegistry {
19
+ commands = new Map();
20
+ aliasMap = new Map(); // alias → canonical name
21
+ register(name, handler, options) {
22
+ const entry = {
23
+ name,
24
+ handler,
25
+ description: options.description,
26
+ aliases: options.aliases ?? [],
27
+ hidden: options.hidden,
28
+ interactive: options.interactive,
29
+ };
30
+ this.commands.set(name, entry);
31
+ for (const alias of entry.aliases) {
32
+ this.aliasMap.set(alias, name);
33
+ }
34
+ }
35
+ /** Resolve a raw input string to its command entry (exact or alias), or null. */
36
+ resolveCommand(input) {
37
+ const trimmed = input.trim();
38
+ if (!trimmed.startsWith('/'))
39
+ return null;
40
+ const withoutSlash = trimmed.slice(1);
41
+ const spaceIdx = withoutSlash.indexOf(' ');
42
+ const cmdName = (spaceIdx === -1 ? withoutSlash : withoutSlash.slice(0, spaceIdx)).toLowerCase();
43
+ return this.commands.get(cmdName) ?? this.commands.get(this.aliasMap.get(cmdName) ?? '') ?? null;
44
+ }
45
+ /**
46
+ * Dispatch a raw user input string. Handlers return their output; the caller
47
+ * renders it. Returns `fallthrough` for non-commands and unmatched skills.
48
+ */
49
+ async dispatch(input, ctx, skillRegistry) {
50
+ const entry = this.resolveCommand(input);
51
+ if (entry) {
52
+ const withoutSlash = input.trim().slice(1);
53
+ const spaceIdx = withoutSlash.indexOf(' ');
54
+ const args = spaceIdx === -1 ? '' : withoutSlash.slice(spaceIdx + 1);
55
+ const result = await entry.handler({ ...ctx, args });
56
+ return { status: result.exit ? 'exit' : 'handled', output: result.output };
57
+ }
58
+ // Skill invocation — delegate to caller (skill name with no matching command)
59
+ const trimmed = input.trim();
60
+ if (trimmed.startsWith('/')) {
61
+ const cmdName = trimmed.slice(1).split(/\s+/)[0]?.toLowerCase() ?? '';
62
+ if (skillRegistry && cmdName.length > 1) {
63
+ return { status: 'fallthrough' };
64
+ }
65
+ }
66
+ // Unknown command
67
+ const unknownName = trimmed.slice(1).split(/\s+/)[0] ?? '';
68
+ return {
69
+ status: 'handled',
70
+ output: `${chalk.yellow(`Unknown command: ${unknownName}`)}\n${chalk.dim('Type /help for available commands.')}`,
71
+ };
72
+ }
73
+ /**
74
+ * Generate help text.
75
+ * @param showAll If true, include hidden commands and aliases.
76
+ * @param skillRegistry If provided, list loaded skills.
77
+ */
78
+ help(showAll, skillRegistry) {
79
+ const lines = [];
80
+ lines.push(chalk.bold.cyan('Available Commands:'));
81
+ lines.push('');
82
+ for (const entry of this.commands.values()) {
83
+ if (entry.hidden && !showAll)
84
+ continue;
85
+ const aliasStr = entry.aliases.length > 0
86
+ ? chalk.dim(` (${entry.aliases.join(', ')})`)
87
+ : '';
88
+ lines.push(` ${chalk.green(`/${entry.name}`)}${aliasStr} — ${entry.description}`);
89
+ }
90
+ if (skillRegistry && skillRegistry.getAll().length > 0) {
91
+ lines.push('');
92
+ lines.push(chalk.bold.cyan('Loaded Skills:'));
93
+ lines.push(chalk.dim(' Use /<skill-name> [args] to invoke'));
94
+ for (const s of skillRegistry.getAll()) {
95
+ const desc = s.description.split('\n')[0];
96
+ lines.push(` ${chalk.green(`/${s.name}`)} — ${desc}`);
97
+ }
98
+ }
99
+ if (!showAll) {
100
+ lines.push('');
101
+ lines.push(chalk.dim('Use /help --all to see aliases and hidden commands.'));
102
+ }
103
+ lines.push('');
104
+ lines.push(chalk.dim('Prefixes: @path (file injection) !shell (shell passthrough)'));
105
+ return lines.join('\n');
106
+ }
107
+ /** Get all registered command entries. */
108
+ getAll() {
109
+ return [...this.commands.values()];
110
+ }
111
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Zoe CLI — Settings Display Utilities
3
+ *
4
+ * Pure formatting functions for settings display.
5
+ * Render functions produce bordered ASCII boxes for the wizard TUI.
6
+ */
7
+ import { SettingsCategory } from '../../../core/settings-schema.js';
8
+ import type { SettingsManager } from '../../../core/settings-manager.js';
9
+ export declare function formatSettingValue(value: unknown, secret: boolean): string;
10
+ export declare function maskValue(value: string): string;
11
+ export declare function getOriginLabel(dotKey: string, projectConfig?: Record<string, any>, globalConfig?: Record<string, any>): string;
12
+ export interface SettingRow {
13
+ dotKey: string;
14
+ value: string;
15
+ origin: string;
16
+ category: string;
17
+ restartRequired: boolean;
18
+ }
19
+ export declare function formatSettingTable(settings: SettingRow[]): string;
20
+ /**
21
+ * Render the bordered header box for Level 1 (category menu).
22
+ * Shows current provider, model, permissions, and auto-confirm.
23
+ */
24
+ export declare function renderWizardHeader(manager: SettingsManager): string;
25
+ /**
26
+ * Render the aligned settings list for Level 2 (category drilldown).
27
+ * 3-column layout: label, value, origin.
28
+ */
29
+ export declare function renderSettingsList(keys: string[], manager: SettingsManager): string;
30
+ /**
31
+ * Render the bordered mini-form for Level 3 (setting edit).
32
+ * Shows setting name, current value, source, and type.
33
+ */
34
+ export declare function renderSettingForm(dotKey: string, manager: SettingsManager): string;
35
+ /**
36
+ * Render the category status label for the Level 1 menu.
37
+ */
38
+ export declare function renderCategoryStatus(categoryKey: SettingsCategory, manager: SettingsManager): string;