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.
Files changed (118) hide show
  1. package/.directory +2 -0
  2. package/.env.example +3 -0
  3. package/AUDIT_LANG.md +45 -0
  4. package/BOXSAFE_VERSION_NOTES.md +14 -0
  5. package/README.md +4 -0
  6. package/TODO.md +130 -0
  7. package/adapters/index.ts +27 -0
  8. package/adapters/primary/cli-adapter.ts +56 -0
  9. package/adapters/secondary/filesystem/node-filesystem.ts +307 -0
  10. package/adapters/secondary/system/configuration.ts +147 -0
  11. package/ai/caller.ts +42 -0
  12. package/ai/label.ts +33 -0
  13. package/ai/modelConfig.ts +236 -0
  14. package/ai/provider.ts +111 -0
  15. package/boxsafe.config.json +68 -0
  16. package/core/auth/dasktop/cred/CRED.md +112 -0
  17. package/core/auth/dasktop/cred/credLinux.ts +82 -0
  18. package/core/auth/dasktop/cred/credWin.ts +2 -0
  19. package/core/config/defaults/boxsafeDefaults.ts +67 -0
  20. package/core/config/defaults/index.ts +1 -0
  21. package/core/config/loadConfig.ts +133 -0
  22. package/core/loop/about.md +13 -0
  23. package/core/loop/boxConfig.ts +20 -0
  24. package/core/loop/buildExecCommand.ts +76 -0
  25. package/core/loop/cmd/execode.ts +121 -0
  26. package/core/loop/cmd/test.js +3 -0
  27. package/core/loop/execLoop.ts +341 -0
  28. package/core/loop/git/VERSIONING.md +17 -0
  29. package/core/loop/git/commands.ts +11 -0
  30. package/core/loop/git/gitClient.ts +78 -0
  31. package/core/loop/git/index.ts +99 -0
  32. package/core/loop/git/runVersionControlRunner.ts +33 -0
  33. package/core/loop/initNavigator.ts +44 -0
  34. package/core/loop/initTasksManager.ts +35 -0
  35. package/core/loop/runValidation.ts +25 -0
  36. package/core/loop/tasks/AGENT-TASKS.md +36 -0
  37. package/core/loop/tasks/index.ts +96 -0
  38. package/core/loop/toolCalls.ts +168 -0
  39. package/core/loop/toolDispatcher.ts +146 -0
  40. package/core/loop/traceLogger.ts +106 -0
  41. package/core/loop/types.ts +26 -0
  42. package/core/loop/versionControlAdapter.ts +36 -0
  43. package/core/loop/waterfall.ts +404 -0
  44. package/core/loop/writeArtifactAtomically.ts +13 -0
  45. package/core/navigate/NAVIGATE.md +186 -0
  46. package/core/navigate/about.md +128 -0
  47. package/core/navigate/examples.ts +367 -0
  48. package/core/navigate/handler.ts +148 -0
  49. package/core/navigate/index.ts +32 -0
  50. package/core/navigate/navigate.test.ts +372 -0
  51. package/core/navigate/navigator.ts +437 -0
  52. package/core/navigate/types.ts +132 -0
  53. package/core/navigate/utils.ts +146 -0
  54. package/core/paths/paths.ts +33 -0
  55. package/core/ports/index.ts +271 -0
  56. package/core/segments/CONVENTIONS.md +30 -0
  57. package/core/segments/loop/index.ts +18 -0
  58. package/core/segments/map.ts +56 -0
  59. package/core/segments/navigate/index.ts +20 -0
  60. package/core/segments/versionControl/index.ts +18 -0
  61. package/core/util/logger.ts +128 -0
  62. package/docs/AGENT-TASKS.md +36 -0
  63. package/docs/ARQUITETURA_CORRECAO.md +121 -0
  64. package/docs/CONVENTIONS.md +30 -0
  65. package/docs/CRED.md +112 -0
  66. package/docs/L_RAG.md +567 -0
  67. package/docs/NAVIGATE.md +186 -0
  68. package/docs/PRIMARY_ACTORS.md +78 -0
  69. package/docs/SECONDARY_ACTORS.md +174 -0
  70. package/docs/VERSIONING.md +17 -0
  71. package/docs/boxsafe.config.md +472 -0
  72. package/eslint.config.mts +15 -0
  73. package/main.ts +53 -0
  74. package/memo/generated/codelog.md +13 -0
  75. package/memo/state/tasks/state.json +6 -0
  76. package/memo/state/tasks/tasks/task_001.md +2 -0
  77. package/memo/states-logs/logs.txt +7 -0
  78. package/memo/states-logs/trace-mljvrxvi-9g0k4q.jsonl +11 -0
  79. package/memo/states-logs/trace-mljvvc9j-pe9ekj.jsonl +11 -0
  80. package/memo/states-logs/trace-mljvvm1c-wbnqzp.jsonl +11 -0
  81. package/memo/states-logs/trace-mljxecwn-9xh3nw.jsonl +11 -0
  82. package/memo/states-logs/trace-mljxqkfm-ipijik.jsonl +11 -0
  83. package/memo/states-logs/trace-mljxwtrw-3fanky.jsonl +11 -0
  84. package/memo/states-logs/trace-mljxzen3-m8iinh.jsonl +11 -0
  85. package/memo/states-logs/trace-mljyucef-td6odn.jsonl +11 -0
  86. package/memo/states-logs/trace-mljyuprw-b1a6f4.jsonl +11 -0
  87. package/memo/states-logs/trace-mljyvefl-b6yoce.jsonl +11 -0
  88. package/memo/states-logs/trace-mljyxjo4-n7ibj2.jsonl +13 -0
  89. package/memo/states-logs/trace-mljziez5-8drqtn.jsonl +13 -0
  90. package/memo/states-logs/trace-mljziulp-dtd03z.jsonl +13 -0
  91. package/memo/states-logs/trace-mljzjwrq-1p2krb.jsonl +13 -0
  92. package/memo/states-logs/trace-mljzl0i7-b1cqa6.jsonl +13 -0
  93. package/memo/states-logs/trace-mljzmlk6-7kdyls.jsonl +13 -0
  94. package/memo/states-logs/trace-mlk0oj25-xa3dcu.jsonl +13 -0
  95. package/memo/states-logs/trace-mlk1x59q-713huj.jsonl +14 -0
  96. package/memo/states-logs/trace-mlk22dz8-7fd6hq.jsonl +14 -0
  97. package/memo/states-logs/trace-mlk241uy-wmx907.jsonl +14 -0
  98. package/memo/states-logs/trace-mlk2bf5r-yoh1vg.jsonl +15 -0
  99. package/package.json +44 -0
  100. package/pnpm-workspace.yaml +4 -0
  101. package/prompt_improvement_example.md +55 -0
  102. package/remove.txt +1 -0
  103. package/tests/adapters.test.ts +128 -0
  104. package/tests/extractCode.test.ts +26 -0
  105. package/tests/integration.test.ts +83 -0
  106. package/tests/loadConfig.test.ts +25 -0
  107. package/tests/navigatorBoundary.test.ts +17 -0
  108. package/tests/ports.test.ts +84 -0
  109. package/tests/runAllTests.ts +49 -0
  110. package/tests/toolCalls.test.ts +149 -0
  111. package/tests/waterfall.test.ts +52 -0
  112. package/tsconfig.json +32 -0
  113. package/tsup.config.ts +17 -0
  114. package/types.d.ts +96 -0
  115. package/util/ANSI.ts +29 -0
  116. package/util/extractCode.ts +217 -0
  117. package/util/extractToolCalls.ts +80 -0
  118. 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.