boxsafe 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.directory +2 -0
- package/.env.example +3 -0
- package/AUDIT_LANG.md +45 -0
- package/BOXSAFE_VERSION_NOTES.md +14 -0
- package/README.md +4 -0
- package/TODO.md +130 -0
- package/adapters/index.ts +27 -0
- package/adapters/primary/cli-adapter.ts +56 -0
- package/adapters/secondary/filesystem/node-filesystem.ts +307 -0
- package/adapters/secondary/system/configuration.ts +147 -0
- package/ai/caller.ts +42 -0
- package/ai/label.ts +33 -0
- package/ai/modelConfig.ts +236 -0
- package/ai/provider.ts +111 -0
- package/boxsafe.config.json +68 -0
- package/core/auth/dasktop/cred/CRED.md +112 -0
- package/core/auth/dasktop/cred/credLinux.ts +82 -0
- package/core/auth/dasktop/cred/credWin.ts +2 -0
- package/core/config/defaults/boxsafeDefaults.ts +67 -0
- package/core/config/defaults/index.ts +1 -0
- package/core/config/loadConfig.ts +133 -0
- package/core/loop/about.md +13 -0
- package/core/loop/boxConfig.ts +20 -0
- package/core/loop/buildExecCommand.ts +76 -0
- package/core/loop/cmd/execode.ts +121 -0
- package/core/loop/cmd/test.js +3 -0
- package/core/loop/execLoop.ts +341 -0
- package/core/loop/git/VERSIONING.md +17 -0
- package/core/loop/git/commands.ts +11 -0
- package/core/loop/git/gitClient.ts +78 -0
- package/core/loop/git/index.ts +99 -0
- package/core/loop/git/runVersionControlRunner.ts +33 -0
- package/core/loop/initNavigator.ts +44 -0
- package/core/loop/initTasksManager.ts +35 -0
- package/core/loop/runValidation.ts +25 -0
- package/core/loop/tasks/AGENT-TASKS.md +36 -0
- package/core/loop/tasks/index.ts +96 -0
- package/core/loop/toolCalls.ts +168 -0
- package/core/loop/toolDispatcher.ts +146 -0
- package/core/loop/traceLogger.ts +106 -0
- package/core/loop/types.ts +26 -0
- package/core/loop/versionControlAdapter.ts +36 -0
- package/core/loop/waterfall.ts +404 -0
- package/core/loop/writeArtifactAtomically.ts +13 -0
- package/core/navigate/NAVIGATE.md +186 -0
- package/core/navigate/about.md +128 -0
- package/core/navigate/examples.ts +367 -0
- package/core/navigate/handler.ts +148 -0
- package/core/navigate/index.ts +32 -0
- package/core/navigate/navigate.test.ts +372 -0
- package/core/navigate/navigator.ts +437 -0
- package/core/navigate/types.ts +132 -0
- package/core/navigate/utils.ts +146 -0
- package/core/paths/paths.ts +33 -0
- package/core/ports/index.ts +271 -0
- package/core/segments/CONVENTIONS.md +30 -0
- package/core/segments/loop/index.ts +18 -0
- package/core/segments/map.ts +56 -0
- package/core/segments/navigate/index.ts +20 -0
- package/core/segments/versionControl/index.ts +18 -0
- package/core/util/logger.ts +128 -0
- package/docs/AGENT-TASKS.md +36 -0
- package/docs/ARQUITETURA_CORRECAO.md +121 -0
- package/docs/CONVENTIONS.md +30 -0
- package/docs/CRED.md +112 -0
- package/docs/L_RAG.md +567 -0
- package/docs/NAVIGATE.md +186 -0
- package/docs/PRIMARY_ACTORS.md +78 -0
- package/docs/SECONDARY_ACTORS.md +174 -0
- package/docs/VERSIONING.md +17 -0
- package/docs/boxsafe.config.md +472 -0
- package/eslint.config.mts +15 -0
- package/main.ts +53 -0
- package/memo/generated/codelog.md +13 -0
- package/memo/state/tasks/state.json +6 -0
- package/memo/state/tasks/tasks/task_001.md +2 -0
- package/memo/states-logs/logs.txt +7 -0
- package/memo/states-logs/trace-mljvrxvi-9g0k4q.jsonl +11 -0
- package/memo/states-logs/trace-mljvvc9j-pe9ekj.jsonl +11 -0
- package/memo/states-logs/trace-mljvvm1c-wbnqzp.jsonl +11 -0
- package/memo/states-logs/trace-mljxecwn-9xh3nw.jsonl +11 -0
- package/memo/states-logs/trace-mljxqkfm-ipijik.jsonl +11 -0
- package/memo/states-logs/trace-mljxwtrw-3fanky.jsonl +11 -0
- package/memo/states-logs/trace-mljxzen3-m8iinh.jsonl +11 -0
- package/memo/states-logs/trace-mljyucef-td6odn.jsonl +11 -0
- package/memo/states-logs/trace-mljyuprw-b1a6f4.jsonl +11 -0
- package/memo/states-logs/trace-mljyvefl-b6yoce.jsonl +11 -0
- package/memo/states-logs/trace-mljyxjo4-n7ibj2.jsonl +13 -0
- package/memo/states-logs/trace-mljziez5-8drqtn.jsonl +13 -0
- package/memo/states-logs/trace-mljziulp-dtd03z.jsonl +13 -0
- package/memo/states-logs/trace-mljzjwrq-1p2krb.jsonl +13 -0
- package/memo/states-logs/trace-mljzl0i7-b1cqa6.jsonl +13 -0
- package/memo/states-logs/trace-mljzmlk6-7kdyls.jsonl +13 -0
- package/memo/states-logs/trace-mlk0oj25-xa3dcu.jsonl +13 -0
- package/memo/states-logs/trace-mlk1x59q-713huj.jsonl +14 -0
- package/memo/states-logs/trace-mlk22dz8-7fd6hq.jsonl +14 -0
- package/memo/states-logs/trace-mlk241uy-wmx907.jsonl +14 -0
- package/memo/states-logs/trace-mlk2bf5r-yoh1vg.jsonl +15 -0
- package/package.json +44 -0
- package/pnpm-workspace.yaml +4 -0
- package/prompt_improvement_example.md +55 -0
- package/remove.txt +1 -0
- package/tests/adapters.test.ts +128 -0
- package/tests/extractCode.test.ts +26 -0
- package/tests/integration.test.ts +83 -0
- package/tests/loadConfig.test.ts +25 -0
- package/tests/navigatorBoundary.test.ts +17 -0
- package/tests/ports.test.ts +84 -0
- package/tests/runAllTests.ts +49 -0
- package/tests/toolCalls.test.ts +149 -0
- package/tests/waterfall.test.ts +52 -0
- package/tsconfig.json +32 -0
- package/tsup.config.ts +17 -0
- package/types.d.ts +96 -0
- package/util/ANSI.ts +29 -0
- package/util/extractCode.ts +217 -0
- package/util/extractToolCalls.ts +80 -0
- package/util/logger.ts +125 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
|
|
3
|
+
const CWD = process.cwd();
|
|
4
|
+
|
|
5
|
+
export const MEMO_DIR = path.join(CWD, 'memo');
|
|
6
|
+
export const STATES_LOGS_DIR = path.join(MEMO_DIR, 'states-logs');
|
|
7
|
+
export const STATES_LOG_FILE = path.join(STATES_LOGS_DIR, 'logs.txt');
|
|
8
|
+
|
|
9
|
+
export const TASKS_STATE_DIR = path.join(MEMO_DIR, 'state', 'tasks');
|
|
10
|
+
export const TASKS_TASKS_DIR = path.join(TASKS_STATE_DIR, 'tasks');
|
|
11
|
+
export const TASKS_STATE_FILE = path.join(TASKS_STATE_DIR, 'state.json');
|
|
12
|
+
|
|
13
|
+
function resolveFromCwd(p: string): string {
|
|
14
|
+
return path.isAbsolute(p) ? p : path.join(CWD, p);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function getGeneratedMarkdownPath(): string {
|
|
18
|
+
const fromEnv = process.env.BOXSAFE_MARKDOWN_PATH?.trim();
|
|
19
|
+
if (fromEnv) return resolveFromCwd(fromEnv);
|
|
20
|
+
return path.join(MEMO_DIR, 'generated', 'codelog.md');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function getArtifactOutputPath(): string {
|
|
24
|
+
const fromEnv = process.env.AGENT_OUTPUT_PATH?.trim();
|
|
25
|
+
if (fromEnv) return resolveFromCwd(fromEnv);
|
|
26
|
+
return path.join(CWD, 'out.ts');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// path to code generated by the model
|
|
30
|
+
export const pathToCode = getGeneratedMarkdownPath();
|
|
31
|
+
|
|
32
|
+
// Backwards-compatible alias
|
|
33
|
+
export const logs = STATES_LOG_FILE;
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview
|
|
3
|
+
* Ports da arquitetura hexagonal - Interfaces que definem contratos entre o core e o mundo externo
|
|
4
|
+
*
|
|
5
|
+
* Baseado na estrutura existente do módulo sgmnt, adaptada para arquitetura hexagonal formal.
|
|
6
|
+
*
|
|
7
|
+
* @module core/ports/index
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { BoxSafeConfig, CommandRun } from '../../types';
|
|
11
|
+
import type { LService, LModel } from '@ai/label';
|
|
12
|
+
|
|
13
|
+
// Re-export BoxSafeConfig for convenience
|
|
14
|
+
export type { BoxSafeConfig, CommandRun } from '../../types';
|
|
15
|
+
|
|
16
|
+
// Re-export navigate types for convenience
|
|
17
|
+
export type {
|
|
18
|
+
FileSystemEntry,
|
|
19
|
+
NavigatorConfig,
|
|
20
|
+
NavigatorResult,
|
|
21
|
+
OperationResult,
|
|
22
|
+
DirectoryListing,
|
|
23
|
+
FileReadResult,
|
|
24
|
+
FileWriteResult,
|
|
25
|
+
DirectoryCreateResult,
|
|
26
|
+
DeleteResult,
|
|
27
|
+
MetadataResult,
|
|
28
|
+
OperationError
|
|
29
|
+
} from '@core/navigate/types';
|
|
30
|
+
|
|
31
|
+
// ============================================================================
|
|
32
|
+
// PRIMARY PORTS - Interfaces for primary actors (CLI, Web, IDE, etc.)
|
|
33
|
+
// ============================================================================
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Main port for system execution - entry point for primary actors
|
|
37
|
+
* Based on existing segment system
|
|
38
|
+
*/
|
|
39
|
+
export interface ISystemExecutionPort {
|
|
40
|
+
/**
|
|
41
|
+
* Executes a specific system segment
|
|
42
|
+
* @param segmentName Name of the segment to be executed
|
|
43
|
+
* @param args Arguments for the segment
|
|
44
|
+
* @returns Execution result
|
|
45
|
+
*/
|
|
46
|
+
executeSegment(segmentName: string, args?: any): Promise<any>;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Lists all available segments
|
|
50
|
+
* @returns Map of available segments
|
|
51
|
+
*/
|
|
52
|
+
listSegments(): Record<string, SegmentInfo>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Information about a segment
|
|
57
|
+
*/
|
|
58
|
+
export interface SegmentInfo {
|
|
59
|
+
description: string;
|
|
60
|
+
implemented: boolean;
|
|
61
|
+
config?: any;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Port for system configuration
|
|
66
|
+
* Based on existing loadConfig
|
|
67
|
+
*/
|
|
68
|
+
export interface ISystemConfigurationPort {
|
|
69
|
+
/**
|
|
70
|
+
* Loads system configurations
|
|
71
|
+
* @param configPath Optional path to configuration file
|
|
72
|
+
* @returns Loaded configurations
|
|
73
|
+
*/
|
|
74
|
+
loadConfiguration(configPath?: string): Promise<ConfigurationResult>;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Validates system configurations
|
|
78
|
+
* @param config Configurations to be validated
|
|
79
|
+
* @returns Validation result
|
|
80
|
+
*/
|
|
81
|
+
validateConfiguration(config: BoxSafeConfig): Promise<ValidationResult>;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Configuration loading result
|
|
86
|
+
*/
|
|
87
|
+
export interface ConfigurationResult {
|
|
88
|
+
config: BoxSafeConfig;
|
|
89
|
+
source: { path: string; loaded: boolean };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Configuration validation result
|
|
94
|
+
*/
|
|
95
|
+
export interface ValidationResult {
|
|
96
|
+
valid: boolean;
|
|
97
|
+
errors: string[];
|
|
98
|
+
warnings: string[];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ============================================================================
|
|
102
|
+
// SECONDARY PORTS - Interfaces for secondary actors (FileSystem, AI, Git, etc.)
|
|
103
|
+
// ============================================================================
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Port for file system navigation
|
|
107
|
+
* Based on existing navigate module
|
|
108
|
+
*/
|
|
109
|
+
export interface IFileSystemPort {
|
|
110
|
+
/**
|
|
111
|
+
* Lists directory contents
|
|
112
|
+
listDirectory(path: string): Promise<any>;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Reads file contents
|
|
116
|
+
*/
|
|
117
|
+
readFile(path: string): Promise<any>;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Writes content to a file
|
|
121
|
+
*/
|
|
122
|
+
writeFile(path: string, content: string, options?: any): Promise<any>;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Creates a directory
|
|
126
|
+
*/
|
|
127
|
+
createDirectory(path: string, options?: any): Promise<any>;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Removes file or directory
|
|
131
|
+
*/
|
|
132
|
+
delete(path: string, options?: any): Promise<any>;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Gets metadata of a file/directory
|
|
136
|
+
*/
|
|
137
|
+
getMetadata(path: string): Promise<any>;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Port for AI model interaction
|
|
142
|
+
* Based on existing model configuration
|
|
143
|
+
*/
|
|
144
|
+
export interface IAIModelPort {
|
|
145
|
+
/**
|
|
146
|
+
* Sends prompt to the model
|
|
147
|
+
*/
|
|
148
|
+
sendPrompt(prompt: string, options?: any): Promise<any>;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Configures model to be used
|
|
152
|
+
*/
|
|
153
|
+
configureModel(config: {
|
|
154
|
+
provider: LService;
|
|
155
|
+
name: LModel;
|
|
156
|
+
parameters?: Record<string, unknown>;
|
|
157
|
+
}): Promise<void>;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Port for version control (Git)
|
|
162
|
+
*/
|
|
163
|
+
export interface IVersionControlPort {
|
|
164
|
+
/**
|
|
165
|
+
* Executes Git command
|
|
166
|
+
*/
|
|
167
|
+
executeGitCommand(command: string, args?: string[]): Promise<any>;
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Verifica status do repositório
|
|
171
|
+
*/
|
|
172
|
+
getStatus(): Promise<any>;
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Cria commit
|
|
176
|
+
*/
|
|
177
|
+
commit(message: string, files?: string[]): Promise<any>;
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Push para remoto
|
|
181
|
+
*/
|
|
182
|
+
push(remote?: string, branch?: string): Promise<any>;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Port para execução de comandos
|
|
187
|
+
* Baseado na configuração commands existente
|
|
188
|
+
*/
|
|
189
|
+
export interface ICommandExecutionPort {
|
|
190
|
+
/**
|
|
191
|
+
* Executa comando do sistema
|
|
192
|
+
*/
|
|
193
|
+
executeCommand(command: CommandRun, options?: CommandOptions): Promise<CommandResult>;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Opções para execução de comando
|
|
198
|
+
*/
|
|
199
|
+
export interface CommandOptions {
|
|
200
|
+
timeout?: number;
|
|
201
|
+
cwd?: string;
|
|
202
|
+
env?: Record<string, string>;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Resultado da execução de comando
|
|
207
|
+
*/
|
|
208
|
+
export interface CommandResult {
|
|
209
|
+
success: boolean;
|
|
210
|
+
exitCode: number;
|
|
211
|
+
stdout: string;
|
|
212
|
+
stderr: string;
|
|
213
|
+
duration?: number;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// ============================================================================
|
|
217
|
+
// DOMAIN PORTS - Interfaces específicas do domínio BoxSafe
|
|
218
|
+
// ============================================================================
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Port para o loop principal do BoxSafe
|
|
222
|
+
* Baseado no módulo loop existente
|
|
223
|
+
*/
|
|
224
|
+
export interface IBoxSafeLoopPort {
|
|
225
|
+
/**
|
|
226
|
+
* Executa o loop iterativo principal
|
|
227
|
+
*/
|
|
228
|
+
executeLoop(options: LoopOptions): Promise<LoopResult>;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Opções para o loop principal
|
|
233
|
+
*/
|
|
234
|
+
export interface LoopOptions {
|
|
235
|
+
service: LService;
|
|
236
|
+
model: LModel;
|
|
237
|
+
initialPrompt: string;
|
|
238
|
+
cmd: CommandRun;
|
|
239
|
+
lang: string;
|
|
240
|
+
pathOutput: string;
|
|
241
|
+
workspace?: string;
|
|
242
|
+
maxIterations?: number;
|
|
243
|
+
limit?: number;
|
|
244
|
+
signal?: AbortSignal;
|
|
245
|
+
pathGeneratedMarkdown?: string;
|
|
246
|
+
logger?: any;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Resultado do loop principal
|
|
251
|
+
*/
|
|
252
|
+
export interface LoopResult {
|
|
253
|
+
ok: boolean;
|
|
254
|
+
iterations: number;
|
|
255
|
+
verdict?: unknown;
|
|
256
|
+
artifacts?: { outputFile?: string };
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// ============================================================================
|
|
260
|
+
// UTILITY TYPES
|
|
261
|
+
// ============================================================================
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Logger interface para uso em todos os ports
|
|
265
|
+
*/
|
|
266
|
+
export interface LoggerPort {
|
|
267
|
+
info: (...args: any[]) => void;
|
|
268
|
+
warn: (...args: any[]) => void;
|
|
269
|
+
error: (...args: any[]) => void;
|
|
270
|
+
debug?: (...args: any[]) => void;
|
|
271
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Segments (skills) conventions
|
|
2
|
+
|
|
3
|
+
## Folder layout
|
|
4
|
+
|
|
5
|
+
Each segment must live in its own folder:
|
|
6
|
+
|
|
7
|
+
- `core/sgmnt/<segment>/index.ts`
|
|
8
|
+
|
|
9
|
+
`index.ts` must export a factory function:
|
|
10
|
+
|
|
11
|
+
- `create<SegmentName>Segment(BSConfig)`
|
|
12
|
+
|
|
13
|
+
The factory returns an object with the same shape used by `core/sgmnt/map.ts`:
|
|
14
|
+
|
|
15
|
+
- `handler: (args?: any) => Promise<any>`
|
|
16
|
+
- `meta: { description: string; implemented: boolean; config?: any }`
|
|
17
|
+
|
|
18
|
+
## map.ts responsibilities
|
|
19
|
+
|
|
20
|
+
`core/sgmnt/map.ts` is the composer:
|
|
21
|
+
|
|
22
|
+
- loads config (`loadBoxSafeConfig`)
|
|
23
|
+
- instantiates each segment via its factory
|
|
24
|
+
- exposes `{ routes, runSegment, BSConfig }`
|
|
25
|
+
|
|
26
|
+
## Adding a new segment
|
|
27
|
+
|
|
28
|
+
1. Create folder `core/sgmnt/<segment>/`
|
|
29
|
+
2. Implement `index.ts` exporting `create<SegmentName>Segment`
|
|
30
|
+
3. Register it inside `core/sgmnt/map.ts` under `routes`.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { NormalizedBoxSafeConfig } from '@core/config/loadConfig';
|
|
2
|
+
|
|
3
|
+
export function createLoopSegment(BSConfig: NormalizedBoxSafeConfig) {
|
|
4
|
+
return {
|
|
5
|
+
handler: async (opts?: any) => {
|
|
6
|
+
const mod = await import('@core/loop/execLoop');
|
|
7
|
+
return mod.loop(opts);
|
|
8
|
+
},
|
|
9
|
+
meta: {
|
|
10
|
+
description: 'Iterative LLM -> code -> exec loop',
|
|
11
|
+
implemented: true,
|
|
12
|
+
config: {
|
|
13
|
+
defaultLang: 'ts',
|
|
14
|
+
pathOutput: process.env.AGENT_OUTPUT_PATH ?? BSConfig.paths?.artifactOutput ?? './out.ts',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Segmentation map initialization
|
|
3
|
+
*
|
|
4
|
+
* Encapsulates all route logic in a single function.
|
|
5
|
+
* No arguments required—all config comes from boxsafe.config.json and env.
|
|
6
|
+
*/
|
|
7
|
+
import { ANSI } from "../../util/ANSI";
|
|
8
|
+
import { loadBoxSafeConfig } from '@core/config/loadConfig';
|
|
9
|
+
import { createLoopSegment } from './loop';
|
|
10
|
+
import { createNavigateSegment } from './navigate';
|
|
11
|
+
import { createVersionControlSegment } from './versionControl';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Initialize segments map with all available routes.
|
|
15
|
+
* Loads config from boxsafe.config.json and env variables.
|
|
16
|
+
* Returns { routes, runSegment } for use in the application.
|
|
17
|
+
*/
|
|
18
|
+
export async function initSegments() {
|
|
19
|
+
const { config: BSConfig } = loadBoxSafeConfig();
|
|
20
|
+
const routes: Record<string, any> = {
|
|
21
|
+
loop: createLoopSegment(BSConfig),
|
|
22
|
+
navigate: createNavigateSegment(BSConfig),
|
|
23
|
+
sandbox: null, // TODO: create
|
|
24
|
+
model: {
|
|
25
|
+
primary: BSConfig.model?.primary ?? null,
|
|
26
|
+
fallback: BSConfig.model?.fallback ?? null,
|
|
27
|
+
endpoint: BSConfig.model?.endpoint ?? null,
|
|
28
|
+
},
|
|
29
|
+
commands: {
|
|
30
|
+
setup: BSConfig.commands?.setup ?? null,
|
|
31
|
+
run: BSConfig.commands?.run ?? null,
|
|
32
|
+
test: BSConfig.commands?.test ?? null,
|
|
33
|
+
},
|
|
34
|
+
interface: {
|
|
35
|
+
channel: BSConfig.interface?.channel ?? null,
|
|
36
|
+
prompt: BSConfig.interface?.prompt ?? null,
|
|
37
|
+
notifications: BSConfig.interface?.notifications ?? null,
|
|
38
|
+
},
|
|
39
|
+
teach: {
|
|
40
|
+
urls: BSConfig.teach?.urls ?? null,
|
|
41
|
+
files: BSConfig.teach?.files ?? null,
|
|
42
|
+
},
|
|
43
|
+
versionControl: createVersionControlSegment(BSConfig),
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
type RouteName = keyof typeof routes;
|
|
47
|
+
|
|
48
|
+
const runSegment = async (name: RouteName, args?: any) => {
|
|
49
|
+
const node = routes[name];
|
|
50
|
+
const handler = node?.handler ?? node?.run ?? null;
|
|
51
|
+
if (typeof handler === "function") return handler(args);
|
|
52
|
+
throw new Error(`Segment '${String(name)}' not implemented`);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return { routes, runSegment, BSConfig };
|
|
56
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { NormalizedBoxSafeConfig } from '@core/config/loadConfig';
|
|
2
|
+
|
|
3
|
+
export function createNavigateSegment(BSConfig: NormalizedBoxSafeConfig) {
|
|
4
|
+
return {
|
|
5
|
+
handler: async (params?: any) => {
|
|
6
|
+
const mod = await import('@core/navigate');
|
|
7
|
+
const workspace = BSConfig.project?.workspace ?? './';
|
|
8
|
+
const handler = mod.createNavigatorHandler(workspace);
|
|
9
|
+
return handler.execute(params);
|
|
10
|
+
},
|
|
11
|
+
meta: {
|
|
12
|
+
description: 'File system navigation with workspace boundary enforcement',
|
|
13
|
+
implemented: true,
|
|
14
|
+
config: {
|
|
15
|
+
workspace: BSConfig.project?.workspace ?? './',
|
|
16
|
+
maxFileSize: 10 * 1024 * 1024,
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { NormalizedBoxSafeConfig } from '@core/config/loadConfig';
|
|
2
|
+
|
|
3
|
+
export function createVersionControlSegment(BSConfig: NormalizedBoxSafeConfig) {
|
|
4
|
+
return {
|
|
5
|
+
handler: async (params?: any) => {
|
|
6
|
+
const mod = await import('@core/loop/git');
|
|
7
|
+
return mod.runVersionControl(params ?? {});
|
|
8
|
+
},
|
|
9
|
+
meta: {
|
|
10
|
+
description: 'Versioning helper: commit, notes and optional push to origin',
|
|
11
|
+
implemented: true,
|
|
12
|
+
config: {
|
|
13
|
+
autoPushDefault: BSConfig.project?.versionControl?.after ?? false,
|
|
14
|
+
createNotesDefault: BSConfig.project?.versionControl?.generateNotes ?? false,
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
export enum LogLevel {
|
|
2
|
+
DEBUG = 1,
|
|
3
|
+
INFO,
|
|
4
|
+
WARN,
|
|
5
|
+
ERROR,
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface LogEntry {
|
|
9
|
+
level: LogLevel;
|
|
10
|
+
message: string;
|
|
11
|
+
module: string;
|
|
12
|
+
timestamp: Date;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class Logger {
|
|
16
|
+
private static instance: Logger; // it the class itself
|
|
17
|
+
private currentLevel: LogLevel; // current log level
|
|
18
|
+
private moduleName: string; // module name
|
|
19
|
+
|
|
20
|
+
// ANSI color codes - simplificado para melhor legibilidade
|
|
21
|
+
private static readonly COLORS = {
|
|
22
|
+
RESET: '\x1b[0m',
|
|
23
|
+
DEBUG: '\x1b[36m', // Cyan
|
|
24
|
+
INFO: '\x1b[32m', // Green
|
|
25
|
+
WARN: '\x1b[33m', // Yellow
|
|
26
|
+
ERROR: '\x1b[31m', // Red
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
private static readonly LEVEL_NAMES = {
|
|
30
|
+
[LogLevel.DEBUG]: 'DEBUG',
|
|
31
|
+
[LogLevel.INFO]: 'INFO',
|
|
32
|
+
[LogLevel.WARN]: 'WARN',
|
|
33
|
+
[LogLevel.ERROR]: 'ERROR',
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
constructor(moduleName: string = 'Core', level: LogLevel = LogLevel.INFO) {
|
|
37
|
+
this.moduleName = moduleName;
|
|
38
|
+
this.currentLevel = level;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static getInstance(moduleName?: string, level?: LogLevel): Logger { // create singleton instance
|
|
42
|
+
if (!Logger.instance) {
|
|
43
|
+
Logger.instance = new Logger(moduleName || 'Core', level);
|
|
44
|
+
}
|
|
45
|
+
return Logger.instance;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
setLevel(level: LogLevel): void {
|
|
49
|
+
this.currentLevel = level;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
getLevel(): LogLevel {
|
|
53
|
+
return this.currentLevel;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private formatMessage(level: LogLevel, message: string): string {
|
|
57
|
+
const levelName = Logger.LEVEL_NAMES[level];
|
|
58
|
+
const color = Logger.COLORS[levelName as keyof typeof Logger.COLORS];
|
|
59
|
+
const reset = Logger.COLORS.RESET;
|
|
60
|
+
|
|
61
|
+
return `${color}[${levelName}(${this.moduleName})]${reset} ${message}\n\n`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private log(level: LogLevel, message: string): void {
|
|
65
|
+
if (level < this.currentLevel) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const formattedMessage = this.formatMessage(level, message);
|
|
70
|
+
process.stdout.write(formattedMessage);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
debug(message: string): void {
|
|
74
|
+
this.log(LogLevel.DEBUG, message);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
info(message: string): void {
|
|
78
|
+
this.log(LogLevel.INFO, message);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
warn(message: string): void {
|
|
82
|
+
this.log(LogLevel.WARN, message);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
error(message: string): void {
|
|
86
|
+
this.log(LogLevel.ERROR, message);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Static methods for quick access
|
|
90
|
+
static debug(message: string, moduleName?: string): void {
|
|
91
|
+
const logger = new Logger(moduleName || 'Core');
|
|
92
|
+
logger.debug(message);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
static info(message: string, moduleName?: string): void {
|
|
96
|
+
const logger = new Logger(moduleName || 'Core');
|
|
97
|
+
logger.info(message);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
static warn(message: string, moduleName?: string): void {
|
|
101
|
+
const logger = new Logger(moduleName || 'Core');
|
|
102
|
+
logger.warn(message);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
static error(message: string, moduleName?: string): void {
|
|
106
|
+
const logger = new Logger(moduleName || 'Core');
|
|
107
|
+
logger.error(message);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Method to create a logger instance for a specific module
|
|
111
|
+
static createModuleLogger(moduleName: string, level?: LogLevel): Logger {
|
|
112
|
+
return new Logger(moduleName, level);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Export a default logger instance
|
|
117
|
+
export const logger = Logger.getInstance();
|
|
118
|
+
/*
|
|
119
|
+
just one instance for anything
|
|
120
|
+
*/
|
|
121
|
+
|
|
122
|
+
// Export convenience functions
|
|
123
|
+
export const log = {
|
|
124
|
+
debug: (message: string, moduleName?: string) => Logger.debug(message, moduleName),
|
|
125
|
+
info: (message: string, moduleName?: string) => Logger.info(message, moduleName),
|
|
126
|
+
warn: (message: string, moduleName?: string) => Logger.warn(message, moduleName),
|
|
127
|
+
error: (message: string, moduleName?: string) => Logger.error(message, moduleName),
|
|
128
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
**Tasks module for BoxSafe — core/loop/tasks**
|
|
2
|
+
|
|
3
|
+
Overview
|
|
4
|
+
- The `TasksManager` provides a minimal, predictable mechanism to load a TODO file,
|
|
5
|
+
split it into small tasks, persist task artifacts and a lightweight runtime state
|
|
6
|
+
under `memo/state/tasks`.
|
|
7
|
+
|
|
8
|
+
Design goals
|
|
9
|
+
- Keep implementation tiny and synchronous-friendly (async IO only).
|
|
10
|
+
- Avoid complex formats: accept either `- item` lines or paragraphs separated by
|
|
11
|
+
blank lines in the TODO file.
|
|
12
|
+
- Persist each task as `memo/state/tasks/tasks/task_###.md` and keep state in
|
|
13
|
+
`memo/state/tasks/state.json` with `current` and `done[]` fields.
|
|
14
|
+
|
|
15
|
+
How it is used
|
|
16
|
+
- The `execLoop` integrates `TasksManager` when `boxsafe.config.json` contains
|
|
17
|
+
`project.todo` pointing to a TODO file. The loop will use the current task as
|
|
18
|
+
the agent prompt, and when the agent completes a task it marks it done and
|
|
19
|
+
moves to the next. Only when all tasks complete does the loop perform the
|
|
20
|
+
normal after-success flow (versioning, notes, etc.).
|
|
21
|
+
|
|
22
|
+
Files
|
|
23
|
+
- `index.ts` — exports `TasksManager` class.
|
|
24
|
+
|
|
25
|
+
Behavior summary
|
|
26
|
+
- `TasksManager.init()` creates `memo/state/tasks` and writes individual task
|
|
27
|
+
files and `state.json` when needed.
|
|
28
|
+
- `getCurrentTask()` returns the current task prompt or `null` when finished.
|
|
29
|
+
- `markCurrentDone()` marks current task as done and advances to the next.
|
|
30
|
+
- `isFinished()` signals completion of all tasks.
|
|
31
|
+
|
|
32
|
+
Notes
|
|
33
|
+
- The module intentionally keeps parsing and behavior simple to be robust and
|
|
34
|
+
easy to audit. If you want more advanced scheduling, priorities or parallel
|
|
35
|
+
execution, we can extend it, but this initial version focuses on correctness
|
|
36
|
+
and minimal surface area.
|