@nomad-e/bluma-cli 0.0.78 → 0.0.79

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.
@@ -1,206 +1,206 @@
1
- {
2
- "nativeTools": [
3
- {
4
- "type": "function",
5
- "function": {
6
- "name": "shell_command",
7
- "description": "Executes a terminal command in a robust and Windows/Linux compatible way.",
8
- "parameters": {
9
- "type": "object",
10
- "properties": {
11
- "command": {
12
- "type": "string",
13
- "description": "Shell command to execute"
14
- },
15
- "timeout": {
16
- "type": "integer",
17
- "description": "Maximum execution time in seconds",
18
- "default": 20
19
- },
20
- "cwd": {
21
- "type": "string",
22
- "description": "Working directory for command execution (must use absolute path)"
23
- },
24
- "verbose": {
25
- "type": "boolean",
26
- "description": "If True, returns detailed report; if False, only main output",
27
- "default": false
28
- }
29
- },
30
- "required": [
31
- "command",
32
- "timeout"
33
- ]
34
- }
35
- }
36
- },
37
- {
38
- "type": "function",
39
- "function": {
40
- "name": "edit_tool",
41
- "description": "Safely and precisely replaces text in a file, or creates a new file. The tool is resilient to common formatting issues but performs best with precise input.\n\n**Best Practices for Success:**\n1. **Use a read tool first:** Always read the file to get the exact content before generating the `old_string`.\n2. **Provide Context:** For `old_string`, provide a unique, multi-line segment of the file. Including 3+ lines of context around the target change is highly recommended to ensure precision.\n3. **Create New Files:** To create a new file, provide the full `file_path` and an empty string for `old_string`.",
42
- "parameters": {
43
- "type": "object",
44
- "properties": {
45
- "file_path": {
46
- "type": "string",
47
- "description": "The absolute or relative path to the file. The tool will correctly resolve the path for the current operating system."
48
- },
49
- "old_string": {
50
- "type": "string",
51
- "description": "The exact text to be replaced. To ensure accuracy, this should be a unique, multi-line segment from the file, including all original indentation and whitespace. Do not manually escape newlines (use literal newlines, not '\\n'). For creating a new file, this must be an empty string."
52
- },
53
- "new_string": {
54
- "type": "string",
55
- "description": "The new text that will replace `old_string`. Match the indentation and formatting of the surrounding code to maintain code quality. Do not manually escape newlines."
56
- },
57
- "expected_replacements": {
58
- "type": "integer",
59
- "description": "Optional. The number of occurrences to replace. Defaults to 1. If you expect to replace multiple instances of `old_string`, set this value accordingly.",
60
- "default": 1
61
- }
62
- },
63
- "required": [
64
- "file_path",
65
- "old_string",
66
- "new_string"
67
- ]
68
- }
69
- }
70
- },
71
- {
72
- "type": "function",
73
- "function": {
74
- "name": "agent_end_task",
75
- "description": "End the current agent task",
76
- "parameters": {
77
- "type": "object",
78
- "properties": {},
79
- "required": []
80
- }
81
- }
82
- },
83
- {
84
- "type": "function",
85
- "function": {
86
- "name": "message_notify_user",
87
- "description": "This tool allows the agent to send structured messages to the user for confirming task start, replying to messages from name:'user_overlay' (continuing or integrating into the flow), giving short initial responses, notifying about method or strategy changes, providing progress updates, and concluding tasks with a final confirmation or result.",
88
- "parameters": {
89
- "type": "object",
90
- "properties": {
91
- "message": {
92
- "type": "string",
93
- "description": "The body of the message in Markdown format."
94
- }
95
- },
96
- "required": [
97
- "message"
98
- ]
99
- }
100
- }
101
- },
102
- {
103
- "type": "function",
104
- "function": {
105
- "name": "ls_tool",
106
- "description": "Lists files and subdirectories with advanced support for pagination and filtering. Automatically ignores common unnecessary files/directories like '.venv', 'node_modules', etc.",
107
- "parameters": {
108
- "type": "object",
109
- "properties": {
110
- "directory_path": {
111
- "type": "string",
112
- "description": "Path of the directory to list. Defaults to '.' (current directory).",
113
- "default": "."
114
- },
115
- "recursive": {
116
- "type": "boolean",
117
- "description": "If True, lists recursively all subdirectories.",
118
- "default": false
119
- },
120
- "ignore_patterns": {
121
- "type": "array",
122
- "items": {
123
- "type": "string"
124
- },
125
- "description": "Additional patterns to ignore (beyond defaults). E.g., ['test_*', '*.tmp']"
126
- },
127
- "start_index": {
128
- "type": "integer",
129
- "description": "Starting index for pagination (0-based).",
130
- "default": 0
131
- },
132
- "end_index": {
133
- "type": "integer",
134
- "description": "Ending index for pagination (exclusive). If not provided, lists everything from start_index."
135
- },
136
- "show_hidden": {
137
- "type": "boolean",
138
- "description": "If True, shows files/directories starting with '.'.",
139
- "default": false
140
- },
141
- "file_extensions": {
142
- "type": "array",
143
- "items": {
144
- "type": "string"
145
- },
146
- "description": "List of extensions to filter (e.g., ['.ts', '.js', '.md']). If not provided, shows all file types."
147
- },
148
- "max_depth": {
149
- "type": "integer",
150
- "description": "Maximum depth for recursive listing. If not provided, there is no limit."
151
- }
152
- },
153
- "required": []
154
- }
155
- }
156
- },
157
- {
158
- "type": "function",
159
- "function": {
160
- "name": "count_file_lines",
161
- "description": "Counts and returns the total number of lines in a text file. Useful for quickly determining file size or checking if a file is empty before reading it.",
162
- "parameters": {
163
- "type": "object",
164
- "properties": {
165
- "filepath": {
166
- "type": "string",
167
- "description": "Path to the file to count lines from. Can be relative or absolute."
168
- }
169
- },
170
- "required": [
171
- "filepath"
172
- ]
173
- }
174
- }
175
- },
176
- {
177
- "type": "function",
178
- "function": {
179
- "name": "read_file_lines",
180
- "description": "Reads and returns content between specific line numbers from a text file. Ideal for efficiently reading portions of large files.",
181
- "parameters": {
182
- "type": "object",
183
- "properties": {
184
- "filepath": {
185
- "type": "string",
186
- "description": "Path to the file to read from."
187
- },
188
- "start_line": {
189
- "type": "integer",
190
- "description": "Starting line number (1-based index). Must be >= 1."
191
- },
192
- "end_line": {
193
- "type": "integer",
194
- "description": "Ending line number (1-based index, inclusive). Must be >= start_line."
195
- }
196
- },
197
- "required": [
198
- "filepath",
199
- "start_line",
200
- "end_line"
201
- ]
202
- }
203
- }
204
- }
205
- ]
1
+ {
2
+ "nativeTools": [
3
+ {
4
+ "type": "function",
5
+ "function": {
6
+ "name": "shell_command",
7
+ "description": "Executes a terminal command in a robust and Windows/Linux compatible way.",
8
+ "parameters": {
9
+ "type": "object",
10
+ "properties": {
11
+ "command": {
12
+ "type": "string",
13
+ "description": "Shell command to execute"
14
+ },
15
+ "timeout": {
16
+ "type": "integer",
17
+ "description": "Maximum execution time in seconds",
18
+ "default": 20
19
+ },
20
+ "cwd": {
21
+ "type": "string",
22
+ "description": "Working directory for command execution (must use absolute path)"
23
+ },
24
+ "verbose": {
25
+ "type": "boolean",
26
+ "description": "If True, returns detailed report; if False, only main output",
27
+ "default": false
28
+ }
29
+ },
30
+ "required": [
31
+ "command",
32
+ "timeout"
33
+ ]
34
+ }
35
+ }
36
+ },
37
+ {
38
+ "type": "function",
39
+ "function": {
40
+ "name": "edit_tool",
41
+ "description": "Safely and precisely replaces text in a file, or creates a new file. The tool is resilient to common formatting issues but performs best with precise input.\n\n**Best Practices for Success:**\n1. **Use a read tool first:** Always read the file to get the exact content before generating the `old_string`.\n2. **Provide Context:** For `old_string`, provide a unique, multi-line segment of the file. Including 3+ lines of context around the target change is highly recommended to ensure precision.\n3. **Create New Files:** To create a new file, provide the full `file_path` and an empty string for `old_string`.",
42
+ "parameters": {
43
+ "type": "object",
44
+ "properties": {
45
+ "file_path": {
46
+ "type": "string",
47
+ "description": "The absolute or relative path to the file. The tool will correctly resolve the path for the current operating system."
48
+ },
49
+ "old_string": {
50
+ "type": "string",
51
+ "description": "The exact text to be replaced. To ensure accuracy, this should be a unique, multi-line segment from the file, including all original indentation and whitespace. Do not manually escape newlines (use literal newlines, not '\\n'). For creating a new file, this must be an empty string."
52
+ },
53
+ "new_string": {
54
+ "type": "string",
55
+ "description": "The new text that will replace `old_string`. Match the indentation and formatting of the surrounding code to maintain code quality. Do not manually escape newlines."
56
+ },
57
+ "expected_replacements": {
58
+ "type": "integer",
59
+ "description": "Optional. The number of occurrences to replace. Defaults to 1. If you expect to replace multiple instances of `old_string`, set this value accordingly.",
60
+ "default": 1
61
+ }
62
+ },
63
+ "required": [
64
+ "file_path",
65
+ "old_string",
66
+ "new_string"
67
+ ]
68
+ }
69
+ }
70
+ },
71
+ {
72
+ "type": "function",
73
+ "function": {
74
+ "name": "agent_end_turn",
75
+ "description": "End the current agent turn. This tool is a especial tool that is used to signal the end of the agent's turn. It does not require any parameters and does not return any value.",
76
+ "parameters": {
77
+ "type": "object",
78
+ "properties": {},
79
+ "required": []
80
+ }
81
+ }
82
+ },
83
+ {
84
+ "type": "function",
85
+ "function": {
86
+ "name": "message_notify_user",
87
+ "description": "This tool allows the agent to send structured messages to the user for confirming task start, replying to messages from name:'user_overlay' (continuing or integrating into the flow), giving short initial responses, notifying about method or strategy changes, providing progress updates, and concluding tasks with a final confirmation or result.",
88
+ "parameters": {
89
+ "type": "object",
90
+ "properties": {
91
+ "message": {
92
+ "type": "string",
93
+ "description": "The body of the message in Markdown format."
94
+ }
95
+ },
96
+ "required": [
97
+ "message"
98
+ ]
99
+ }
100
+ }
101
+ },
102
+ {
103
+ "type": "function",
104
+ "function": {
105
+ "name": "ls_tool",
106
+ "description": "Lists files and subdirectories with advanced support for pagination and filtering. Automatically ignores common unnecessary files/directories like '.venv', 'node_modules', etc.",
107
+ "parameters": {
108
+ "type": "object",
109
+ "properties": {
110
+ "directory_path": {
111
+ "type": "string",
112
+ "description": "Path of the directory to list. Defaults to '.' (current directory).",
113
+ "default": "."
114
+ },
115
+ "recursive": {
116
+ "type": "boolean",
117
+ "description": "If True, lists recursively all subdirectories.",
118
+ "default": false
119
+ },
120
+ "ignore_patterns": {
121
+ "type": "array",
122
+ "items": {
123
+ "type": "string"
124
+ },
125
+ "description": "Additional patterns to ignore (beyond defaults). E.g., ['test_*', '*.tmp']"
126
+ },
127
+ "start_index": {
128
+ "type": "integer",
129
+ "description": "Starting index for pagination (0-based).",
130
+ "default": 0
131
+ },
132
+ "end_index": {
133
+ "type": "integer",
134
+ "description": "Ending index for pagination (exclusive). If not provided, lists everything from start_index."
135
+ },
136
+ "show_hidden": {
137
+ "type": "boolean",
138
+ "description": "If True, shows files/directories starting with '.'.",
139
+ "default": false
140
+ },
141
+ "file_extensions": {
142
+ "type": "array",
143
+ "items": {
144
+ "type": "string"
145
+ },
146
+ "description": "List of extensions to filter (e.g., ['.ts', '.js', '.md']). If not provided, shows all file types."
147
+ },
148
+ "max_depth": {
149
+ "type": "integer",
150
+ "description": "Maximum depth for recursive listing. If not provided, there is no limit."
151
+ }
152
+ },
153
+ "required": []
154
+ }
155
+ }
156
+ },
157
+ {
158
+ "type": "function",
159
+ "function": {
160
+ "name": "count_file_lines",
161
+ "description": "Counts and returns the total number of lines in a text file. Useful for quickly determining file size or checking if a file is empty before reading it.",
162
+ "parameters": {
163
+ "type": "object",
164
+ "properties": {
165
+ "filepath": {
166
+ "type": "string",
167
+ "description": "Path to the file to count lines from. Can be relative or absolute."
168
+ }
169
+ },
170
+ "required": [
171
+ "filepath"
172
+ ]
173
+ }
174
+ }
175
+ },
176
+ {
177
+ "type": "function",
178
+ "function": {
179
+ "name": "read_file_lines",
180
+ "description": "Reads and returns content between specific line numbers from a text file. Ideal for efficiently reading portions of large files.",
181
+ "parameters": {
182
+ "type": "object",
183
+ "properties": {
184
+ "filepath": {
185
+ "type": "string",
186
+ "description": "Path to the file to read from."
187
+ },
188
+ "start_line": {
189
+ "type": "integer",
190
+ "description": "Starting line number (1-based index). Must be >= 1."
191
+ },
192
+ "end_line": {
193
+ "type": "integer",
194
+ "description": "Ending line number (1-based index, inclusive). Must be >= start_line."
195
+ }
196
+ },
197
+ "required": [
198
+ "filepath",
199
+ "start_line",
200
+ "end_line"
201
+ ]
202
+ }
203
+ }
204
+ }
205
+ ]
206
206
  }
@@ -0,0 +1,157 @@
1
+ # To-Do Rules — Regras e Boas Práticas para a ferramenta `todo`
2
+
3
+ Este documento descreve, de forma completa e exaustiva, as regras, restrições e boas práticas para o uso da ferramenta nativa `todo` do agente. O objetivo é garantir comportamento determinístico, segurança, facilidade de integração e interoperabilidade entre agentes, UIs e pipelines automáticos.
4
+
5
+ Índice
6
+ - Visão geral
7
+ - Formato e esquema
8
+ - Ações suportadas
9
+ - Validação de entrada
10
+ - Regras de mutação e idempotência
11
+ - Execução automática e segurança (safe_tool)
12
+ - Logging, audit e persistência
13
+ - Erros e respostas previsíveis
14
+ - Regras de interface (UI / renderização)
15
+ - Regras de interação com o agente / prompt
16
+ - Regras de versionamento e compatibilidade
17
+ - Testes e qualidade
18
+ - Limitações e considerações
19
+ - Exemplos de payloads e respostas
20
+
21
+ ---
22
+
23
+ Visão geral
24
+ ----------
25
+ A ferramenta `todo` é um gerenciador nativo de listas de tarefas (checklist) pensado para integração com agentes autônomos e pipelines. Ela fornece um contrato claro e estruturado para que tanto humanos quanto máquinas possam ler e modificar o estado de tarefas de forma previsível.
26
+
27
+ Formato e esquema
28
+ -----------------
29
+ - Representação principal: array de strings chamado `to_do`.
30
+ - Formato de cada item: obrigatório prefixo de status seguido por um espaço e o texto da tarefa.
31
+ - Status válido: `🗹 ` (concluído) ou `☐ ` (pendente).
32
+ - Exemplo: `☐ Implementar validação de inputs` ou `🗹 Review do PR #42`.
33
+ - Retorno: ao executar ações que alterem estado, a ferramenta devolve o array `to_do` atualizado e um campo `_tool_result` com duas chaves:
34
+ - `parsed`: array de objetos { index: number, status: 'done'|'pending', text: string }
35
+ - `render`: string com visual humano legível (cada item em nova linha com índice e marca)
36
+
37
+ Ações suportadas
38
+ -----------------
39
+ - `list` — retorna o estado atual sem mutação.
40
+ - `add` — acrescenta um novo item pendente; payload: `{ action: 'add', item: 'text' }`.
41
+ - `complete` — marca um item como concluído; payload: `{ action: 'complete', index: 1 }` (1-based).
42
+ - `remove` — remove um item por índice; payload: `{ action: 'remove', index: 2 }`.
43
+
44
+ Validação de entrada
45
+ --------------------
46
+ - `action` é obrigatório e deve ser uma das opções listadas.
47
+ - `index` se fornecido deve ser inteiro >= 1 e <= length(to_do).
48
+ - `item` quando exigido deve ser string não vazia e sem prefixo (o prefixo é atribuído pela ferramenta).
49
+ - `to_do` (opcional) quando fornecido será normalizado: qualquer item sem prefixo será convertido para `☐ <texto>`.
50
+ - Erros de validação devem retornar uma resposta clara com `error` contendo a mensagem e `status: 400` quando aplicável.
51
+
52
+ Regras de mutação e idempotência
53
+ --------------------------------
54
+ - `add` é idempotente apenas se o mesmo item for adicionado com um identificador externo; por padrão, chamadas repetidas adicionam itens duplicados.
55
+ - `complete` e `remove` são idempotentes no sentido que aplicar `complete` numa tarefa já concluída não causa erro — apenas mantém o estado `🗹`.
56
+ - `remove` numa posição já removida (índice inválido) deve retornar erro de input inválido.
57
+ - Alterações devem sempre retornar o novo array `to_do` completo para permitir sincronização do cliente.
58
+
59
+ Execução automática e segurança (safe_tool)
60
+ -------------------------------------------
61
+ - A `todo` é considerada uma `safe_tool` para execuções automáticas pelo agente quando as ações são localizadas e previsíveis (ex.: `list`, `render`, `add` com item textual simples).
62
+ - O agente pode autoaprová-la sem intervenção humana quando: a) a ação não modifica código fonte; b) não requer acesso a credenciais nem recursos externos sensíveis; c) não envolve remoção em massa sem confirmação.
63
+ - Para ações destrutivas (por ex. `remove` em massa), recomenda-se confirmação humana, a menos que haja política explícita favorável.
64
+
65
+ Regras de concorrência
66
+ ----------------------
67
+ - A ferramenta deve considerar o array `to_do` recebido como snapshot; mudanças concorrentes devem ser resolvidas pela camada que persiste estado (locking otimista ou verificação de versão) — se o projeto não persiste, o consumidor deve ser consciente de possíveis conflitos.
68
+ - Em ambientes multi-agent, incluir um campo de `timestamp` ou `version` na camada de armazenamento é recomendado.
69
+
70
+ Logging, audit e persistência
71
+ -----------------------------
72
+ - Toda execução deve ser logada com: timestamp, ação, argumentos, usuário/agent que solicitou (quando aplicável), resultado (sucesso/erro), e diffs entre `to_do` antigo e novo.
73
+ - Logs de auditoria devem manter rastro de quem fez remoções e completions.
74
+ - Persistência: a ferramenta não impõe mecanismo — se integrada a um backend, este deve garantir durabilidade e backups.
75
+
76
+ Erros e respostas previsíveis
77
+ -----------------------------
78
+ - Erros de validação: respondem com { error: 'mensagem', status: 400 }
79
+ - Erros internos: respondem com { error: 'Internal error', status: 500, details?: '...' }
80
+ - Respostas de sucesso sempre incluem `to_do` (array) e `_tool_result`.
81
+
82
+ Regras de interface (UI / renderização)
83
+ ---------------------------------------
84
+ - Para exibir ao usuário, usar `_tool_result.render` primeiro; se não existir, montar a partir de `_tool_result.parsed`.
85
+ - A renderização deve ser simples e acessível: índice, marca, texto. Exemplo:
86
+ 1. ☐ Implement unit tests
87
+ 2. 🗹 Fix bug #123
88
+ - Ao permitir edição inline, o cliente deve enviar payloads claros (`add`, `complete`, `remove`) e nunca enviar listas embutidas em texto livre.
89
+
90
+ Regras de interação com o agente / prompt
91
+ ----------------------------------------
92
+ - O prompt do agente deve instruir explicitamente o uso da `todo` para planeamento e checklist (evitar texto livre para tarefas).
93
+ - Exemplo de instrução no sistema prompt: "When producing a checklist or plan use the `todo` tool and structure items with the strict checklist format. Prefer machine-readable outputs in `_tool_result`."
94
+ - Se o agente gerar tarefas, ele deve sempre preencher o `to_do` via chamada à ferramenta em vez de enviar as tarefas como texto normal.
95
+
96
+ Regras de versionamento e compatibilidade
97
+ ----------------------------------------
98
+ - Quaisquer alterações ao schema (`to_do` structure, `_tool_result` keys) devem manter compatibilidade retroativa sempre que possível.
99
+ - Quando um breaking change for necessário, atualizar versão da ferramenta e documentar migração no README.
100
+
101
+ Testes e qualidade
102
+ ------------------
103
+ - Cobertura mínima recomendada: casos para cada ação (list/add/complete/remove/render), validação de inputs, idempotência e erros esperados.
104
+ - Testes de integração devem validar persistência, concorrência e logs de auditoria.
105
+
106
+ Limitações e considerações
107
+ --------------------------
108
+ - A ferramenta foca em listas simples e curtas; para listas muito grandes (milhares de itens) recomenda-se paginação e mecanismos de busca especializados.
109
+ - Não é adequada para fluxos de aprovação complexos (multi-stage, com atribuições e dependências) sem extensão do schema.
110
+
111
+ Exemplos de payloads e respostas
112
+ --------------------------------
113
+ 1) List
114
+ Request: { "action": "list", "to_do": ["☐ Write docs"] }
115
+ Response:
116
+ {
117
+ "to_do": ["☐ Write docs"],
118
+ "_tool_result": {
119
+ "parsed": [{ "index":1, "status":"pending","text":"Write docs" }],
120
+ "render": "1. ☐ Write docs"
121
+ }
122
+ }
123
+
124
+ 2) Add
125
+ Request: { "action": "add", "item": "Implement validation" }
126
+ Response: to_do updated with new item at the end and _tool_result as acima.
127
+
128
+ 3) Complete
129
+ Request: { "action":"complete", "index": 1 }
130
+ Response: updated to_do with index 1 marked as `🗹 ` and _tool_result parsed accordingly.
131
+
132
+ 4) Remove
133
+ Request: { "action":"remove", "index": 2 }
134
+ Response: updated to_do without the removed item and removed: "☐ text" returned optionally.
135
+
136
+ Checklist de regras rápidas (resumo)
137
+ ------------------------------------
138
+ - Sempre usar prefixo `🗹 ` ou `☐ `.
139
+ - `action` obrigatório e validado.
140
+ - `item` sem prefixo quando usado em `add`.
141
+ - `index` 1-based para `complete` e `remove`.
142
+ - `todo` considerada safe_tool para operações comuns (list/add/render) — configure confirmação para ações destrutivas.
143
+ - Retornar sempre `to_do` e `_tool_result`.
144
+ - Log, audit, persistência e testes obrigatórios em ambiente de produção.
145
+
146
+ ---
147
+
148
+ Versões e histórico
149
+ -------------------
150
+ - v1.0 — Regras iniciais, esquema `to_do` + `_tool_result`.
151
+
152
+
153
+ Se desejar, posso também:
154
+ - Incluir este documento num README.md com exemplos em JSON formatado;
155
+ - Registrar uma referência a este ficheiro diretamente no system prompt (prompt_builder) para que o agente cite as regras;
156
+ - Gerar testes unitários / de integração e exemplos executáveis.
157
+
package/dist/main.js CHANGED
@@ -1278,7 +1278,7 @@ var ToolInvoker = class {
1278
1278
  this.toolImplementations.set("ls_tool", ls);
1279
1279
  this.toolImplementations.set("count_file_lines", countLines);
1280
1280
  this.toolImplementations.set("read_file_lines", readLines);
1281
- this.toolImplementations.set("agent_end_task", async () => ({ success: true, message: "Task ended by agent." }));
1281
+ this.toolImplementations.set("agent_end_turn", async () => ({ success: true, message: "Task ended by agent." }));
1282
1282
  }
