@agentuity/opencode 0.1.15

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 (128) hide show
  1. package/AGENTS.md +40 -0
  2. package/README.md +113 -0
  3. package/dist/agents/builder.d.ts +4 -0
  4. package/dist/agents/builder.d.ts.map +1 -0
  5. package/dist/agents/builder.js +298 -0
  6. package/dist/agents/builder.js.map +1 -0
  7. package/dist/agents/expert.d.ts +4 -0
  8. package/dist/agents/expert.d.ts.map +1 -0
  9. package/dist/agents/expert.js +773 -0
  10. package/dist/agents/expert.js.map +1 -0
  11. package/dist/agents/index.d.ts +10 -0
  12. package/dist/agents/index.d.ts.map +1 -0
  13. package/dist/agents/index.js +40 -0
  14. package/dist/agents/index.js.map +1 -0
  15. package/dist/agents/lead.d.ts +4 -0
  16. package/dist/agents/lead.d.ts.map +1 -0
  17. package/dist/agents/lead.js +463 -0
  18. package/dist/agents/lead.js.map +1 -0
  19. package/dist/agents/memory.d.ts +4 -0
  20. package/dist/agents/memory.d.ts.map +1 -0
  21. package/dist/agents/memory.js +317 -0
  22. package/dist/agents/memory.js.map +1 -0
  23. package/dist/agents/reviewer.d.ts +4 -0
  24. package/dist/agents/reviewer.d.ts.map +1 -0
  25. package/dist/agents/reviewer.js +321 -0
  26. package/dist/agents/reviewer.js.map +1 -0
  27. package/dist/agents/scout.d.ts +4 -0
  28. package/dist/agents/scout.d.ts.map +1 -0
  29. package/dist/agents/scout.js +280 -0
  30. package/dist/agents/scout.js.map +1 -0
  31. package/dist/agents/types.d.ts +29 -0
  32. package/dist/agents/types.d.ts.map +1 -0
  33. package/dist/agents/types.js +2 -0
  34. package/dist/agents/types.js.map +1 -0
  35. package/dist/config/index.d.ts +2 -0
  36. package/dist/config/index.d.ts.map +1 -0
  37. package/dist/config/index.js +2 -0
  38. package/dist/config/index.js.map +1 -0
  39. package/dist/config/loader.d.ts +14 -0
  40. package/dist/config/loader.d.ts.map +1 -0
  41. package/dist/config/loader.js +98 -0
  42. package/dist/config/loader.js.map +1 -0
  43. package/dist/index.d.ts +6 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +6 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/mcps/context7.d.ts +3 -0
  48. package/dist/mcps/context7.d.ts.map +1 -0
  49. package/dist/mcps/context7.js +7 -0
  50. package/dist/mcps/context7.js.map +1 -0
  51. package/dist/mcps/grep-app.d.ts +3 -0
  52. package/dist/mcps/grep-app.d.ts.map +1 -0
  53. package/dist/mcps/grep-app.js +7 -0
  54. package/dist/mcps/grep-app.js.map +1 -0
  55. package/dist/mcps/index.d.ts +8 -0
  56. package/dist/mcps/index.d.ts.map +1 -0
  57. package/dist/mcps/index.js +25 -0
  58. package/dist/mcps/index.js.map +1 -0
  59. package/dist/plugin/hooks/keyword.d.ts +6 -0
  60. package/dist/plugin/hooks/keyword.d.ts.map +1 -0
  61. package/dist/plugin/hooks/keyword.js +110 -0
  62. package/dist/plugin/hooks/keyword.js.map +1 -0
  63. package/dist/plugin/hooks/params.d.ts +20 -0
  64. package/dist/plugin/hooks/params.d.ts.map +1 -0
  65. package/dist/plugin/hooks/params.js +157 -0
  66. package/dist/plugin/hooks/params.js.map +1 -0
  67. package/dist/plugin/hooks/session.d.ts +6 -0
  68. package/dist/plugin/hooks/session.d.ts.map +1 -0
  69. package/dist/plugin/hooks/session.js +20 -0
  70. package/dist/plugin/hooks/session.js.map +1 -0
  71. package/dist/plugin/hooks/tools.d.ts +7 -0
  72. package/dist/plugin/hooks/tools.d.ts.map +1 -0
  73. package/dist/plugin/hooks/tools.js +111 -0
  74. package/dist/plugin/hooks/tools.js.map +1 -0
  75. package/dist/plugin/index.d.ts +2 -0
  76. package/dist/plugin/index.d.ts.map +1 -0
  77. package/dist/plugin/index.js +2 -0
  78. package/dist/plugin/index.js.map +1 -0
  79. package/dist/plugin/plugin.d.ts +3 -0
  80. package/dist/plugin/plugin.d.ts.map +1 -0
  81. package/dist/plugin/plugin.js +249 -0
  82. package/dist/plugin/plugin.js.map +1 -0
  83. package/dist/services/auth.d.ts +14 -0
  84. package/dist/services/auth.d.ts.map +1 -0
  85. package/dist/services/auth.js +54 -0
  86. package/dist/services/auth.js.map +1 -0
  87. package/dist/services/index.d.ts +2 -0
  88. package/dist/services/index.d.ts.map +1 -0
  89. package/dist/services/index.js +2 -0
  90. package/dist/services/index.js.map +1 -0
  91. package/dist/tools/delegate.d.ts +35 -0
  92. package/dist/tools/delegate.d.ts.map +1 -0
  93. package/dist/tools/delegate.js +51 -0
  94. package/dist/tools/delegate.js.map +1 -0
  95. package/dist/tools/index.d.ts +2 -0
  96. package/dist/tools/index.d.ts.map +1 -0
  97. package/dist/tools/index.js +2 -0
  98. package/dist/tools/index.js.map +1 -0
  99. package/dist/types.d.ts +143 -0
  100. package/dist/types.d.ts.map +1 -0
  101. package/dist/types.js +16 -0
  102. package/dist/types.js.map +1 -0
  103. package/package.json +56 -0
  104. package/src/agents/builder.ts +300 -0
  105. package/src/agents/expert.ts +775 -0
  106. package/src/agents/index.ts +49 -0
  107. package/src/agents/lead.ts +466 -0
  108. package/src/agents/memory.ts +320 -0
  109. package/src/agents/reviewer.ts +323 -0
  110. package/src/agents/scout.ts +283 -0
  111. package/src/agents/types.ts +30 -0
  112. package/src/config/index.ts +1 -0
  113. package/src/config/loader.ts +127 -0
  114. package/src/index.ts +24 -0
  115. package/src/mcps/context7.ts +8 -0
  116. package/src/mcps/grep-app.ts +8 -0
  117. package/src/mcps/index.ts +34 -0
  118. package/src/plugin/hooks/keyword.ts +126 -0
  119. package/src/plugin/hooks/params.ts +188 -0
  120. package/src/plugin/hooks/session.ts +27 -0
  121. package/src/plugin/hooks/tools.ts +127 -0
  122. package/src/plugin/index.ts +1 -0
  123. package/src/plugin/plugin.ts +280 -0
  124. package/src/services/auth.ts +88 -0
  125. package/src/services/index.ts +1 -0
  126. package/src/tools/delegate.ts +62 -0
  127. package/src/tools/index.ts +1 -0
  128. package/src/types.ts +131 -0
