@newsails/veil-cli 1.0.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 (199) hide show
  1. package/.veil/agents/analyst/AGENT.md +21 -0
  2. package/.veil/agents/analyst/agent.json +23 -0
  3. package/.veil/agents/assistant/AGENT.md +15 -0
  4. package/.veil/agents/assistant/agent.json +19 -0
  5. package/.veil/agents/coder/AGENT.md +18 -0
  6. package/.veil/agents/coder/agent.json +19 -0
  7. package/.veil/agents/hello/AGENT.md +5 -0
  8. package/.veil/agents/hello/agent.json +13 -0
  9. package/.veil/agents/writer/AGENT.md +12 -0
  10. package/.veil/agents/writer/agent.json +17 -0
  11. package/.veil/memory/MEMORY.md +343 -0
  12. package/.veil/memory/agents/analyst/MEMORY.md +55 -0
  13. package/.veil/memory/agents/hello/MEMORY.md +12 -0
  14. package/.veil/runtime.pid +1 -0
  15. package/.veil/settings.json +10 -0
  16. package/.veil-studio/studio.db +0 -0
  17. package/.veil-studio/studio.db-shm +0 -0
  18. package/.veil-studio/studio.db-wal +0 -0
  19. package/PLAN/01-vision.md +26 -0
  20. package/PLAN/02-tech-stack.md +94 -0
  21. package/PLAN/03-agents.md +232 -0
  22. package/PLAN/04-runtime.md +171 -0
  23. package/PLAN/05-tools.md +211 -0
  24. package/PLAN/06-communication.md +243 -0
  25. package/PLAN/07-storage.md +218 -0
  26. package/PLAN/08-api-cli.md +153 -0
  27. package/PLAN/09-permissions.md +108 -0
  28. package/PLAN/10-ably.md +105 -0
  29. package/PLAN/11-file-formats.md +442 -0
  30. package/PLAN/12-folder-structure.md +205 -0
  31. package/PLAN/13-operations.md +212 -0
  32. package/PLAN/README.md +23 -0
  33. package/README.md +128 -0
  34. package/REPORT.md +174 -0
  35. package/TODO.md +45 -0
  36. package/ai-tests/FRONTEND_PROMPT.md +220 -0
  37. package/ai-tests/Research & Planning.md +814 -0
  38. package/ai-tests/prompt-001-basic-api.md +230 -0
  39. package/ai-tests/prompt-002-basic-flows.md +230 -0
  40. package/ai-tests/prompt-003-agent-behaviors.md +220 -0
  41. package/api/middleware.js +60 -0
  42. package/api/routes/agents.js +193 -0
  43. package/api/routes/chat.js +93 -0
  44. package/api/routes/completions.js +122 -0
  45. package/api/routes/daemons.js +80 -0
  46. package/api/routes/memory.js +169 -0
  47. package/api/routes/models.js +40 -0
  48. package/api/routes/remote-methods.js +74 -0
  49. package/api/routes/sessions.js +208 -0
  50. package/api/routes/settings.js +108 -0
  51. package/api/routes/system.js +50 -0
  52. package/api/routes/tasks.js +270 -0
  53. package/api/server.js +120 -0
  54. package/cli/formatter.js +70 -0
  55. package/cli/index.js +443 -0
  56. package/cli/parser.js +113 -0
  57. package/config/config.json +10 -0
  58. package/config/models.json +6826 -0
  59. package/core/agent.js +329 -0
  60. package/core/cancel.js +38 -0
  61. package/core/compaction.js +176 -0
  62. package/core/events.js +13 -0
  63. package/core/loop.js +564 -0
  64. package/core/memory.js +51 -0
  65. package/core/prompt.js +185 -0
  66. package/core/queue.js +96 -0
  67. package/core/registry.js +291 -0
  68. package/core/remote-methods.js +124 -0
  69. package/core/router.js +386 -0
  70. package/core/running-sessions.js +18 -0
  71. package/docs/api/01-system.md +84 -0
  72. package/docs/api/02-agents.md +374 -0
  73. package/docs/api/03-chat.md +269 -0
  74. package/docs/api/04-tasks.md +470 -0
  75. package/docs/api/05-sessions.md +444 -0
  76. package/docs/api/06-daemons.md +142 -0
  77. package/docs/api/07-memory.md +186 -0
  78. package/docs/api/08-settings.md +133 -0
  79. package/docs/api/09-models.md +119 -0
  80. package/docs/api/09-websocket.md +350 -0
  81. package/docs/api/10-completions.md +134 -0
  82. package/docs/api/README.md +116 -0
  83. package/docs/guide/01-quickstart.md +220 -0
  84. package/docs/guide/02-folder-structure.md +185 -0
  85. package/docs/guide/03-configuration.md +252 -0
  86. package/docs/guide/04-agents.md +267 -0
  87. package/docs/guide/05-cli.md +290 -0
  88. package/docs/guide/06-tools.md +643 -0
  89. package/docs/guide/07-permissions.md +236 -0
  90. package/docs/guide/08-memory.md +139 -0
  91. package/docs/guide/09-multi-agent.md +271 -0
  92. package/docs/guide/10-daemons.md +226 -0
  93. package/docs/guide/README.md +53 -0
  94. package/docs/index.html +623 -0
  95. package/examples/README.md +151 -0
  96. package/examples/agents/assistant/AGENT.md +31 -0
  97. package/examples/agents/assistant/SOUL.md +9 -0
  98. package/examples/agents/assistant/agent.json +74 -0
  99. package/examples/agents/hello/AGENT.md +15 -0
  100. package/examples/agents/hello/agent.json +14 -0
  101. package/examples/agents/monitor/AGENT.md +51 -0
  102. package/examples/agents/monitor/agent.json +33 -0
  103. package/examples/agents/monitor/heartbeats/monitor.md +24 -0
  104. package/examples/agents/orchestrator/AGENT.md +70 -0
  105. package/examples/agents/orchestrator/agent.json +30 -0
  106. package/examples/agents/researcher/AGENT.md +52 -0
  107. package/examples/agents/researcher/agent.json +49 -0
  108. package/examples/agents/researcher/skills/web-research.md +28 -0
  109. package/examples/skills/code-review.md +72 -0
  110. package/examples/skills/summarise.md +59 -0
  111. package/examples/skills/web-research.md +42 -0
  112. package/examples/tools/word-count/index.js +27 -0
  113. package/examples/tools/word-count/tool.json +18 -0
  114. package/infrastructure/database.js +563 -0
  115. package/infrastructure/scheduler.js +122 -0
  116. package/llm/client.js +206 -0
  117. package/migrations/001-initial.sql +121 -0
  118. package/migrations/002-debuggability.sql +13 -0
  119. package/migrations/003-drop-orphaned-columns.sql +72 -0
  120. package/migrations/004-session-message-token-fields.sql +78 -0
  121. package/migrations/005-session-thinking.sql +5 -0
  122. package/package.json +30 -0
  123. package/schemas/agent.json +143 -0
  124. package/schemas/settings.json +111 -0
  125. package/scripts/fetch-models.js +93 -0
  126. package/session-debug-scenario.md +248 -0
  127. package/settings/fields.js +52 -0
  128. package/system-prompts/base-core.md +7 -0
  129. package/system-prompts/environment.md +13 -0
  130. package/system-prompts/reminders/anti-drift.md +6 -0
  131. package/system-prompts/reminders/stall-recovery.md +10 -0
  132. package/system-prompts/safety-rules.md +25 -0
  133. package/system-prompts/task-heuristics.md +27 -0
  134. package/test/client.js +71 -0
  135. package/test/integration/01-health.test.js +25 -0
  136. package/test/integration/02-agents.test.js +80 -0
  137. package/test/integration/03-chat-hello.test.js +48 -0
  138. package/test/integration/04-chat-multiturn.test.js +61 -0
  139. package/test/integration/05-chat-writer.test.js +48 -0
  140. package/test/integration/06-task-basic.test.js +68 -0
  141. package/test/integration/07-task-tools.test.js +74 -0
  142. package/test/integration/08-task-code-analysis.test.js +69 -0
  143. package/test/integration/09-memory-analyst.test.js +63 -0
  144. package/test/integration/10-task-advanced.test.js +85 -0
  145. package/test/integration/11-sessions-advanced.test.js +84 -0
  146. package/test/integration/12-assistant-chat-tools.test.js +75 -0
  147. package/test/integration/13-edge-cases.test.js +99 -0
  148. package/test/integration/14-cancel.test.js +62 -0
  149. package/test/integration/15-debug.test.js +106 -0
  150. package/test/integration/16-memory-api.test.js +83 -0
  151. package/test/integration/17-settings-api.test.js +41 -0
  152. package/test/integration/18-tool-search-activation.test.js +119 -0
  153. package/test/results/.gitkeep +0 -0
  154. package/test/runner.js +206 -0
  155. package/test/smoke.js +216 -0
  156. package/tools/agent_message.js +85 -0
  157. package/tools/agent_send.js +80 -0
  158. package/tools/agent_spawn.js +44 -0
  159. package/tools/bash.js +49 -0
  160. package/tools/edit_file.js +41 -0
  161. package/tools/glob.js +64 -0
  162. package/tools/grep.js +82 -0
  163. package/tools/list_dir.js +63 -0
  164. package/tools/log_write.js +31 -0
  165. package/tools/memory_read.js +38 -0
  166. package/tools/memory_search.js +65 -0
  167. package/tools/memory_write.js +42 -0
  168. package/tools/read_file.js +48 -0
  169. package/tools/sleep.js +22 -0
  170. package/tools/task_create.js +41 -0
  171. package/tools/task_respond.js +37 -0
  172. package/tools/task_spawn.js +64 -0
  173. package/tools/task_status.js +39 -0
  174. package/tools/task_subscribe.js +37 -0
  175. package/tools/todo_read.js +26 -0
  176. package/tools/todo_write.js +38 -0
  177. package/tools/tool_activate.js +24 -0
  178. package/tools/tool_search.js +24 -0
  179. package/tools/web_fetch.js +50 -0
  180. package/tools/web_search.js +52 -0
  181. package/tools/write_file.js +28 -0
  182. package/ui/api.js +190 -0
  183. package/ui/app.js +281 -0
  184. package/ui/index.html +382 -0
  185. package/ui/views/agents.js +377 -0
  186. package/ui/views/chat.js +610 -0
  187. package/ui/views/connection.js +96 -0
  188. package/ui/views/daemons.js +129 -0
  189. package/ui/views/feed.js +194 -0
  190. package/ui/views/memory.js +263 -0
  191. package/ui/views/models.js +146 -0
  192. package/ui/views/sessions.js +314 -0
  193. package/ui/views/settings.js +142 -0
  194. package/ui/views/tasks.js +415 -0
  195. package/utils/context.js +49 -0
  196. package/utils/id.js +16 -0
  197. package/utils/models.js +88 -0
  198. package/utils/paths.js +213 -0
  199. package/utils/settings.js +172 -0