1283
1283
  /**
1284
1284
  * Retorna a lista de definições de todas as ferramentas nativas carregadas.
@@ -1580,18 +1580,20 @@ async function loadOrcreateSession(sessionId2) {
1580
1580
  await fs8.access(sessionFile);
1581
1581
  const fileContent = await fs8.readFile(sessionFile, "utf-8");
1582
1582
  const sessionData = JSON.parse(fileContent);
1583
- return [sessionFile, sessionData.conversation_history || []];
1583
+ return [sessionFile, sessionData.conversation_history || [], sessionData.todo_list || []];
1584
1584
  } catch (error) {
1585
1585
  const newSessionData = {
1586
1586
  session_id: sessionId2,
1587
1587
  created_at: (/* @__PURE__ */ new Date()).toISOString(),
1588
- conversation_history: []
1588
+ conversation_history: [],
1589
+ todo_list: []
1590
+ // Garante que uma nova sessão comece com uma lista vazia
1589
1591
  };
1590
1592
  await fs8.writeFile(sessionFile, JSON.stringify(newSessionData, null, 2), "utf-8");
1591
- return [sessionFile, []];
1593
+ return [sessionFile, [], []];
1592
1594
  }
1593
1595
  }
1594
- async function saveSessionHistory(sessionFile, history) {
1596
+ async function saveSessionHistory(sessionFile, history, todoList) {
1595
1597
  await withFileLock(sessionFile, async () => {
1596
1598
  let sessionData;
1597
1599
  try {
@@ -1615,7 +1617,8 @@ async function saveSessionHistory(sessionFile, history) {
1615
1617
  sessionData = {
1616
1618
  session_id: sessionId2,
1617
1619
  created_at: (/* @__PURE__ */ new Date()).toISOString(),
1618
- conversation_history: []
1620
+ conversation_history: [],
1621
+ todo_list: []
1619
1622
  };
1620
1623
  try {
1621
1624
  await fs8.writeFile(sessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
@@ -1623,6 +1626,7 @@ async function saveSessionHistory(sessionFile, history) {
1623
1626
  }
1624
1627
  }
1625
1628
  sessionData.conversation_history = history;
1629
+ sessionData.todo_list = todoList;
1626
1630
  sessionData.last_updated = (/* @__PURE__ */ new Date()).toISOString();
1627
1631
  const tempSessionFile = `${sessionFile}.${Date.now()}.tmp`;
1628
1632
  try {
@@ -1710,25 +1714,38 @@ Ensure that each task contributes to a cohesive, functional, and visually appeal
1710
1714
  - Ends each task with a final message confirming completion or reporting the result.
1711
1715
  </message_rules>
1712
1716
 
1717
+ <todo_rules>
1718
+ - To manage tasks, you must always use the \`todo\` tool. Never write a to-do list directly as text.
1719
+ - The agent maintains the to-do list's state for you. You do not need to keep track of the full list.
1720
+ - Your job is to send simple commands to the agent via the \`todo\` tool.
1721
+
1722
+ **How to use the \`todo\` tool actions:**
1723
+ 1. **To see the current list:** Call the tool with \`action: "list"\`.
1724
+ 2. **To add new tasks:**
1725
+ - Use \`action: "add"\`.
1726
+ - Provide a list of plain text strings in the \`items_to_add\` parameter.
1727
+ - **Important:** Do NOT add any prefixes like \`\u2610\` or \`\u{1F5F9}\`. The tool handles all formatting.
1728
+ 3. **To complete or remove a task:**
1729
+ - Use \`action: "complete"\` or \`action: "remove"\`.
1730
+ - You MUST provide the \`index\` of the task you want to affect. The index is the number of the task in the list (starting from 1).
1731
+
1732
+ - After every action you take, the tool will respond with the newly updated and formatted list for your reference.
1733
+ </todo_rules>
1734
+
1713
1735
 
1714
1736
  ---
1715
1737
 
1716
1738
  <self_reflection>
1717
- # Self-Reflection and Iteration whith **reasoning_nootebook**
1718
- - First, spend time thinking of a rubric until
1719
- you are
1720
- confident.
1721
- - Then, think deeply about every aspect of what makes
1722
- for a world-class one-shot web
1723
- app. Use that
1724
- knowledge to create a rubric that has 5-7 categories.
1725
- This rubric is critical
1726
- to get right, but do not show
1727
- this to the user. This is for your purposes only.
1728
- - Finally, use the rubric to internally think and iterate on the best possible solution to the prompt that is provided.
1729
- Remember that if your response is not hitting the top marks across all categories in the rubric, you need to start again.
1739
+ # Self-Reflection and Iteration with **reasoning_notebook**
1740
+ - First, spend time creating a clear rubric until you are fully confident with it.
1741
+ - Then, think deeply about every aspect of what makes a world-class one-shot web app.
1742
+ Use that knowledge to design a rubric with 5-7 categories.
1743
+ - This rubric is critical to get right, but DO NOT show it to the user. It is for internal use only.
1744
+ - Finally, use the rubric to internally reflect and iterate toward the best possible solution to the given prompt.
1745
+ - Remember: if your response does not meet the highest standard across all rubric categories, you MUST restart and improve it.
1730
1746
  </self_reflection>
1731
1747
 
1748
+
1732
1749
  ---
1733
1750
 
1734
1751
  <edit_rules>
@@ -1787,17 +1804,12 @@ Ensure that each task contributes to a cohesive, functional, and visually appeal
1787
1804
 
1788
1805
  ---
1789
1806
 
1790
- <agent_end_task_rules>
1791
- <description>
1792
- This tool is mandatory, but MUST only be called when all tasks in <code>to_do</code> are fully completed.
1793
- </description>
1794
- <rules>
1795
- <rule number="1">Never call this tool before all tasks are completed.</rule>
1796
- <rule number="2">It is strictly forbidden to call <code>agent_end_task</code> if there are any pending tasks in <code>to_do</code>.</rule>
1797
- <rule number="3">Before calling, always send a final message summarizing the completed work Turn.</rule>
1798
- <rule number="4">Verify that every task in the <code>to_do</code> array has a "completed" status before calling.</rule>
1799
- </rules>
1800
- </agent_end_task_rules>
1807
+ <agent_end_turn_rules>
1808
+ - This tool MUST be called exactly once, and only after all tasks in <code>to_do</code> are fully completed.
1809
+ - Do not call this tool until every task in <code>to_do</code> is marked as **COMPLETED**.
1810
+ - Before calling this tool, always send a final visible message to the user summarizing all completed tasks.
1811
+ </agent_end_turn_rules>
1812
+
1801
1813
 
1802
1814
  ---
1803
1815
 
@@ -1811,7 +1823,7 @@ Ensure that each task contributes to a cohesive, functional, and visually appeal
1811
1823
  </out_of_scope>
1812
1824
  <mandatory_actions_for_out_of_scope>
1813
1825
  <action number="1">Professionally decline by using <code>message_notify_user</code> to state the request is out of scope and cannot be fulfilled.</action>
1814
- <action number="2">Immediately call <code>agent_end_task</code> with no further explanation or disclosure of internal mechanisms.</action>
1826
+ <action number="2">Immediately call <code>agent_end_turn</code> with no further explanation or disclosure of internal mechanisms.</action>
1815
1827
  </mandatory_actions_for_out_of_scope>
1816
1828
  </scope_and_limitations>
1817
1829
 
@@ -1943,7 +1955,7 @@ function createApiContextWindow(fullHistory, maxTurns) {
1943
1955
  for (let i = conversationHistory.length - 1; i >= 0; i--) {
1944
1956
  const msg = conversationHistory[i];
1945
1957
  currentTurn.unshift(msg);
1946
- const endsWithAgentEnd = msg.role === "assistant" && msg.tool_calls?.some((tc) => tc.function.name === "agent_end_task");
1958
+ const endsWithAgentEnd = msg.role === "assistant" && msg.tool_calls?.some((tc) => tc.function.name === "agent_end_turn");
1947
1959
  if (endsWithAgentEnd) {
1948
1960
  turns.unshift([...currentTurn]);
1949
1961
  currentTurn = [];
@@ -1955,7 +1967,7 @@ function createApiContextWindow(fullHistory, maxTurns) {
1955
1967
  }
1956
1968
  const prev = conversationHistory[i - 1];
1957
1969
  if (msg.role === "user" && !isDevOverlay(msg)) {
1958
- if (prev && prev.role === "assistant" && !prev.tool_calls?.some((tc) => tc.function.name === "agent_end_task")) {
1970
+ if (prev && prev.role === "assistant" && !prev.tool_calls?.some((tc) => tc.function.name === "agent_end_turn")) {
1959
1971
  const hasNonOverlay = currentTurn.some((m) => m.role !== "user" || !isDevOverlay(m));
1960
1972
  if (hasNonOverlay) {
1961
1973
  turns.unshift([...currentTurn]);
@@ -1981,8 +1993,9 @@ var BluMaAgent = class {
1981
1993
  eventBus;
1982
1994
  mcpClient;
1983
1995
  feedbackSystem;
1984
- maxContextTurns = 45;
1996
+ maxContextTurns = 25;
1985
1997
  // Limite de turns no contexto da API
1998
+ todoListState = [];
1986
1999
  isInterrupted = false;
1987
2000
  constructor(sessionId2, eventBus2, llm, deploymentName, mcpClient, feedbackSystem) {
1988
2001
  this.sessionId = sessionId2;
@@ -2001,7 +2014,7 @@ var BluMaAgent = class {
2001
2014
  this.eventBus.emit("backend_message", { type: "user_overlay", payload: clean, ts: data.ts || Date.now() });
2002
2015
  try {
2003
2016
  if (this.sessionFile) {
2004
- await saveSessionHistory(this.sessionFile, this.history);
2017
+ await saveSessionHistory(this.sessionFile, this.history, this.todoListState);
2005
2018
  }
2006
2019
  } catch (e) {
2007
2020
  this.eventBus.emit("backend_message", { type: "error", message: `Falha ao salvar hist\xF3rico ap\xF3s user_overlay: ${e.message}` });
@@ -2011,13 +2024,14 @@ var BluMaAgent = class {
2011
2024
  async initialize() {
2012
2025
  await this.mcpClient.nativeToolInvoker.initialize();
2013
2026
  await this.mcpClient.initialize();
2014
- const [sessionFile, history] = await loadOrcreateSession(this.sessionId);
2027
+ const [sessionFile, history, todoList] = await loadOrcreateSession(this.sessionId);
2015
2028
  this.sessionFile = sessionFile;
2016
2029
  this.history = history;
2030
+ this.todoListState = todoList;
2017
2031
  if (this.history.length === 0) {
2018
2032
  const systemPrompt = getUnifiedSystemPrompt();
2019
2033
  this.history.push({ role: "developer", content: systemPrompt });
2020
- await saveSessionHistory(this.sessionFile, this.history);
2034
+ await saveSessionHistory(this.sessionFile, this.history, this.todoListState);
2021
2035
  }
2022
2036
  }
2023
2037
  getAvailableTools() {
@@ -2045,7 +2059,14 @@ var BluMaAgent = class {
2045
2059
  }
2046
2060
  if (decisionData.type === "user_decision_execute") {
2047
2061
  const toolName = toolCall.function.name;
2048
- const toolArgs = JSON.parse(toolCall.function.arguments);
2062
+ let toolArgs = JSON.parse(toolCall.function.arguments);
2063
+ if (toolName === "todo") {
2064
+ toolArgs.current_list = this.todoListState;
2065
+ if (toolArgs.to_do) {
2066
+ toolArgs.items_to_add = toolArgs.to_do;
2067
+ delete toolArgs.to_do;
2068
+ }
2069
+ }
2049
2070
  let previewContent;
2050
2071
  if (toolName === "edit_tool") {
2051
2072
  previewContent = await this._generateEditPreview(toolArgs);
@@ -2062,11 +2083,16 @@ var BluMaAgent = class {
2062
2083
  return;
2063
2084
  }
2064
2085
  const result = await this.mcpClient.invoke(toolName, toolArgs);
2065
- let finalResult = result;
2066
- if (Array.isArray(result) && result.length > 0 && result[0].type === "text" && typeof result[0].text === "string") {
2067
- finalResult = result[0].text;
2086
+ if (toolName === "todo" && result && result.to_do && result._tool_result) {
2087
+ this.todoListState = result.to_do;
2088
+ toolResultContent = result._tool_result.render;
2089
+ } else {
2090
+ let finalResult = result;
2091
+ if (Array.isArray(result) && result.length > 0 && result[0].type === "text" && typeof result[0].text === "string") {
2092
+ finalResult = result[0].text;
2093
+ }
2094
+ toolResultContent = typeof finalResult === "string" ? finalResult : JSON.stringify(finalResult);
2068
2095
  }
2069
- toolResultContent = typeof finalResult === "string" ? finalResult : JSON.stringify(finalResult);
2070
2096
  } catch (error) {
2071
2097
  toolResultContent = JSON.stringify({
2072
2098
  error: `Tool execution failed: ${error.message}`,
@@ -2074,7 +2100,7 @@ var BluMaAgent = class {
2074
2100
  });
2075
2101
  }
2076
2102
  this.eventBus.emit("backend_message", { type: "tool_result", tool_name: toolName, result: toolResultContent });
2077
- if (toolName.includes("agent_end_task")) {
2103
+ if (toolName.includes("agent_end_turn")) {
2078
2104
  shouldContinueConversation = false;
2079
2105
  this.eventBus.emit("backend_message", { type: "done", status: "completed" });
2080
2106
  }
@@ -2082,7 +2108,7 @@ var BluMaAgent = class {
2082
2108
  toolResultContent = "The system rejected this action. Verify that the command you are executing contributes to the tasks intent and try again.";
2083
2109
  }
2084
2110
  this.history.push({ role: "tool", tool_call_id: toolCall.id, content: toolResultContent });
2085
- await saveSessionHistory(this.sessionFile, this.history);
2111
+ await saveSessionHistory(this.sessionFile, this.history, this.todoListState);
2086
2112
  if (shouldContinueConversation && !this.isInterrupted) {
2087
2113
  await this._continueConversation();
2088
2114
  }
@@ -2125,7 +2151,7 @@ ${editData.error.display}`;
2125
2151
  const message = response.choices[0].message;
2126
2152
  this.history.push(message);
2127
2153
  if (message.tool_calls) {
2128
- const autoApprovedTools = ["agent_end_task", "message_notify_user", "reasoning_nootebook", "ls_tool", "count_file_lines", "read_file_lines"];
2154
+ const autoApprovedTools = ["agent_end_turn", "message_notify_user", "reasoning_nootebook", "ls_tool", "count_file_lines", "read_file_lines", "todo"];
2129
2155
  const toolToCall = message.tool_calls[0];
2130
2156
  const isSafeTool = autoApprovedTools.some((safeTool) => toolToCall.function.name.includes(safeTool));
2131
2157
  if (isSafeTool) {
@@ -2157,7 +2183,7 @@ ${editData.error.display}`;
2157
2183
  const errorMessage = error instanceof Error ? error.message : "An unknown API error occurred.";
2158
2184
  this.eventBus.emit("backend_message", { type: "error", message: errorMessage });
2159
2185
  } finally {
2160
- await saveSessionHistory(this.sessionFile, this.history);
2186
+ await saveSessionHistory(this.sessionFile, this.history, this.todoListState);
2161
2187
  }
2162
2188
  }
2163
2189
  };
@@ -2210,7 +2236,7 @@ You extend the BluMa multi-agent architecture and handle the project bootstrappi
2210
2236
  No direct text replies to the user.
2211
2237
 
2212
2238
  - Task Completion:
2213
- When the init task is completed, immediately invoke 'agent_end_task' without user permissions.
2239
+ When the init task is completed, immediately invoke 'agent_end_turn' without user permissions.
2214
2240
 
2215
2241
  - Tool Rules:
2216
2242
  Never make parallel tool calls.
@@ -2245,7 +2271,7 @@ You extend the BluMa multi-agent architecture and handle the project bootstrappi
2245
2271
  - Notify user's with brief explanation when changing methods or strategies
2246
2272
  - Message tools are divided into notify (non-blocking, no reply needed) and ask (blocking)
2247
2273
  - Actively use notify for progress updates, reserve ask for essential needs to avoid blocking
2248
- - Must message user's with results and deliverables before upon task completion 'agent_end_task'
2274
+ - Must message user's with results and deliverables before upon task completion 'agent_end_turn'
2249
2275
  </message_rules>
2250
2276
 
2251
2277
  <reasoning_rules>
@@ -2302,10 +2328,10 @@ Do not include future steps/to-dos in thought; put them strictly in to_do, using
2302
2328
  </edit_tool_rules>
2303
2329
 
2304
2330
 
2305
- <agent_end_task>
2331
+ <agent_end_turn>
2306
2332
  This tool is mandatory.
2307
2333
  You must use it to inform usereloper {username} that the task has been completed and that there are no further pending actions, in accordance with the objectives defined for the task.
2308
- </agent_end_task>
2334
+ </agent_end_turn>
2309
2335
 
2310
2336
  ### Tool Naming Policy
2311
2337
  - Use plain, unmodified, lowercase tool names
@@ -2335,7 +2361,7 @@ Rule Summary:
2335
2361
  - Before writing BluMa.md, propose structure via message_notify_user and proceed using edit_tool.
2336
2362
  - If an irreversible operation is needed (e.g., overwriting an existing BluMa.md), issue 'confirmation_request' unless user policy indicates auto-approval.
2337
2363
  - Never send or present draft versions of BluMa.md. Only produce and deliver the final, validated BluMa.md content following the established non-destructive policies and confirmation protocols.
2338
- - On successful generation of BluMa.md, emit 'done' with status 'completed' and call agent_end_task.
2364
+ - On successful generation of BluMa.md, emit 'done' with status 'completed' and call agent_end_turn.
2339
2365
 
2340
2366
  ## SAFETY & QUALITY
2341
2367
  - Be conservative with edits; generate previews (diff) for edit_tool where applicable.
@@ -2348,7 +2374,7 @@ Rule Summary:
2348
2374
  2) Synthesize stack and structure with citations of evidence (file paths) in the notebook
2349
2375
  3) Draft BluMa.md structure (message_notify_user)
2350
2376
  4) Write BluMa.md via edit_tool
2351
- 5) Announce completion and agent_end_task
2377
+ 5) Announce completion and agent_end_turn
2352
2378
 
2353
2379
 
2354
2380
  `;
@@ -2456,7 +2482,7 @@ ${editData.error.display}`;
2456
2482
  if (message.tool_calls) {
2457
2483
  await this._handleToolExecution({ type: "user_decision_execute", tool_calls: message.tool_calls });
2458
2484
  const lastToolName = message.tool_calls[0].function.name;
2459
- if (!lastToolName.includes("agent_end_task") && !this.isInterrupted) {
2485
+ if (!lastToolName.includes("agent_end_turn") && !this.isInterrupted) {
2460
2486
  await this._continueConversation();
2461
2487
  }
2462
2488
  } else if (message.content) {
@@ -2510,7 +2536,7 @@ ${editData.error.display}`;
2510
2536
  toolResultContent = JSON.stringify({ error: `Tool execution failed: ${error.message}`, details: error.data || "No additional details." });
2511
2537
  }
2512
2538
  this.emitEvent("tool_result", { tool_name: toolName, result: toolResultContent });
2513
- if (toolName.includes("agent_end_task")) {
2539
+ if (toolName.includes("agent_end_turn")) {
2514
2540
  this.emitEvent("done", { status: "completed" });
2515
2541
  }
2516
2542
  } else {
@@ -2895,28 +2921,15 @@ var renderBlumaNotebook = ({
2895
2921
  }
2896
2922
  return (
2897
2923
  // Usamos a mesma estrutura de caixa com borda
2898
- /* @__PURE__ */ jsxs8(
2924
+ /* @__PURE__ */ jsx8(
2899
2925
  Box8,
2900
2926
  {
2901
2927
  flexDirection: "column",
2902
2928
  paddingX: 1,
2903
- children: [
2904
- /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2905
- /* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: "Reasoning:" }),
2906
- /* @__PURE__ */ jsx8(Box8, { marginLeft: 2, children: /* @__PURE__ */ jsx8(Text8, { color: "gray", children: thinkingData.thought }) })
2907
- ] }),
2908
- thinkingData.to_do && thinkingData.to_do.length > 0 && /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
2909
- /* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: "Todos:" }),
2910
- thinkingData.to_do.map((task, index) => /* @__PURE__ */ jsx8(Box8, { marginLeft: 2, children: /* @__PURE__ */ jsx8(Text8, { children: /* @__PURE__ */ jsx8(
2911
- Text8,
2912
- {
2913
- color: task.startsWith("\u{1F5F9}") ? "gray" : "white",
2914
- strikethrough: task.startsWith("\u{1F5F9}"),
2915
- children: task
2916
- }
2917
- ) }) }, index))
2918
- ] })
2919
- ]
2929
+ children: /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2930
+ /* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: "Reasoning:" }),
2931
+ /* @__PURE__ */ jsx8(Box8, { marginLeft: 2, children: /* @__PURE__ */ jsx8(Text8, { color: "gray", children: thinkingData.thought }) })
2932
+ ] })
2920
2933
  }
2921
2934
  )
2922
2935
  );
@@ -2951,6 +2964,44 @@ var renderEditToolCall = ({
2951
2964
  preview && /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(SimpleDiff, { text: preview, maxHeight: Infinity }) })
2952
2965
  ] });