@@ -0,0 +1,188 @@
1
+ import type { PluginContext, CoderConfig } from '../../types';
2
+
3
+ export interface ParamsHooks {
4
+ onParams: (input: unknown, output: unknown) => Promise<void>;
5
+ }
6
+
7
+ /**
8
+ * Dynamic mode triggers based on user message content.
9
+ *
10
+ * Trigger phrases are intentionally specific to avoid false positives.
11
+ * Single common words are avoided; multi-word phrases are preferred.
12
+ */
13
+ const DYNAMIC_MODES = {
14
+ /**
15
+ * Creative mode: Higher temperature for brainstorming and idea generation
16
+ * Advertised keyword: "brainstorm"
17
+ */
18
+ creative: {
19
+ triggers: [
20
+ 'brainstorm',
21
+ 'be creative',
22
+ 'get creative',
23
+ 'give me ideas',
24
+ 'explore options',
25
+ 'explore alternatives',
26
+ 'think outside the box',
27
+ ],
28
+ settings: {
29
+ temperature: 0.8,
30
+ },
31
+ },
32
+
33
+ /**
34
+ * Deep thinking mode: Maximum reasoning for complex analysis
35
+ * Advertised keyword: "think hard"
36
+ */
37
+ deepThink: {
38
+ triggers: [
39
+ 'think hard',
40
+ 'think deeply',
41
+ 'reason through this',
42
+ 'analyze carefully',
43
+ 'think this through',
44
+ 'give this extra thought',
45
+ ],
46
+ settings: {
47
+ // For Anthropic models, this enables max thinking budget
48
+ // These get passed through as provider options
49
+ thinking: {
50
+ type: 'enabled',
51
+ budgetTokens: 32000,
52
+ },
53
+ },
54
+ },
55
+
56
+ /**
57
+ * Thorough mode: More iterations for comprehensive work
58
+ * Advertised keyword: "dig deep" or "go deep"
59
+ */
60
+ thorough: {
61
+ triggers: [
62
+ 'dig deep',
63
+ 'go deep',
64
+ 'deep dive',
65
+ 'take your time',
66
+ 'be thorough',
67
+ 'be meticulous',
68
+ ],
69
+ settings: {
70
+ maxSteps: 50,
71
+ },
72
+ },
73
+ } as const;
74
+
75
+ /**
76
+ * Check if message content triggers any dynamic mode
77
+ */
78
+ function detectMode(
79
+ messageContent: string
80
+ ): { mode: string; settings: Record<string, unknown> } | null {
81
+ const lower = messageContent.toLowerCase();
82
+
83
+ for (const [modeName, config] of Object.entries(DYNAMIC_MODES)) {
84
+ for (const trigger of config.triggers) {
85
+ if (lower.includes(trigger)) {
86
+ return {
87
+ mode: modeName,
88
+ settings: config.settings as Record<string, unknown>,
89
+ };
90
+ }
91
+ }
92
+ }
93
+
94
+ return null;
95
+ }
96
+
97
+ export function createParamsHooks(ctx: PluginContext, _config: CoderConfig): ParamsHooks {
98
+ return {
99
+ async onParams(input: unknown, output: unknown): Promise<void> {
100
+ // Input contains: sessionID, agent, model, provider, message
101
+ const inputObj = input as {
102
+ sessionID?: string;
103
+ agent?: string;
104
+ message?: { content?: string };
105
+ };
106
+
107
+ // Output contains: temperature, topP, topK, options
108
+ const outputObj = output as {
109
+ temperature?: number;
110
+ topP?: number;
111
+ topK?: number;
112
+ options?: Record<string, unknown>;
113
+ };
114
+
115
+ // Get message content for mode detection
116
+ const messageContent = inputObj.message?.content || '';
117
+ if (!messageContent) return;
118
+
119
+ // Check for dynamic mode triggers
120
+ const detected = detectMode(messageContent);
121
+ if (!detected) return;
122
+
123
+ // Apply detected mode settings
124
+ ctx.client.app.log({
125
+ body: {
126
+ service: 'agentuity-coder',
127
+ level: 'info',
128
+ message: `Dynamic mode activated: ${detected.mode}`,
129
+ extra: { mode: detected.mode, settings: detected.settings },
130
+ },
131
+ });
132
+
133
+ // Show toast to user
134
+ const modeMessages: Record<string, string> = {
135
+ creative: '🎨 Creative Mode activated - higher creativity enabled',
136
+ deepThink: '🧠 Deep Think Mode activated - extended reasoning enabled',
137
+ thorough: '🔍 Thorough Mode activated - more iterations enabled',
138
+ };
139
+
140
+ try {
141
+ ctx.client.tui?.showToast?.({
142
+ body: { message: modeMessages[detected.mode] || `${detected.mode} mode activated` },
143
+ });
144
+ } catch {
145
+ // Toast may not be available in all contexts (e.g., headless)
146
+ }
147
+
148
+ // Apply temperature if specified
149
+ if (
150
+ 'temperature' in detected.settings &&
151
+ typeof detected.settings.temperature === 'number'
152
+ ) {
153
+ outputObj.temperature = detected.settings.temperature;
154
+ }
155
+
156
+ // Apply maxSteps if specified
157
+ if ('maxSteps' in detected.settings && typeof detected.settings.maxSteps === 'number') {
158
+ outputObj.options = {
159
+ ...outputObj.options,
160
+ maxSteps: detected.settings.maxSteps,
161
+ };
162
+ }
163
+
164
+ // Apply provider-specific options (like thinking budget)
165
+ if ('thinking' in detected.settings) {
166
+ outputObj.options = {
167
+ ...outputObj.options,
168
+ thinking: detected.settings.thinking,
169
+ };
170
+ }
171
+ },
172
+ };
173
+ }
174
+
175
+ /**
176
+ * Advertised magic words for users:
177
+ *
178
+ * - "brainstorm" - Activates creative mode (temperature → 0.8)
179
+ * - "think hard" - Activates deep thinking mode (max reasoning budget)
180
+ * - "dig deep" / "go deep" - Activates thorough mode (maxSteps → 50)
181
+ *
182
+ * These can also be triggered by specific phrases like:
183
+ * - "be creative", "give me ideas", "explore options", "explore alternatives"
184
+ * - "think deeply", "analyze carefully", "reason through this"
185
+ * - "deep dive", "take your time", "be thorough", "be meticulous"
186
+ *
187
+ * Note: Triggers use multi-word phrases to avoid false positives from common words.
188
+ */
@@ -0,0 +1,27 @@
1
+ import type { PluginContext, CoderConfig } from '../../types';
2
+
3
+ export interface SessionHooks {
4
+ onMessage: (input: unknown, output: unknown) => Promise<void>;
5
+ }
6
+
7
+ export function createSessionHooks(_ctx: PluginContext, _config: CoderConfig): SessionHooks {
8
+ const initializedSessions = new Set<string>();
9
+
10
+ return {
11
+ async onMessage(input: unknown, _output: unknown): Promise<void> {
12
+ const sessionId = extractSessionId(input);
13
+ if (!sessionId) return;
14
+
15
+ if (!initializedSessions.has(sessionId)) {
16
+ initializedSessions.add(sessionId);
17
+ }
18
+ },
19
+ };
20
+ }
21
+
22
+ function extractSessionId(input: unknown): string | undefined {
23
+ if (typeof input === 'object' && input !== null && 'sessionID' in input) {
24
+ return (input as { sessionID: string }).sessionID;
25
+ }
26
+ return undefined;
27
+ }
@@ -0,0 +1,127 @@
1
+ import type { PluginContext, CoderConfig } from '../../types';
2
+ import { checkAuth } from '../../services/auth';
3
+
4
+ export interface ToolHooks {
5
+ before: (input: unknown, output: unknown) => Promise<void>;
6
+ after: (input: unknown, output: unknown) => Promise<void>;
7
+ }
8
+
9
+ const CLOUD_TOOL_PREFIXES = [
10
+ 'agentuity.kv',
11
+ 'agentuity.storage',
12
+ 'agentuity.vector',
13
+ 'agentuity.sandbox',
14
+ ];
15
+
16
+ /** Cloud service detection for bash commands */
17
+ const CLOUD_SERVICES: Record<string, { name: string; emoji: string }> = {
18
+ 'agentuity cloud kv': { name: 'KV Storage', emoji: '🗄️' },
19
+ 'agentuity cloud storage': { name: 'Object Storage', emoji: '📦' },
20
+ 'agentuity cloud vector': { name: 'Vector Search', emoji: '🔍' },
21
+ 'agentuity cloud sandbox': { name: 'Sandbox', emoji: '🏖️' },
22
+ 'agentuity cloud db': { name: 'Postgres', emoji: '🐘' },
23
+ 'agentuity cloud ssh': { name: 'SSH', emoji: '🔐' },
24
+ 'agentuity cloud scp': { name: 'File Transfer', emoji: '📤' },
25
+ };
26
+
27
+ export function createToolHooks(ctx: PluginContext, config: CoderConfig): ToolHooks {
28
+ const blockedCommands = config.blockedCommands ?? [];
29
+
30
+ return {
31
+ async before(input: unknown, output: unknown): Promise<void> {
32
+ const toolName = extractToolName(input);
33
+ if (!toolName) return;
34
+
35
+ // Check MCP cloud tools
36
+ if (isCloudTool(toolName)) {
37
+ const authResult = await checkAuth();
38
+ if (!authResult.ok) {
39
+ const out = output as { error?: string };
40
+ out.error = authResult.error;
41
+ }
42
+ }
43
+
44
+ // Detect bash commands using agentuity CLI
45
+ if (toolName === 'bash') {
46
+ const command = extractBashCommand(input);
47
+ if (command?.includes('agentuity')) {
48
+ // Security: Block sensitive commands
49
+ const blockedPattern = isBlockedCommand(command, blockedCommands);
50
+ if (blockedPattern) {
51
+ const out = output as { blocked?: boolean; error?: string };
52
+ out.blocked = true;
53
+ out.error = `🚫 Blocked: "${blockedPattern}" commands are not allowed for security reasons.`;
54
+
55
+ ctx.client.app.log({
56
+ body: {
57
+ service: 'agentuity-coder',
58
+ level: 'warn',
59
+ message: `Blocked command pattern: ${blockedPattern}`,
60
+ extra: { command },
61
+ },
62
+ });
63
+ return;
64
+ }
65
+
66
+ // Show toast for cloud service usage
67
+ const service = detectCloudService(command);
68
+ if (service) {
69
+ try {
70
+ ctx.client.tui?.showToast?.({
71
+ body: { message: `${service.emoji} Agentuity ${service.name}` },
72
+ });
73
+ } catch {
74
+ // Toast may not be available
75
+ }
76
+ }
77
+ }
78
+ }
79
+ },
80
+
81
+ async after(_input: unknown, _output: unknown): Promise<void> {},
82
+ };
83
+ }
84
+
85
+ function extractToolName(input: unknown): string | undefined {
86
+ if (typeof input === 'object' && input !== null && 'tool' in input) {
87
+ return (input as { tool: string }).tool;
88
+ }
89
+ return undefined;
90
+ }
91
+
92
+ function extractBashCommand(input: unknown): string | undefined {
93
+ if (typeof input !== 'object' || input === null) return undefined;
94
+ const inp = input as Record<string, unknown>;
95
+
96
+ // Try different possible arg structures
97
+ if (typeof inp.command === 'string') return inp.command;
98
+ if (typeof inp.args === 'object' && inp.args !== null) {
99
+ const args = inp.args as Record<string, unknown>;
100
+ if (typeof args.command === 'string') return args.command;
101
+ }
102
+
103
+ return undefined;
104
+ }
105
+
106
+ function detectCloudService(command: string): { name: string; emoji: string } | null {
107
+ for (const [pattern, service] of Object.entries(CLOUD_SERVICES)) {
108
+ if (command.includes(pattern)) {
109
+ return service;
110
+ }
111
+ }
112
+ return null;
113
+ }
114
+
115
+ function isCloudTool(toolName: string): boolean {
116
+ return CLOUD_TOOL_PREFIXES.some((prefix) => toolName.startsWith(prefix));
117
+ }
118
+
119
+ /** Check if a command matches any blocked pattern, returns the matched pattern or null */
120
+ function isBlockedCommand(command: string, blockedPatterns: string[]): string | null {
121
+ for (const pattern of blockedPatterns) {
122
+ if (command.includes(pattern)) {
123
+ return pattern;
124
+ }
125
+ }
126
+ return null;
127
+ }
@@ -0,0 +1 @@
1
+ export { createCoderPlugin } from './plugin';
@@ -0,0 +1,280 @@
1
+ import type { PluginContext, PluginHooks, AgentConfig, CommandDefinition } from '../types';
2
+ import { agents } from '../agents';
3
+ import { loadCoderConfig, getDefaultConfig, mergeConfig } from '../config';
4
+ import { createSessionHooks } from './hooks/session';
5
+ import { createToolHooks } from './hooks/tools';
6
+ import { createKeywordHooks } from './hooks/keyword';
7
+ import { createParamsHooks } from './hooks/params';
8
+ import { z } from 'zod';
9
+ import type { AgentRole } from '../types';
10
+
11
+ // Agent display names for @mentions
12
+ const AGENT_MENTIONS: Record<AgentRole, string> = {
13
+ lead: '@Agentuity Coder Lead',
14
+ scout: '@Agentuity Coder Scout',
15
+ builder: '@Agentuity Coder Builder',
16
+ reviewer: '@Agentuity Coder Reviewer',
17
+ memory: '@Agentuity Coder Memory',
18
+ expert: '@Agentuity Coder Expert',
19
+ };
20
+
21
+ export async function createCoderPlugin(ctx: PluginContext): Promise<PluginHooks> {
22
+ ctx.client.app.log({
23
+ body: {
24
+ service: 'agentuity-coder',
25
+ level: 'info',
26
+ message: 'Agentuity Coder plugin initializing',
27
+ },
28
+ });
29
+
30
+ const userConfig = await loadCoderConfig();
31
+ const coderConfig = mergeConfig(getDefaultConfig(), userConfig);
32
+
33
+ const sessionHooks = createSessionHooks(ctx, coderConfig);
34
+ const toolHooks = createToolHooks(ctx, coderConfig);
35
+ const keywordHooks = createKeywordHooks(ctx, coderConfig);
36
+ const paramsHooks = createParamsHooks(ctx, coderConfig);
37
+
38
+ const configHandler = createConfigHandler(coderConfig);
39
+
40
+ // Get the tool helper from Open Code context if available
41
+ const toolHelper = (ctx as { tool?: unknown }).tool as
42
+ | ((schema: (s: typeof z) => unknown) => unknown)
43
+ | undefined;
44
+
45
+ const tools = toolHelper ? createTools(toolHelper) : undefined;
46
+
47
+ // Show startup toast (fire and forget, don't block)
48
+ try {
49
+ ctx.client.tui?.showToast?.({ body: { message: '🚀 Agentuity Coder ready' } });
50
+ } catch {
51
+ // Toast may not be available
52
+ }
53
+
54
+ return {
55
+ ...(tools ? { tool: tools } : {}),
56
+ config: configHandler,
57
+ 'chat.message': async (input: unknown, output: unknown) => {
58
+ await keywordHooks.onMessage(input, output);
59
+ await sessionHooks.onMessage(input, output);
60
+ },
61
+ 'chat.params': paramsHooks.onParams,
62
+ 'tool.execute.before': toolHooks.before,
63
+ 'tool.execute.after': toolHooks.after,
64
+ };
65
+ }
66
+
67
+ function createConfigHandler(
68
+ coderConfig: ReturnType<typeof getDefaultConfig>
69
+ ): (config: Record<string, unknown>) => Promise<void> {
70
+ return async (config: Record<string, unknown>) => {
71
+ const agentConfigs = createAgentConfigs(coderConfig);
72
+ const commands = createCommands();
73
+
74
+ config.agent = {
75
+ ...(config.agent as Record<string, AgentConfig> | undefined),
76
+ ...agentConfigs,
77
+ };
78
+
79
+ config.command = {
80
+ ...(config.command as Record<string, CommandDefinition> | undefined),
81
+ ...commands,
82
+ };
83
+ };
84
+ }
85
+
86
+ function createAgentConfigs(
87
+ config: ReturnType<typeof getDefaultConfig>
88
+ ): Record<string, AgentConfig> {
89
+ const result: Record<string, AgentConfig> = {};
90
+
91
+ for (const agent of Object.values(agents)) {
92
+ const modelConfig = config.agents?.[agent.role];
93
+
94
+ // Convert tools.exclude to Open Code format (tool: false)
95
+ const tools: Record<string, boolean> = {};
96
+ if (agent.tools?.exclude) {
97
+ for (const tool of agent.tools.exclude) {
98
+ tools[tool] = false;
99
+ }
100
+ }
101
+
102
+ result[agent.displayName] = {
103
+ description: agent.description,
104
+ model: modelConfig?.model ?? agent.defaultModel,
105
+ prompt: agent.systemPrompt,
106
+ mode: agent.mode ?? 'subagent',
107
+ ...(Object.keys(tools).length > 0 ? { tools } : {}),
108
+ // Pass through thinking/reasoning settings
109
+ ...(agent.variant ? { variant: agent.variant } : {}),
110
+ ...(agent.temperature !== undefined ? { temperature: agent.temperature } : {}),
111
+ ...(agent.maxSteps !== undefined ? { maxSteps: agent.maxSteps } : {}),
112
+ };
113
+ }
114
+
115
+ return result;
116
+ }
117
+
118
+ function createCommands(): Record<string, CommandDefinition> {
119
+ return {
120
+ 'agentuity-coder': {
121
+ name: 'agentuity-coder',
122
+ description:
123
+ 'Run a task with the Agentuity Coder agent team (use @Agentuity Coder Lead, @Agentuity Coder Scout, etc.)',
124
+ template: `<coder-mode>
125
+ You are the Agentuity Coder Lead agent orchestrating the Agentuity Coder team.
126
+
127
+ ## Your Team (use @mentions to invoke)
128
+ - **@Agentuity Coder Scout**: Explore codebase, find patterns, research docs (read-only)
129
+ - **@Agentuity Coder Builder**: Implement features, write code, run tests
130
+ - **@Agentuity Coder Reviewer**: Review changes, catch issues, apply fixes
131
+ - **@Agentuity Coder Memory**: Store context, remember decisions
132
+ - **@Agentuity Coder Expert**: Agentuity CLI and cloud services specialist
133
+
134
+ ## Task
135
+ $ARGUMENTS
136
+
137
+ ## Guidelines
138
+ 1. Use @Agentuity Coder Scout first to understand context
139
+ 2. Delegate implementation to @Agentuity Coder Builder
140
+ 3. Have @Agentuity Coder Reviewer check the work
141
+ 4. Use @Agentuity Coder Expert for Agentuity CLI questions
142
+ 5. Only use cloud services when genuinely helpful
143
+ 6. **When done, tell @Agentuity Coder Memory to memorialize the session**
144
+ </coder-mode>`,
145
+ agent: 'Agentuity Coder Lead',
146
+ argumentHint: '"task description"',
147
+ },
148
+ 'agentuity-memory-save': {
149
+ name: 'agentuity-memory-save',
150
+ description: 'Save the current session to memory for future recall',
151
+ template: `Memorialize this session. Summarize what was accomplished in this conversation:
152
+ - Problem/task that was addressed
153
+ - Key decisions and their rationale
154
+ - Patterns and approaches used
155
+ - Solutions implemented
156
+ - Open questions or follow-ups
157
+
158
+ Save to vector storage using the coder-sessions namespace so the team can recall this work in future sessions.
159
+
160
+ $ARGUMENTS`,
161
+ agent: 'Agentuity Coder Memory',
162
+ argumentHint: '(optional additional context)',
163
+ },
164
+
165
+ // ─────────────────────────────────────────────────────────────────────
166
+ // Agentuity Cloud Service Commands
167
+ // ─────────────────────────────────────────────────────────────────────
168
+
169
+ 'agentuity-cloud': {
170
+ name: 'agentuity-cloud',
171
+ description: '☁️ Agentuity cloud services (KV, Storage, Vector, Sandbox, DB, SSH, etc.)',
172
+ template: `You are the Agentuity Coder Expert helping with Agentuity cloud services.
173
+
174
+ Use the \`agentuity\` CLI to execute the user's request.
175
+
176
+ ## Available Services
177
+ | Service | CLI | Purpose |
178
+ |---------|-----|---------|
179
+ | KV | \`agentuity cloud kv\` | Key-value storage (namespaces, keys) |
180
+ | Storage | \`agentuity cloud storage\` | Object/file storage (buckets) |
181
+ | Vector | \`agentuity cloud vector\` | Embeddings & semantic search |
182
+ | Sandbox | \`agentuity cloud sandbox\` | Isolated execution environments |
183
+ | Database | \`agentuity cloud db\` | Postgres databases |
184
+ | SSH | \`agentuity cloud ssh\` | SSH into deployments/sandboxes |
185
+ | Deployments | \`agentuity cloud deployment\` | Manage deployments |
186
+ | Agents | \`agentuity cloud agent\` | Cloud agent management |
187
+ | Sessions | \`agentuity cloud session\` | Agent session data |
188
+ | Threads | \`agentuity cloud thread\` | Conversation threads |
189
+
190
+ ## Guidelines
191
+ 1. First check auth: \`agentuity auth whoami\`
192
+ 2. Prefer \`--json\` for programmatic output
193
+ 3. List/inspect before creating new resources
194
+ 4. Explain what commands you're running
195
+
196
+ ## User Request
197
+ $ARGUMENTS`,
198
+ agent: 'Agentuity Coder Expert',
199
+ subtask: true,
200
+ argumentHint: '"list kv namespaces" or "upload file.txt to storage"',
201
+ },
202
+
203
+ 'agentuity-sandbox': {
204
+ name: 'agentuity-sandbox',
205
+ description: '🏖️ Agentuity sandboxes (isolated execution environments)',
206
+ template: `You are the Agentuity Coder Expert helping with Agentuity sandboxes.
207
+
208
+ Use the \`agentuity cloud sandbox\` CLI commands to help the user.
209
+
210
+ ## Common Commands
211
+ \`\`\`bash
212
+ agentuity cloud sandbox runtime list --json # List available runtimes (bun:1, python:3.14, etc.)
213
+ agentuity cloud sandbox run [--memory 1Gi] [--cpu 1000m] \\
214
+ [--runtime <name>] [--runtimeId <id>] \\
215
+ [--name <name>] [--description <text>] \\
216
+ -- <command> # One-shot execution
217
+ agentuity cloud sandbox create --json [--memory 1Gi] [--cpu 1000m] \\
218
+ [--network] [--runtime <name>] [--runtimeId <id>] \\
219
+ [--name <name>] [--description <text>] # Create persistent sandbox
220
+ agentuity cloud sandbox list --json # List sandboxes (includes telemetry)
221
+ agentuity cloud sandbox exec <id> -- <command> # Run in existing sandbox
222
+ agentuity cloud sandbox files <id> [path] --json # List files
223
+ agentuity cloud sandbox cp ./local <id>:/home/agentuity # Copy files to sandbox
224
+ agentuity cloud sandbox delete <id> --json # Delete sandbox
225
+ agentuity cloud sandbox snapshot create <id> \\
226
+ [--name <name>] [--description <text>] [--tag <tag>] # Save sandbox state
227
+ \`\`\`
228
+
229
+ ## Guidelines
230
+ 1. First check auth: \`agentuity auth whoami\`
231
+ 2. Use \`--json\` for programmatic output
232
+ 3. Explain what commands you're running
233
+ 4. Default working directory inside sandboxes: \`/home/agentuity\`
234
+ 5. Use \`runtime list\` to find runtimes, then pass \`--runtime\` or \`--runtimeId\` on \`run\`/\`create\`
235
+ 6. Use \`--name\` and \`--description\` for better tracking
236
+ 7. Snapshot \`--tag\` defaults to \`latest\`, max 128 chars, must match \`^[a-zA-Z0-9][a-zA-Z0-9._-]*$\`
237
+ 8. Telemetry fields from \`list\`/\`get\`: \`cpuTimeMs\`, \`memoryByteSec\`, \`networkEgressBytes\`, \`networkEnabled\`, \`mode\`
238
+
239
+ ## User Request
240
+ $ARGUMENTS`,
241
+ agent: 'Agentuity Coder Expert',
242
+ subtask: true,
243
+ argumentHint: '"run bun test" or "create a sandbox with 2Gi memory"',
244
+ },
245
+ };
246
+ }
247
+
248
+ function createTools(tool: (schema: (s: typeof z) => unknown) => unknown): Record<string, unknown> {
249
+ const coderDelegate = tool((s) => ({
250
+ description: `Delegate a task to a specialized Agentuity Coder agent.
251
+
252
+ Use this to:
253
+ - Scout: Explore codebase, find patterns, research documentation
254
+ - Builder: Implement features, write code, run tests
255
+ - Reviewer: Review changes, catch issues, apply fixes
256
+ - Memory: Store context, remember decisions across sessions
257
+ - Expert: Get help with Agentuity CLI and cloud services`,
258
+ args: s.object({
259
+ agent: s
260
+ .enum(['scout', 'builder', 'reviewer', 'memory', 'expert'])
261
+ .describe('Which agent to delegate to'),
262
+ task: s.string().describe('Clear description of the task'),
263
+ context: s.string().optional().describe('Additional context from previous tasks'),
264
+ }),
265
+ execute: async (args: { agent: AgentRole; task: string; context?: string }) => {
266
+ const mention = AGENT_MENTIONS[args.agent];
267
+ let prompt = `${mention}\n\n## Task\n${args.task}`;
268
+ if (args.context) {
269
+ prompt = `${mention}\n\n## Context\n${args.context}\n\n## Task\n${args.task}`;
270
+ }
271
+ return {
272
+ output: `To delegate this task, use the Task tool with this prompt:\n\n${prompt}\n\nThe ${args.agent} agent will handle this task.`,
273
+ };
274
+ },
275
+ }));
276
+
277
+ return {
278
+ coder_delegate: coderDelegate,
279
+ };
280
+ }