claude-mycelium 2.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/.claude/settings.local.json +14 -0
- package/README.md +304 -0
- package/dist/coordination/gradient-cache.d.ts +48 -0
- package/dist/coordination/gradient-cache.d.ts.map +1 -0
- package/dist/coordination/gradient-cache.js +145 -0
- package/dist/coordination/gradient-cache.js.map +1 -0
- package/dist/coordination/index.d.ts +10 -0
- package/dist/coordination/index.d.ts.map +1 -0
- package/dist/coordination/index.js +10 -0
- package/dist/coordination/index.js.map +1 -0
- package/dist/core/agent-executor.d.ts +31 -0
- package/dist/core/agent-executor.d.ts.map +1 -0
- package/dist/core/agent-executor.js +257 -0
- package/dist/core/agent-executor.js.map +1 -0
- package/dist/core/change-applier.d.ts +10 -0
- package/dist/core/change-applier.d.ts.map +1 -0
- package/dist/core/change-applier.js +32 -0
- package/dist/core/change-applier.js.map +1 -0
- package/dist/core/gradient.d.ts +60 -0
- package/dist/core/gradient.d.ts.map +1 -0
- package/dist/core/gradient.js +191 -0
- package/dist/core/gradient.js.map +1 -0
- package/dist/core/index.d.ts +24 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +24 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/mode-selector.d.ts +44 -0
- package/dist/core/mode-selector.d.ts.map +1 -0
- package/dist/core/mode-selector.js +208 -0
- package/dist/core/mode-selector.js.map +1 -0
- package/dist/core/signals/centrality.d.ts +44 -0
- package/dist/core/signals/centrality.d.ts.map +1 -0
- package/dist/core/signals/centrality.js +264 -0
- package/dist/core/signals/centrality.js.map +1 -0
- package/dist/core/signals/churn.d.ts +41 -0
- package/dist/core/signals/churn.d.ts.map +1 -0
- package/dist/core/signals/churn.js +188 -0
- package/dist/core/signals/churn.js.map +1 -0
- package/dist/core/signals/complexity.d.ts +29 -0
- package/dist/core/signals/complexity.d.ts.map +1 -0
- package/dist/core/signals/complexity.js +169 -0
- package/dist/core/signals/complexity.js.map +1 -0
- package/dist/core/signals/debt.d.ts +27 -0
- package/dist/core/signals/debt.d.ts.map +1 -0
- package/dist/core/signals/debt.js +80 -0
- package/dist/core/signals/debt.js.map +1 -0
- package/dist/core/signals/errors.d.ts +32 -0
- package/dist/core/signals/errors.d.ts.map +1 -0
- package/dist/core/signals/errors.js +73 -0
- package/dist/core/signals/errors.js.map +1 -0
- package/dist/core/signals/index.d.ts +19 -0
- package/dist/core/signals/index.d.ts.map +1 -0
- package/dist/core/signals/index.js +19 -0
- package/dist/core/signals/index.js.map +1 -0
- package/dist/cost/cost-tracker.d.ts +90 -0
- package/dist/cost/cost-tracker.d.ts.map +1 -0
- package/dist/cost/cost-tracker.js +305 -0
- package/dist/cost/cost-tracker.js.map +1 -0
- package/dist/cost/index.d.ts +56 -0
- package/dist/cost/index.d.ts.map +1 -0
- package/dist/cost/index.js +111 -0
- package/dist/cost/index.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/anthropic-client.d.ts +52 -0
- package/dist/llm/anthropic-client.d.ts.map +1 -0
- package/dist/llm/anthropic-client.js +310 -0
- package/dist/llm/anthropic-client.js.map +1 -0
- package/dist/llm/index.d.ts +27 -0
- package/dist/llm/index.d.ts.map +1 -0
- package/dist/llm/index.js +34 -0
- package/dist/llm/index.js.map +1 -0
- package/dist/prompts/complexity-reducer.d.ts +7 -0
- package/dist/prompts/complexity-reducer.d.ts.map +1 -0
- package/dist/prompts/complexity-reducer.js +55 -0
- package/dist/prompts/complexity-reducer.js.map +1 -0
- package/dist/prompts/debt-payer.d.ts +7 -0
- package/dist/prompts/debt-payer.d.ts.map +1 -0
- package/dist/prompts/debt-payer.js +55 -0
- package/dist/prompts/debt-payer.js.map +1 -0
- package/dist/prompts/error-reducer.d.ts +7 -0
- package/dist/prompts/error-reducer.d.ts.map +1 -0
- package/dist/prompts/error-reducer.js +54 -0
- package/dist/prompts/error-reducer.js.map +1 -0
- package/dist/prompts/index.d.ts +22 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +112 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/stabilizer.d.ts +7 -0
- package/dist/prompts/stabilizer.d.ts.map +1 -0
- package/dist/prompts/stabilizer.js +55 -0
- package/dist/prompts/stabilizer.js.map +1 -0
- package/dist/prompts/types.d.ts +14 -0
- package/dist/prompts/types.d.ts.map +1 -0
- package/dist/prompts/types.js +5 -0
- package/dist/prompts/types.js.map +1 -0
- package/dist/trace/index.d.ts +51 -0
- package/dist/trace/index.d.ts.map +1 -0
- package/dist/trace/index.js +60 -0
- package/dist/trace/index.js.map +1 -0
- package/dist/trace/trace-event.d.ts +72 -0
- package/dist/trace/trace-event.d.ts.map +1 -0
- package/dist/trace/trace-event.js +244 -0
- package/dist/trace/trace-event.js.map +1 -0
- package/dist/types/index.d.ts +206 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/ci-provider.d.ts +43 -0
- package/dist/utils/ci-provider.d.ts.map +1 -0
- package/dist/utils/ci-provider.js +130 -0
- package/dist/utils/ci-provider.js.map +1 -0
- package/dist/utils/config.d.ts +31 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +85 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/error-provider.d.ts +51 -0
- package/dist/utils/error-provider.d.ts.map +1 -0
- package/dist/utils/error-provider.js +123 -0
- package/dist/utils/error-provider.js.map +1 -0
- package/dist/utils/file-utils.d.ts +18 -0
- package/dist/utils/file-utils.d.ts.map +1 -0
- package/dist/utils/file-utils.js +95 -0
- package/dist/utils/file-utils.js.map +1 -0
- package/dist/utils/index.d.ts +10 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +10 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +36 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +74 -0
- package/dist/utils/logger.js.map +1 -0
- package/docs/IMPLEMENTATION-STATUS.md +199 -0
- package/docs/PHASE-0-COMPLETE.md +252 -0
- package/docs/PHASE-1-COMPLETE.md +204 -0
- package/docs/PHASE-2-COMPLETE.md +233 -0
- package/docs/PHASE2_COMPLETION_CHECKLIST.md +290 -0
- package/docs/PHASE2_INTEGRATION_SUMMARY.md +255 -0
- package/docs/PHASE2_QUICK_REFERENCE.md +365 -0
- package/docs/PHASE2_TEST_RESULTS.md +282 -0
- package/docs/ROADMAP.md +746 -0
- package/docs/SNAPSHOT.md +376 -0
- package/docs/adrs/ADR-001-signal-computation.md +76 -0
- package/docs/adrs/ADR-002-inhibitor-signals.md +108 -0
- package/docs/adrs/ADR-003-llm-integration.md +156 -0
- package/docs/adrs/ADR-004-process-architecture.md +175 -0
- package/docs/adrs/ADR-005-testing-strategy.md +243 -0
- package/docs/pitch.md +94 -0
- package/docs/specs/fourth-spec.md +1973 -0
- package/docs/specs/initial-spec.md +2096 -0
- package/docs/specs/second-spec.md +2690 -0
- package/package.json +50 -0
- package/src/coordination/gradient-cache.ts +185 -0
- package/src/coordination/index.ts +10 -0
- package/src/core/agent-executor.ts +327 -0
- package/src/core/change-applier.ts +338 -0
- package/src/core/gradient.ts +258 -0
- package/src/core/index.ts +24 -0
- package/src/core/mode-selector.ts +243 -0
- package/src/core/signals/centrality.ts +328 -0
- package/src/core/signals/churn.ts +239 -0
- package/src/core/signals/complexity.ts +206 -0
- package/src/core/signals/debt.ts +111 -0
- package/src/core/signals/errors.ts +93 -0
- package/src/core/signals/index.ts +19 -0
- package/src/cost/cost-tracker.ts +410 -0
- package/src/cost/index.ts +143 -0
- package/src/index.ts +43 -0
- package/src/llm/anthropic-client.ts +415 -0
- package/src/llm/index.ts +43 -0
- package/src/prompts/complexity-reducer.ts +59 -0
- package/src/prompts/debt-payer.ts +59 -0
- package/src/prompts/error-reducer.ts +58 -0
- package/src/prompts/index.ts +128 -0
- package/src/prompts/stabilizer.ts +59 -0
- package/src/prompts/types.ts +15 -0
- package/src/trace/README.md +178 -0
- package/src/trace/index.ts +88 -0
- package/src/trace/trace-event.ts +324 -0
- package/src/types/index.ts +271 -0
- package/src/utils/ci-provider.ts +145 -0
- package/src/utils/config.ts +95 -0
- package/src/utils/error-provider.ts +138 -0
- package/src/utils/file-utils.ts +111 -0
- package/src/utils/index.ts +10 -0
- package/src/utils/logger.ts +94 -0
- package/test-8d713cc8-f4b7-403d-8153-57573172b94c.ts +3 -0
- package/tests/coordination/gradient-cache.test.ts +270 -0
- package/tests/core/agent-executor.test.ts +217 -0
- package/tests/core/change-applier.test.ts +336 -0
- package/tests/core/gradient.test.ts +263 -0
- package/tests/core/mode-selector.test.ts +239 -0
- package/tests/core/signals/centrality.test.ts +512 -0
- package/tests/core/signals/churn.test.ts +355 -0
- package/tests/core/signals/complexity.test.ts +284 -0
- package/tests/core/signals/debt.test.ts +437 -0
- package/tests/core/signals/errors.test.ts +350 -0
- package/tests/cost/cost-tracker.test.ts +475 -0
- package/tests/integration/phase2.test.ts +405 -0
- package/tests/llm/anthropic-client.test.ts +437 -0
- package/tests/prompts/prompts.test.ts +266 -0
- package/tests/trace/trace-event.test.ts +666 -0
- package/tests/utils/file-utils.test.ts +148 -0
- package/tsconfig.json +24 -0
- package/vitest.config.ts +28 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { exec } from 'child_process';
|
|
2
|
+
import { promisify } from 'util';
|
|
3
|
+
import type { CIProvider, ChangeSet } from '../types/index.js';
|
|
4
|
+
import { loadConfig } from './config.js';
|
|
5
|
+
import { logInfo, logError } from './logger.js';
|
|
6
|
+
|
|
7
|
+
const execAsync = promisify(exec);
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* CI provider that runs tests and linters
|
|
11
|
+
* Per spec §16 (second-spec.md)
|
|
12
|
+
*
|
|
13
|
+
* Default command: "npm test && npm run lint"
|
|
14
|
+
* Configurable via .agent-meta/config.json
|
|
15
|
+
*/
|
|
16
|
+
export class NpmCIProvider implements CIProvider {
|
|
17
|
+
private ciCommand: string;
|
|
18
|
+
|
|
19
|
+
constructor(ciCommand?: string) {
|
|
20
|
+
if (ciCommand) {
|
|
21
|
+
this.ciCommand = ciCommand;
|
|
22
|
+
} else {
|
|
23
|
+
// Load from config
|
|
24
|
+
const config = loadConfig();
|
|
25
|
+
this.ciCommand = config.ci_command;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Run CI checks (tests + lint)
|
|
31
|
+
* Returns whether all checks passed and output
|
|
32
|
+
*/
|
|
33
|
+
async run(changes: ChangeSet): Promise<{ passed: boolean; output: string }> {
|
|
34
|
+
logInfo('Running CI checks', {
|
|
35
|
+
command: this.ciCommand,
|
|
36
|
+
files: changes.files_touched.length,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
const { stdout, stderr } = await execAsync(this.ciCommand, {
|
|
41
|
+
maxBuffer: 1024 * 1024 * 10, // 10MB buffer for large test output
|
|
42
|
+
timeout: 300000, // 5 minute timeout
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const output = [stdout, stderr].filter(Boolean).join('\n');
|
|
46
|
+
|
|
47
|
+
logInfo('CI checks passed', {
|
|
48
|
+
additions: changes.additions,
|
|
49
|
+
deletions: changes.deletions,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
passed: true,
|
|
54
|
+
output,
|
|
55
|
+
};
|
|
56
|
+
} catch (error: any) {
|
|
57
|
+
// exec throws error when command exits with non-zero code
|
|
58
|
+
const output = [error.stdout || '', error.stderr || '']
|
|
59
|
+
.filter(Boolean)
|
|
60
|
+
.join('\n');
|
|
61
|
+
|
|
62
|
+
logError('CI checks failed', error, {
|
|
63
|
+
exitCode: error.code,
|
|
64
|
+
signal: error.signal,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
passed: false,
|
|
69
|
+
output: output || error.message,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Run only tests (skip lint)
|
|
76
|
+
*/
|
|
77
|
+
async runTests(): Promise<{ passed: boolean; output: string }> {
|
|
78
|
+
const testCommand = 'npm test';
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
const { stdout, stderr } = await execAsync(testCommand, {
|
|
82
|
+
maxBuffer: 1024 * 1024 * 10,
|
|
83
|
+
timeout: 300000,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
passed: true,
|
|
88
|
+
output: [stdout, stderr].filter(Boolean).join('\n'),
|
|
89
|
+
};
|
|
90
|
+
} catch (error: any) {
|
|
91
|
+
return {
|
|
92
|
+
passed: false,
|
|
93
|
+
output:
|
|
94
|
+
[error.stdout, error.stderr].filter(Boolean).join('\n') ||
|
|
95
|
+
error.message,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Run only lint (skip tests)
|
|
102
|
+
*/
|
|
103
|
+
async runLint(): Promise<{ passed: boolean; output: string }> {
|
|
104
|
+
const lintCommand = 'npm run lint';
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
const { stdout, stderr } = await execAsync(lintCommand, {
|
|
108
|
+
maxBuffer: 1024 * 1024 * 10,
|
|
109
|
+
timeout: 60000, // 1 minute for lint
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
passed: true,
|
|
114
|
+
output: [stdout, stderr].filter(Boolean).join('\n'),
|
|
115
|
+
};
|
|
116
|
+
} catch (error: any) {
|
|
117
|
+
return {
|
|
118
|
+
passed: false,
|
|
119
|
+
output:
|
|
120
|
+
[error.stdout, error.stderr].filter(Boolean).join('\n') ||
|
|
121
|
+
error.message,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Check if CI is configured (npm scripts exist)
|
|
128
|
+
*/
|
|
129
|
+
async isConfigured(): Promise<boolean> {
|
|
130
|
+
try {
|
|
131
|
+
// Check if npm test is defined
|
|
132
|
+
await execAsync('npm run test --help', {
|
|
133
|
+
timeout: 5000,
|
|
134
|
+
});
|
|
135
|
+
return true;
|
|
136
|
+
} catch {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Default CI provider instance
|
|
144
|
+
*/
|
|
145
|
+
export const ciProvider = new NpmCIProvider();
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { fileExists, readJsonFile, writeJsonFile } from './file-utils.js';
|
|
2
|
+
import type { SystemConfig } from '../types/index.js';
|
|
3
|
+
|
|
4
|
+
const CONFIG_PATH = '.agent-meta/config.json';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Default configuration per spec §13
|
|
8
|
+
*/
|
|
9
|
+
export const DEFAULT_CONFIG: SystemConfig = {
|
|
10
|
+
version: '2.0.0',
|
|
11
|
+
created_at: new Date().toISOString(),
|
|
12
|
+
error_provider: 'file',
|
|
13
|
+
error_file: '.agent-meta/_errors.json',
|
|
14
|
+
ci_command: 'npm test && npm run lint',
|
|
15
|
+
spawn_count: 0,
|
|
16
|
+
last_gc_at_spawn: 0,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Load configuration from .agent-meta/config.json
|
|
21
|
+
* Creates default config if file doesn't exist
|
|
22
|
+
*/
|
|
23
|
+
export function loadConfig(): SystemConfig {
|
|
24
|
+
if (!fileExists(CONFIG_PATH)) {
|
|
25
|
+
// Initialize with defaults
|
|
26
|
+
writeJsonFile(CONFIG_PATH, DEFAULT_CONFIG);
|
|
27
|
+
return DEFAULT_CONFIG;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const config = readJsonFile<SystemConfig>(CONFIG_PATH);
|
|
32
|
+
|
|
33
|
+
// Merge with defaults to handle missing fields
|
|
34
|
+
return {
|
|
35
|
+
...DEFAULT_CONFIG,
|
|
36
|
+
...config,
|
|
37
|
+
};
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.error(`Failed to load config from ${CONFIG_PATH}:`, error);
|
|
40
|
+
console.error('Using default configuration');
|
|
41
|
+
return DEFAULT_CONFIG;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Save configuration to .agent-meta/config.json
|
|
47
|
+
*/
|
|
48
|
+
export function saveConfig(config: SystemConfig): void {
|
|
49
|
+
try {
|
|
50
|
+
writeJsonFile(CONFIG_PATH, config);
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error(`Failed to save config to ${CONFIG_PATH}:`, error);
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Update specific config fields
|
|
59
|
+
*/
|
|
60
|
+
export function updateConfig(updates: Partial<SystemConfig>): SystemConfig {
|
|
61
|
+
const config = loadConfig();
|
|
62
|
+
const updated = {
|
|
63
|
+
...config,
|
|
64
|
+
...updates,
|
|
65
|
+
};
|
|
66
|
+
saveConfig(updated);
|
|
67
|
+
return updated;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Increment spawn counter and check if GC should run
|
|
72
|
+
* GC runs every 100 spawns (per spec §8)
|
|
73
|
+
*/
|
|
74
|
+
export function incrementSpawnCount(): { count: number; shouldRunGC: boolean } {
|
|
75
|
+
const config = loadConfig();
|
|
76
|
+
config.spawn_count += 1;
|
|
77
|
+
|
|
78
|
+
const shouldRunGC = config.spawn_count - config.last_gc_at_spawn >= 100;
|
|
79
|
+
|
|
80
|
+
saveConfig(config);
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
count: config.spawn_count,
|
|
84
|
+
shouldRunGC,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Mark that GC has been run
|
|
90
|
+
*/
|
|
91
|
+
export function markGCRun(): void {
|
|
92
|
+
const config = loadConfig();
|
|
93
|
+
config.last_gc_at_spawn = config.spawn_count;
|
|
94
|
+
saveConfig(config);
|
|
95
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { fileExists, readJsonFile, writeJsonFile } from './file-utils.js';
|
|
2
|
+
import type { ErrorProvider, ErrorProviderData } from '../types/index.js';
|
|
3
|
+
import { logWarn } from './logger.js';
|
|
4
|
+
|
|
5
|
+
const ERROR_FILE_PATH = '.agent-meta/_errors.json';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* File-based error provider implementation
|
|
9
|
+
* Per spec §2.5 (second-spec.md lines 665-705)
|
|
10
|
+
*
|
|
11
|
+
* Users populate .agent-meta/_errors.json manually or via external tools
|
|
12
|
+
* Format:
|
|
13
|
+
* {
|
|
14
|
+
* "updated_at": "2026-01-30T17:00:00Z",
|
|
15
|
+
* "errors": [
|
|
16
|
+
* {
|
|
17
|
+
* "file": "src/auth.ts",
|
|
18
|
+
* "count": 6,
|
|
19
|
+
* "types": ["TypeError", "ReferenceError"]
|
|
20
|
+
* }
|
|
21
|
+
* ]
|
|
22
|
+
* }
|
|
23
|
+
*/
|
|
24
|
+
export class FileErrorProvider implements ErrorProvider {
|
|
25
|
+
private errorFilePath: string;
|
|
26
|
+
|
|
27
|
+
constructor(errorFilePath: string = ERROR_FILE_PATH) {
|
|
28
|
+
this.errorFilePath = errorFilePath;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Get error count and types for a specific file
|
|
33
|
+
*/
|
|
34
|
+
async getErrors(file: string): Promise<{ count: number; types: string[] }> {
|
|
35
|
+
if (!fileExists(this.errorFilePath)) {
|
|
36
|
+
// No error file exists - return zero errors
|
|
37
|
+
return { count: 0, types: [] };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
const data = readJsonFile<ErrorProviderData>(this.errorFilePath);
|
|
42
|
+
|
|
43
|
+
const entry = data.errors.find((e) => e.file === file);
|
|
44
|
+
|
|
45
|
+
if (!entry) {
|
|
46
|
+
return { count: 0, types: [] };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
count: entry.count,
|
|
51
|
+
types: entry.types,
|
|
52
|
+
};
|
|
53
|
+
} catch (error) {
|
|
54
|
+
logWarn(`Failed to read error file: ${this.errorFilePath}`, {
|
|
55
|
+
error: error instanceof Error ? error.message : String(error),
|
|
56
|
+
});
|
|
57
|
+
return { count: 0, types: [] };
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Initialize error file with empty data
|
|
63
|
+
*/
|
|
64
|
+
initializeErrorFile(): void {
|
|
65
|
+
if (!fileExists(this.errorFilePath)) {
|
|
66
|
+
const initialData: ErrorProviderData = {
|
|
67
|
+
updated_at: new Date().toISOString(),
|
|
68
|
+
errors: [],
|
|
69
|
+
};
|
|
70
|
+
writeJsonFile(this.errorFilePath, initialData);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Update errors for a specific file
|
|
76
|
+
* Helper for manual error tracking
|
|
77
|
+
*/
|
|
78
|
+
updateErrors(file: string, count: number, types: string[]): void {
|
|
79
|
+
let data: ErrorProviderData;
|
|
80
|
+
|
|
81
|
+
if (fileExists(this.errorFilePath)) {
|
|
82
|
+
data = readJsonFile<ErrorProviderData>(this.errorFilePath);
|
|
83
|
+
} else {
|
|
84
|
+
data = {
|
|
85
|
+
updated_at: new Date().toISOString(),
|
|
86
|
+
errors: [],
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Update or add entry
|
|
91
|
+
const existingIndex = data.errors.findIndex((e) => e.file === file);
|
|
92
|
+
|
|
93
|
+
if (existingIndex >= 0) {
|
|
94
|
+
data.errors[existingIndex] = { file, count, types };
|
|
95
|
+
} else {
|
|
96
|
+
data.errors.push({ file, count, types });
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
data.updated_at = new Date().toISOString();
|
|
100
|
+
|
|
101
|
+
writeJsonFile(this.errorFilePath, data);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Clear all error data
|
|
106
|
+
*/
|
|
107
|
+
clearErrors(): void {
|
|
108
|
+
const data: ErrorProviderData = {
|
|
109
|
+
updated_at: new Date().toISOString(),
|
|
110
|
+
errors: [],
|
|
111
|
+
};
|
|
112
|
+
writeJsonFile(this.errorFilePath, data);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Get all errors (for reporting)
|
|
117
|
+
*/
|
|
118
|
+
getAllErrors(): ErrorProviderData['errors'] {
|
|
119
|
+
if (!fileExists(this.errorFilePath)) {
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
const data = readJsonFile<ErrorProviderData>(this.errorFilePath);
|
|
125
|
+
return data.errors;
|
|
126
|
+
} catch (error) {
|
|
127
|
+
logWarn(`Failed to read error file: ${this.errorFilePath}`, {
|
|
128
|
+
error: error instanceof Error ? error.message : String(error),
|
|
129
|
+
});
|
|
130
|
+
return [];
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Default error provider instance
|
|
137
|
+
*/
|
|
138
|
+
export const errorProvider = new FileErrorProvider();
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
|
|
4
|
+
export function pathToSafeFilename(filePath: string): string {
|
|
5
|
+
return filePath.replace(/[/\\]+/g, '__');
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function safeFilenameToPath(safeFilename: string): string {
|
|
9
|
+
return safeFilename.replace(/__/g, '/');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function fileExists(filePath: string): boolean {
|
|
13
|
+
try {
|
|
14
|
+
fs.accessSync(filePath, fs.constants.F_OK);
|
|
15
|
+
return true;
|
|
16
|
+
} catch {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function readFile(filePath: string): string {
|
|
22
|
+
return fs.readFileSync(filePath, 'utf-8');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function writeFile(filePath: string, content: string): void {
|
|
26
|
+
const dir = path.dirname(filePath);
|
|
27
|
+
if (!fs.existsSync(dir)) {
|
|
28
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
29
|
+
}
|
|
30
|
+
fs.writeFileSync(filePath, content, 'utf-8');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function appendFile(filePath: string, content: string): void {
|
|
34
|
+
const dir = path.dirname(filePath);
|
|
35
|
+
if (!fs.existsSync(dir)) {
|
|
36
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
37
|
+
}
|
|
38
|
+
fs.appendFileSync(filePath, content, 'utf-8');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function readJsonFile<T>(filePath: string): T {
|
|
42
|
+
const content = readFile(filePath);
|
|
43
|
+
return JSON.parse(content);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function writeJsonFile<T>(filePath: string, data: T, indent: number = 2): void {
|
|
47
|
+
const content = JSON.stringify(data, null, indent);
|
|
48
|
+
writeFile(filePath, content);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function listFilesRecursive(dirPath: string): string[] {
|
|
52
|
+
const files: string[] = [];
|
|
53
|
+
|
|
54
|
+
function traverse(currentPath: string): void {
|
|
55
|
+
const entries = fs.readdirSync(currentPath, { withFileTypes: true });
|
|
56
|
+
for (const entry of entries) {
|
|
57
|
+
const fullPath = path.join(currentPath, entry.name);
|
|
58
|
+
if (entry.isDirectory()) {
|
|
59
|
+
traverse(fullPath);
|
|
60
|
+
} else {
|
|
61
|
+
files.push(fullPath);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
traverse(dirPath);
|
|
67
|
+
return files;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function getLineCount(filePath: string): number {
|
|
71
|
+
const content = readFile(filePath);
|
|
72
|
+
return content.split('\n').length;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function isTypeScriptFile(filePath: string): boolean {
|
|
76
|
+
return /\.ts$/.test(filePath) && !/\.d\.ts$/.test(filePath);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function isTestFile(filePath: string): boolean {
|
|
80
|
+
return /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filePath);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function ensureDir(dirPath: string): void {
|
|
84
|
+
if (!fs.existsSync(dirPath)) {
|
|
85
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function deleteFile(filePath: string): void {
|
|
90
|
+
if (fileExists(filePath)) {
|
|
91
|
+
fs.unlinkSync(filePath);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function copyFile(sourcePath: string, destPath: string): void {
|
|
96
|
+
const dir = path.dirname(destPath);
|
|
97
|
+
if (!fs.existsSync(dir)) {
|
|
98
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
99
|
+
}
|
|
100
|
+
fs.copyFileSync(sourcePath, destPath);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function getFileModTime(filePath: string): number {
|
|
104
|
+
const stats = fs.statSync(filePath);
|
|
105
|
+
return stats.mtimeMs;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function getFileSize(filePath: string): number {
|
|
109
|
+
const stats = fs.statSync(filePath);
|
|
110
|
+
return stats.size;
|
|
111
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for Claude-Mycelium
|
|
3
|
+
* Centralized exports for cleaner imports
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export * from './file-utils.js';
|
|
7
|
+
export * from './config.js';
|
|
8
|
+
export * from './logger.js';
|
|
9
|
+
export * from './error-provider.js';
|
|
10
|
+
export * from './ci-provider.js';
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured logging utility for Claude-Mycelium
|
|
3
|
+
* Simple console-based logging with timestamp and context
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
7
|
+
|
|
8
|
+
interface LogContext {
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const LOG_LEVEL: LogLevel = (process.env.LOG_LEVEL as LogLevel) || 'info';
|
|
13
|
+
|
|
14
|
+
const LEVEL_PRIORITY: Record<LogLevel, number> = {
|
|
15
|
+
debug: 0,
|
|
16
|
+
info: 1,
|
|
17
|
+
warn: 2,
|
|
18
|
+
error: 3,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function shouldLog(level: LogLevel): boolean {
|
|
22
|
+
return LEVEL_PRIORITY[level] >= LEVEL_PRIORITY[LOG_LEVEL];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function formatTimestamp(): string {
|
|
26
|
+
return new Date().toISOString();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function formatMessage(level: LogLevel, message: string, context?: LogContext): string {
|
|
30
|
+
const timestamp = formatTimestamp();
|
|
31
|
+
const contextStr = context ? ` ${JSON.stringify(context)}` : '';
|
|
32
|
+
return `[${timestamp}] [${level.toUpperCase()}] ${message}${contextStr}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Log debug message (lowest priority)
|
|
37
|
+
*/
|
|
38
|
+
export function logDebug(message: string, context?: LogContext): void {
|
|
39
|
+
if (shouldLog('debug')) {
|
|
40
|
+
console.debug(formatMessage('debug', message, context));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Log info message (normal priority)
|
|
46
|
+
*/
|
|
47
|
+
export function logInfo(message: string, context?: LogContext): void {
|
|
48
|
+
if (shouldLog('info')) {
|
|
49
|
+
console.info(formatMessage('info', message, context));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Log warning message (high priority)
|
|
55
|
+
*/
|
|
56
|
+
export function logWarn(message: string, context?: LogContext): void {
|
|
57
|
+
if (shouldLog('warn')) {
|
|
58
|
+
console.warn(formatMessage('warn', message, context));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Log error message (highest priority)
|
|
64
|
+
*/
|
|
65
|
+
export function logError(message: string, error?: Error, context?: LogContext): void {
|
|
66
|
+
if (shouldLog('error')) {
|
|
67
|
+
const errorContext = error
|
|
68
|
+
? {
|
|
69
|
+
...context,
|
|
70
|
+
error: error.message,
|
|
71
|
+
stack: error.stack,
|
|
72
|
+
}
|
|
73
|
+
: context;
|
|
74
|
+
|
|
75
|
+
console.error(formatMessage('error', message, errorContext));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Create a child logger with fixed context
|
|
81
|
+
* Useful for agent-specific or file-specific logging
|
|
82
|
+
*/
|
|
83
|
+
export function createLogger(baseContext: LogContext) {
|
|
84
|
+
return {
|
|
85
|
+
debug: (message: string, context?: LogContext) =>
|
|
86
|
+
logDebug(message, { ...baseContext, ...context }),
|
|
87
|
+
info: (message: string, context?: LogContext) =>
|
|
88
|
+
logInfo(message, { ...baseContext, ...context }),
|
|
89
|
+
warn: (message: string, context?: LogContext) =>
|
|
90
|
+
logWarn(message, { ...baseContext, ...context }),
|
|
91
|
+
error: (message: string, error?: Error, context?: LogContext) =>
|
|
92
|
+
logError(message, error, { ...baseContext, ...context }),
|
|
93
|
+
};
|
|
94
|
+
}
|