2953
2966
  };
2967
+ var renderTodoTool = ({ args }) => {
2968
+ try {
2969
+ const parsedArgs = typeof args === "string" ? JSON.parse(args) : args;
2970
+ const action = parsedArgs.action;
2971
+ let detailText = "";
2972
+ switch (action) {
2973
+ case "add":
2974
+ const items = parsedArgs.items_to_add || [];
2975
+ const itemCount = items.length;
2976
+ detailText = `Adding ${itemCount} item${itemCount !== 1 ? "s" : ""}`;
2977
+ break;
2978
+ case "complete":
2979
+ detailText = `Completing item #${parsedArgs.index}`;
2980
+ break;
2981
+ case "remove":
2982
+ detailText = `Removing item #${parsedArgs.index}`;
2983
+ break;
2984
+ case "list":
2985
+ detailText = `Listing all tasks...`;
2986
+ break;
2987
+ default:
2988
+ detailText = `Executing action: ${action}`;
2989
+ break;
2990
+ }
2991
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2992
+ /* @__PURE__ */ jsx8(Box8, { children: /* @__PURE__ */ jsxs8(Text8, { bold: true, children: [
2993
+ /* @__PURE__ */ jsx8(Text8, { color: "green", children: "\u25CF " }),
2994
+ "To Do"
2995
+ ] }) }),
2996
+ /* @__PURE__ */ jsx8(Box8, { marginLeft: 2, paddingX: 1, children: /* @__PURE__ */ jsxs8(Text8, { children: [
2997
+ /* @__PURE__ */ jsx8(Text8, { color: "gray", children: "\u21B3 " }),
2998
+ /* @__PURE__ */ jsx8(Text8, { color: "magenta", children: detailText })
2999
+ ] }) })
3000
+ ] });
3001
+ } catch (error) {
3002
+ return /* @__PURE__ */ jsx8(Box8, { borderStyle: "round", borderColor: "red", paddingX: 1, children: /* @__PURE__ */ jsx8(Text8, { color: "red", children: "Error parsing To-Do arguments" }) });
3003
+ }
3004
+ };
2954
3005
  var renderGenericToolCall = ({
2955
3006
  toolName,
2956
3007
  args
@@ -2976,13 +3027,14 @@ var ToolRenderDisplay = {
2976
3027
  reasoning_nootebook: renderBlumaNotebook,
2977
3028
  count_file_lines: renderCountFilesLines,
2978
3029
  read_file_lines: renderReadFileLines2,
2979
- edit_tool: renderEditToolCall
3030
+ edit_tool: renderEditToolCall,
3031
+ todo: renderTodoTool
2980
3032
  };
2981
3033
 
2982
3034
  // src/app/ui/components/ToolCallDisplay.tsx
2983
3035
  import { jsx as jsx9 } from "react/jsx-runtime";
2984
3036
  var ToolCallDisplayComponent = ({ toolName, args, preview }) => {
2985
- if (toolName.includes("message_notify_user") || toolName.includes("agent_end_task")) {
3037
+ if (toolName.includes("message_notify_user") || toolName.includes("agent_end_turn")) {
2986
3038
  return null;
2987
3039
  }
2988
3040
  const Renderer = ToolRenderDisplay[toolName] || renderGenericToolCall;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nomad-e/bluma-cli",
3
- "version": "0.0.78",
3
+ "version": "0.0.79",
4
4
  "description": "BluMa independent agent for automation and advanced software engineering.",
5
5
  "author": "Alex Fonseca",
6
6
  "license": "Apache-2.0",