@@ -0,0 +1,377 @@
1
+ 'use strict';
2
+ window.Veil = window.Veil || {};
3
+ window.Veil.views = window.Veil.views || {};
4
+
5
+ window.Veil.views.agents = {
6
+ _agents: [],
7
+ _selected: null,
8
+ _detail: null,
9
+
10
+ render() {
11
+ return `
12
+ <div style="display:flex;height:100%;">
13
+ <!-- List panel -->
14
+ <div style="width:240px;flex-shrink:0;border-right:1px solid var(--border);display:flex;flex-direction:column;overflow:hidden;background:var(--surface);">
15
+ <div style="padding:12px 14px;border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;">
16
+ <span style="font-weight:600;font-size:13px;color:var(--text);">Agents</span>
17
+ <button id="btn-create-agent" class="btn btn-primary btn-sm">+ New</button>
18
+ </div>
19
+ <div id="agent-list" style="flex:1;overflow-y:auto;padding:6px;">
20
+ <div style="padding:20px;text-align:center;color:var(--text3);font-size:13px;">${window.Veil.utils.spinner()}</div>
21
+ </div>
22
+ </div>
23
+ <!-- Detail panel -->
24
+ <div id="agent-detail" style="flex:1;overflow-y:auto;">
25
+ <div style="display:flex;align-items:center;justify-content:center;height:100%;color:var(--text3);font-size:13.5px;">
26
+ Select an agent
27
+ </div>
28
+ </div>
29
+ </div>`;
30
+ },
31
+
32
+ async mount() {
33
+ document.getElementById('btn-create-agent').addEventListener('click', () => this._showCreateModal());
34
+ await this._loadList();
35
+ },
36
+
37
+ unmount() {
38
+ this._selected = null;
39
+ this._detail = null;
40
+ },
41
+
42
+ async _loadList() {
43
+ const el = document.getElementById('agent-list');
44
+ if (!el) return;
45
+ try {
46
+ const data = await window.Veil.state.api.listAgents();
47
+ this._agents = data.agents || [];
48
+ if (this._agents.length === 0) {
49
+ el.innerHTML = `<div style="padding:24px;text-align:center;color:var(--text3);font-size:13px;line-height:1.7;">No agents found.<br>Create one with <b>+ New</b> or add agent folders to <code>.veil/agents/</code>.</div>`;
50
+ return;
51
+ }
52
+ const U = window.Veil.utils;
53
+ el.innerHTML = this._agents.map(a => {
54
+ const initial = a.name.slice(0, 2).toUpperCase();
55
+ const colors = ['#7C6AF0','#3B82F6','#22C55E','#EAB308','#EF4444','#EC4899'];
56
+ const col = colors[a.name.charCodeAt(0) % colors.length];
57
+ return `
58
+ <div class="list-item ${this._selected === a.name ? 'selected' : ''}" data-agent="${U.esc(a.name)}"
59
+ style="display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:8px;">
60
+ <div style="width:32px;height:32px;border-radius:50%;background:${col}22;color:${col};display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;flex-shrink:0;">${U.esc(initial)}</div>
61
+ <div style="min-width:0;flex:1;">
62
+ <div style="font-weight:600;font-size:13px;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">${U.esc(a.name)}</div>
63
+ <div style="font-size:11.5px;color:var(--text3);margin-top:1px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">${U.esc(a.model || '')}</div>
64
+ </div>
65
+ </div>`;
66
+ }).join('');
67
+
68
+ el.querySelectorAll('[data-agent]').forEach(row => {
69
+ row.addEventListener('click', () => {
70
+ const name = row.getAttribute('data-agent');
71
+ el.querySelectorAll('.list-item').forEach(r => r.classList.remove('selected'));
72
+ row.classList.add('selected');
73
+ this._selected = name;
74
+ this._loadDetail(name);
75
+ });
76
+ });
77
+
78
+ if (this._selected) this._loadDetail(this._selected);
79
+ } catch (err) {
80
+ if (el) el.innerHTML = `<div style="padding:16px;color:var(--red);font-size:13px;">Error: ${window.Veil.utils.esc(err.message)}</div>`;
81
+ }
82
+ },
83
+
84
+ async _loadDetail(name) {
85
+ const el = document.getElementById('agent-detail');
86
+ if (!el) return;
87
+ el.innerHTML = `<div style="padding:20px;color:var(--text3);">${window.Veil.utils.spinner()} Loading…</div>`;
88
+ try {
89
+ const data = await window.Veil.state.api.getAgent(name);
90
+ const agent = data.agent;
91
+ this._detail = agent;
92
+ const U = window.Veil.utils;
93
+ const modes = agent.modes || {};
94
+ const modeKeys = Object.keys(modes).filter(k => modes[k] && modes[k].enabled);
95
+
96
+ const initial = agent.name.slice(0,2).toUpperCase();
97
+ const colors = ['#7C6AF0','#3B82F6','#22C55E','#EAB308','#EF4444','#EC4899'];
98
+ const col = colors[agent.name.charCodeAt(0) % colors.length];
99
+ el.innerHTML = `
100
+ <div style="padding:24px;">
101
+ <!-- Header -->
102
+ <div style="display:flex;align-items:flex-start;gap:16px;margin-bottom:24px;">
103
+ <div style="width:48px;height:48px;border-radius:50%;background:${col}22;color:${col};display:flex;align-items:center;justify-content:center;font-size:16px;font-weight:700;flex-shrink:0;">${U.esc(initial)}</div>
104
+ <div style="flex:1;min-width:0;">
105
+ <div style="display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:4px;">
106
+ <h2 style="font-size:18px;font-weight:700;color:var(--text);letter-spacing:-0.02em;">${U.esc(agent.name)}</h2>
107
+ ${modeKeys.map(m => `<span class="badge badge-${m==='chat'?'active':m==='task'?'processing':m==='daemon'?'waiting':'closed'}">${U.esc(m)}</span>`).join('')}
108
+ </div>
109
+ <p style="font-size:13px;color:var(--text2);">${U.esc(agent.description || '(no description)')}</p>
110
+ </div>
111
+ <div style="display:flex;gap:6px;flex-shrink:0;">
112
+ <button class="btn btn-ghost btn-sm" id="btn-edit-agent">Edit</button>
113
+ <button class="btn btn-ghost btn-sm" id="btn-reload-agent">↻</button>
114
+ <button class="btn btn-danger btn-sm" id="btn-delete-agent">Delete</button>
115
+ </div>
116
+ </div>
117
+
118
+ <!-- Info grid -->
119
+ <div class="card" style="margin-bottom:16px;padding:18px;">
120
+ <div style="display:grid;grid-template-columns:repeat(3,1fr);gap:16px;">
121
+ ${this._infoRow('Model', agent.model)}
122
+ ${this._infoRow('Temperature', agent.temperature != null ? agent.temperature : '—')}
123
+ ${this._infoRow('Reasoning', agent.reasoning || '—')}
124
+ ${this._infoRow('Skill Discovery',agent.skillDiscovery ? 'on' : 'off')}
125
+ ${this._infoRow('Memory', agent.memory?.enabled ? `on (max ${agent.memory.maxLines||'?'} lines)` : 'off')}
126
+ ${this._infoRow('Source', agent.source || 'project')}
127
+ </div>
128
+ <div style="margin-top:14px;padding-top:14px;border-top:1px solid var(--border);">
129
+ <div class="info-label">Folder</div>
130
+ <code style="font-size:12px;color:var(--text2);font-family:'JetBrains Mono',monospace;">${U.esc(agent.agentFolder || '—')}</code>
131
+ </div>
132
+ </div>
133
+
134
+ <!-- Quick actions -->
135
+ <div class="card" style="margin-bottom:16px;padding:14px;">
136
+ <div style="font-size:11px;font-weight:600;color:var(--text3);text-transform:uppercase;letter-spacing:0.06em;margin-bottom:10px;">Open with agent</div>
137
+ <div style="display:flex;gap:8px;flex-wrap:wrap;">
138
+ ${modeKeys.includes('chat') ? `<button class="btn btn-secondary btn-sm" onclick="window.Veil.state.currentAgent='${U.esc(agent.name)}';window.Veil.navigate('chat')">💬 Chat</button>` : ''}
139
+ ${modeKeys.includes('task') ? `<button class="btn btn-secondary btn-sm" onclick="window.Veil.state.currentAgent='${U.esc(agent.name)}';window.Veil.navigate('tasks')">📋 Tasks</button>` : ''}
140
+ <button class="btn btn-secondary btn-sm" onclick="window.Veil.state.currentAgent='${U.esc(agent.name)}';window.Veil.navigate('sessions')">📝 Sessions</button>
141
+ <button class="btn btn-secondary btn-sm" id="btn-skills-${U.esc(agent.name)}">🔧 Skills</button>
142
+ <button class="btn btn-secondary btn-sm" onclick="window.Veil.state.currentAgent='${U.esc(agent.name)}';window.Veil.navigate('memory')">🧠 Memory</button>
143
+ </div>
144
+ </div>
145
+ </div>`;
146
+
147
+ document.getElementById('btn-edit-agent').addEventListener('click', () => this._showEditModal(agent));
148
+ document.getElementById('btn-reload-agent').addEventListener('click', () => this._reloadAgent(name));
149
+ document.getElementById('btn-delete-agent').addEventListener('click', () => this._confirmDelete(name));
150
+ document.getElementById(`btn-skills-${name}`)?.addEventListener('click', () => this._showSkills(name));
151
+ } catch (err) {
152
+ if (el) el.innerHTML = `<div style="padding:16px;color:var(--red);font-size:13px;">Error loading agent: ${window.Veil.utils.esc(err.message)}</div>`;
153
+ }
154
+ },
155
+
156
+ _infoRow(label, value) {
157
+ return `<div>
158
+ <div class="info-label">${label}</div>
159
+ <div class="info-value">${value}</div>
160
+ </div>`;
161
+ },
162
+
163
+ _renderMode(modeKey, modeConf) {
164
+ const U = window.Veil.utils;
165
+ const details = [];
166
+ if (modeConf.maxIterations) details.push(`max ${modeConf.maxIterations} iter`);
167
+ if (modeConf.maxDurationSeconds) details.push(`${modeConf.maxDurationSeconds}s limit`);
168
+ if (modeConf.tools && modeConf.tools.length) details.push(`tools: ${modeConf.tools.join(', ')}`);
169
+ if (modeConf.schedule) details.push(`cron: ${modeConf.schedule}`);
170
+ return `<div style="margin-bottom:8px;">
171
+ <span class="badge badge-${modeKey==='chat'?'active':modeKey==='task'?'processing':modeKey==='daemon'?'waiting':'closed'}" style="margin-right:6px;">${U.esc(modeKey)}</span>
172
+ ${details.length ? `<span style="font-size:12px;color:var(--text2);">${U.esc(details.join(' · '))}</span>` : ''}
173
+ </div>`;
174
+ },
175
+
176
+ async _reloadAgent(name) {
177
+ const btn = document.getElementById('btn-reload-agent');
178
+ if (btn) { btn.disabled = true; btn.textContent = '↻ …'; }
179
+ try {
180
+ await window.Veil.state.api.reloadAgent(name);
181
+ window.Veil.utils.toast(`Agent "${name}" reloaded`, 'success');
182
+ this._loadDetail(name);
183
+ } catch (err) {
184
+ window.Veil.utils.toast('Reload failed: ' + err.message, 'error');
185
+ if (btn) { btn.disabled = false; btn.textContent = '↻ Reload'; }
186
+ }
187
+ },
188
+
189
+ async _confirmDelete(name) {
190
+ window.Veil.modal.show(`
191
+ <div>
192
+ <h3 style="font-size:16px;font-weight:700;color:var(--red);margin-bottom:12px;">Delete agent "${window.Veil.utils.esc(name)}"?</h3>
193
+ <p style="font-size:13px;color:var(--text2);margin-bottom:20px;">This permanently removes the agent folder and all its contents from disk. This cannot be undone.</p>
194
+ <div style="display:flex;gap:10px;justify-content:flex-end;">
195
+ <button class="btn btn-secondary" onclick="window.Veil.modal.hide()">Cancel</button>
196
+ <button class="btn btn-danger" id="modal-confirm-del">Delete permanently</button>
197
+ </div>
198
+ </div>`);
199
+ document.getElementById('modal-confirm-del').addEventListener('click', async () => {
200
+ try {
201
+ await window.Veil.state.api.deleteAgent(name);
202
+ window.Veil.modal.hide();
203
+ window.Veil.utils.toast(`Agent "${name}" deleted`, 'success');
204
+ this._selected = null;
205
+ document.getElementById('agent-detail').innerHTML = `<div style="display:flex;align-items:center;justify-content:center;height:100%;color:var(--text3);font-size:13.5px;">Agent deleted</div>`;
206
+ await this._loadList();
207
+ } catch (err) {
208
+ window.Veil.utils.toast('Delete failed: ' + err.message, 'error');
209
+ window.Veil.modal.hide();
210
+ }
211
+ });
212
+ },
213
+
214
+ _showCreateModal() {
215
+ const U = window.Veil.utils;
216
+ window.Veil.modal.show(`
217
+ <div>
218
+ <h3 style="font-size:16px;font-weight:700;color:var(--text);margin-bottom:16px;">Create Agent</h3>
219
+ <div id="create-agent-err" style="display:none;background:var(--red-dim);color:var(--red);border:1px solid rgba(239,68,68,0.3);border-radius:7px;padding:8px 12px;margin-bottom:12px;font-size:13px;"></div>
220
+ <div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:12px;">
221
+ <div>
222
+ <label style="display:block;font-size:11.5px;font-weight:600;color:var(--text3);text-transform:uppercase;letter-spacing:0.06em;margin-bottom:6px;">Name *</label>
223
+ <input id="ca-name" class="input" placeholder="my-agent" />
224
+ </div>
225
+ <div>
226
+ <label style="display:block;font-size:11.5px;font-weight:600;color:var(--text3);text-transform:uppercase;letter-spacing:0.06em;margin-bottom:6px;">Level</label>
227
+ <select id="ca-level" class="input" style="cursor:pointer;">
228
+ <option value="project">project</option>
229
+ <option value="global">global</option>
230
+ </select>
231
+ </div>
232
+ </div>
233
+ <div style="margin-bottom:12px;">
234
+ <label style="display:block;font-size:11.5px;font-weight:600;color:var(--text3);text-transform:uppercase;letter-spacing:0.06em;margin-bottom:6px;">Model *</label>
235
+ <input id="ca-model" class="input" placeholder="anthropic/claude-sonnet-4-5" />
236
+ </div>
237
+ <div style="margin-bottom:12px;">
238
+ <label style="display:block;font-size:11.5px;font-weight:600;color:var(--text3);text-transform:uppercase;letter-spacing:0.06em;margin-bottom:6px;">Description</label>
239
+ <input id="ca-desc" class="input" placeholder="(optional)" />
240
+ </div>
241
+ <div style="margin-bottom:12px;">
242
+ <label style="display:block;font-size:11.5px;font-weight:600;color:var(--text3);text-transform:uppercase;letter-spacing:0.06em;margin-bottom:8px;">Enable Modes</label>
243
+ <div style="display:flex;gap:14px;flex-wrap:wrap;">
244
+ <label style="display:flex;align-items:center;gap:6px;font-size:13px;cursor:pointer;"><input type="checkbox" id="ca-chat" checked> chat</label>
245
+ <label style="display:flex;align-items:center;gap:6px;font-size:13px;cursor:pointer;"><input type="checkbox" id="ca-task"> task</label>
246
+ <label style="display:flex;align-items:center;gap:6px;font-size:13px;cursor:pointer;"><input type="checkbox" id="ca-daemon"> daemon</label>
247
+ <label style="display:flex;align-items:center;gap:6px;font-size:13px;cursor:pointer;"><input type="checkbox" id="ca-subagent"> subagent</label>
248
+ </div>
249
+ </div>
250
+ <div style="margin-bottom:20px;">
251
+ <label style="display:block;font-size:11.5px;font-weight:600;color:var(--text3);text-transform:uppercase;letter-spacing:0.06em;margin-bottom:6px;">AGENT.md content</label>
252
+ <textarea id="ca-agentmd" class="input mono" rows="4" placeholder="System prompt / instructions for the agent…" style="resize:vertical;"></textarea>
253
+ </div>
254
+ <div style="display:flex;gap:10px;justify-content:flex-end;">
255
+ <button class="btn btn-secondary" onclick="window.Veil.modal.hide()">Cancel</button>
256
+ <button class="btn btn-primary" id="ca-submit">Create Agent</button>
257
+ </div>
258
+ </div>`);
259
+
260
+ document.getElementById('ca-submit').addEventListener('click', async () => {
261
+ const name = document.getElementById('ca-name').value.trim();
262
+ const model = document.getElementById('ca-model').value.trim();
263
+ const level = document.getElementById('ca-level').value;
264
+ const desc = document.getElementById('ca-desc').value.trim();
265
+ const agentMd = document.getElementById('ca-agentmd').value;
266
+ const errEl = document.getElementById('create-agent-err');
267
+
268
+ if (!name) { errEl.textContent = 'Name is required'; errEl.style.display='block'; return; }
269
+ if (!model) { errEl.textContent = 'Model is required'; errEl.style.display='block'; return; }
270
+
271
+ const modes = {};
272
+ if (document.getElementById('ca-chat').checked) modes.chat = { enabled: true };
273
+ if (document.getElementById('ca-task').checked) modes.task = { enabled: true };
274
+ if (document.getElementById('ca-daemon').checked) modes.daemon = { enabled: true };
275
+ if (document.getElementById('ca-subagent').checked) modes.subagent = { enabled: true };
276
+
277
+ const config = { model };
278
+ if (desc) config.description = desc;
279
+ if (Object.keys(modes).length) config.modes = modes;
280
+
281
+ const body = { name, level, config };
282
+ if (agentMd.trim()) body.agentMd = agentMd;
283
+
284
+ const btn = document.getElementById('ca-submit');
285
+ btn.disabled = true; btn.innerHTML = U.spinner() + ' Creating…';
286
+ try {
287
+ await window.Veil.state.api.createAgent(body);
288
+ window.Veil.modal.hide();
289
+ window.Veil.utils.toast(`Agent "${name}" created`, 'success');
290
+ this._selected = name;
291
+ await this._loadList();
292
+ } catch (err) {
293
+ btn.disabled = false; btn.textContent = 'Create Agent';
294
+ errEl.textContent = err.message; errEl.style.display = 'block';
295
+ }
296
+ });
297
+ },
298
+
299
+ _showEditModal(agent) {
300
+ const U = window.Veil.utils;
301
+ const configCopy = Object.assign({}, agent);
302
+ delete configCopy.agentFolder; delete configCopy.name;
303
+ window.Veil.modal.show(`
304
+ <div>
305
+ <h3 style="font-size:16px;font-weight:700;color:var(--text);margin-bottom:4px;">Edit agent: ${U.esc(agent.name)}</h3>
306
+ <p style="font-size:13px;color:var(--text2);margin-bottom:16px;">Edit the JSON config below (merged with existing) and/or update AGENT.md.</p>
307
+ <div id="edit-agent-err" style="display:none;background:var(--red-dim);color:var(--red);border:1px solid rgba(239,68,68,0.3);border-radius:7px;padding:8px 12px;margin-bottom:12px;font-size:13px;"></div>
308
+ <div style="margin-bottom:12px;">
309
+ <label style="display:block;font-size:11.5px;font-weight:600;color:var(--text3);text-transform:uppercase;letter-spacing:0.06em;margin-bottom:6px;">Config JSON (shallow-merged)</label>
310
+ <textarea id="ea-config" class="input mono" rows="10" style="resize:vertical;">${U.esc(JSON.stringify(configCopy, null, 2))}</textarea>
311
+ </div>
312
+ <div style="margin-bottom:20px;">
313
+ <label style="display:block;font-size:11.5px;font-weight:600;color:var(--text3);text-transform:uppercase;letter-spacing:0.06em;margin-bottom:6px;">AGENT.md <span style="color:var(--text3);font-weight:400;text-transform:none;">(leave blank to keep)</span></label>
314
+ <textarea id="ea-agentmd" class="input mono" rows="5" placeholder="Optional: new AGENT.md content" style="resize:vertical;"></textarea>
315
+ </div>
316
+ <div style="display:flex;gap:10px;justify-content:flex-end;">
317
+ <button class="btn btn-secondary" onclick="window.Veil.modal.hide()">Cancel</button>
318
+ <button class="btn btn-primary" id="ea-submit">Save Changes</button>
319
+ </div>
320
+ </div>`);
321
+
322
+ document.getElementById('ea-submit').addEventListener('click', async () => {
323
+ const errEl = document.getElementById('edit-agent-err');
324
+ const btn = document.getElementById('ea-submit');
325
+ let config;
326
+ try {
327
+ config = JSON.parse(document.getElementById('ea-config').value);
328
+ } catch {
329
+ errEl.textContent = 'Invalid JSON in config field'; errEl.style.display = 'block'; return;
330
+ }
331
+ const body = { config };
332
+ const agentMd = document.getElementById('ea-agentmd').value;
333
+ if (agentMd.trim()) body.agentMd = agentMd;
334
+ btn.disabled = true; btn.innerHTML = U.spinner() + ' Saving…';
335
+ try {
336
+ await window.Veil.state.api.updateAgent(agent.name, body);
337
+ window.Veil.modal.hide();
338
+ window.Veil.utils.toast('Agent updated', 'success');
339
+ this._loadDetail(agent.name);
340
+ } catch (err) {
341
+ btn.disabled = false; btn.textContent = 'Save Changes';
342
+ errEl.textContent = err.message; errEl.style.display = 'block';
343
+ }
344
+ });
345
+ },
346
+
347
+ async _showSkills(name) {
348
+ window.Veil.modal.show(`<div style="color:var(--text2);padding:12px;">${window.Veil.utils.spinner()} Loading skills…</div>`);
349
+ try {
350
+ const data = await window.Veil.state.api.getAgentSkills(name);
351
+ const U = window.Veil.utils;
352
+ const skills = data.skills || [];
353
+ const tools = data.customTools || [];
354
+ window.Veil.modal.show(`
355
+ <div>
356
+ <h3 style="font-size:16px;font-weight:700;color:var(--text);margin-bottom:16px;">Skills — ${U.esc(name)}</h3>
357
+ ${skills.length === 0 && tools.length === 0 ? '<p style="color:var(--text3);font-size:13.5px;">No skills or custom tools configured.</p>' : ''}
358
+ ${skills.length ? `<div style="margin-bottom:14px;">
359
+ <div class="panel-header" style="border:none;padding:0 0 8px;">Skills</div>
360
+ ${skills.map(s => `<div style="display:flex;align-items:center;gap:10px;padding:6px 0;border-bottom:1px solid var(--border);">
361
+ <span style="color:${s.loaded ? 'var(--green)' : 'var(--red)'}">${s.loaded ? '✓' : '✗'}</span>
362
+ <span style="font-size:13px;color:var(--text);">${U.esc(s.name)}</span>
363
+ <span style="font-size:12px;color:var(--text3);">${U.esc(s.source || '')}</span>
364
+ ${s.error ? `<span style="font-size:12px;color:var(--red);">${U.esc(s.error)}</span>` : ''}
365
+ </div>`).join('')}
366
+ </div>` : ''}
367
+ ${tools.length ? `<div>
368
+ <div class="panel-header" style="border:none;padding:0 0 8px;">Custom Tools</div>
369
+ ${tools.map(t => `<div style="padding:6px 0;border-bottom:1px solid var(--border);font-size:13px;color:var(--text);">${U.esc(t.name)} <span style="color:var(--text3);">${U.esc(t.source||'')}</span></div>`).join('')}
370
+ </div>` : ''}
371
+ <div style="margin-top:16px;text-align:right;"><button class="btn btn-secondary" onclick="window.Veil.modal.hide()">Close</button></div>
372
+ </div>`);
373
+ } catch (err) {
374
+ window.Veil.modal.show(`<div style="color:var(--red);padding:12px;">${window.Veil.utils.esc(err.message)}<br><br><button class="btn btn-secondary btn-sm" onclick="window.Veil.modal.hide()">Close</button></div>`);
375
+ }
376
+ },
377
+ };