add-skill-kit 3.2.3 → 3.2.5
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/README.md +1 -1
- package/bin/lib/commands/help.js +0 -4
- package/bin/lib/commands/install.js +90 -9
- package/bin/lib/ui.js +1 -1
- package/lib/agent-cli/__tests__/adaptive_engine.test.js +190 -0
- package/lib/agent-cli/__tests__/integration/cross_script.test.js +222 -0
- package/lib/agent-cli/__tests__/integration/full_cycle.test.js +230 -0
- package/lib/agent-cli/__tests__/pattern_analyzer.test.js +173 -0
- package/lib/agent-cli/__tests__/pre_execution_check.test.js +167 -0
- package/lib/agent-cli/__tests__/skill_injector.test.js +191 -0
- package/lib/agent-cli/bin/agent.js +191 -0
- package/lib/agent-cli/dashboard/dashboard_server.js +340 -0
- package/lib/agent-cli/dashboard/index.html +538 -0
- package/lib/agent-cli/lib/audit.js +154 -0
- package/lib/agent-cli/lib/audit.test.js +100 -0
- package/lib/agent-cli/lib/auto-learn.js +319 -0
- package/lib/agent-cli/lib/auto_preview.py +148 -0
- package/lib/agent-cli/lib/backup.js +138 -0
- package/lib/agent-cli/lib/backup.test.js +78 -0
- package/lib/agent-cli/lib/checklist.py +222 -0
- package/lib/agent-cli/lib/cognitive-lesson.js +476 -0
- package/lib/agent-cli/lib/completion.js +149 -0
- package/lib/agent-cli/lib/config.js +35 -0
- package/lib/agent-cli/lib/eslint-fix.js +238 -0
- package/lib/agent-cli/lib/evolution-signal.js +215 -0
- package/lib/agent-cli/lib/export.js +86 -0
- package/lib/agent-cli/lib/export.test.js +65 -0
- package/lib/agent-cli/lib/fix.js +337 -0
- package/lib/agent-cli/lib/fix.test.js +80 -0
- package/lib/agent-cli/lib/gemini-export.js +83 -0
- package/lib/agent-cli/lib/generate-registry.js +42 -0
- package/lib/agent-cli/lib/hooks/install-hooks.js +152 -0
- package/lib/agent-cli/lib/hooks/lint-learn.js +172 -0
- package/lib/agent-cli/lib/ignore.js +116 -0
- package/lib/agent-cli/lib/ignore.test.js +58 -0
- package/lib/agent-cli/lib/init.js +124 -0
- package/lib/agent-cli/lib/learn.js +255 -0
- package/lib/agent-cli/lib/learn.test.js +70 -0
- package/lib/agent-cli/lib/migrate-to-v4.js +322 -0
- package/lib/agent-cli/lib/proposals.js +199 -0
- package/lib/agent-cli/lib/proposals.test.js +56 -0
- package/lib/agent-cli/lib/recall.js +820 -0
- package/lib/agent-cli/lib/recall.test.js +107 -0
- package/lib/agent-cli/lib/selfevolution-bridge.js +167 -0
- package/lib/agent-cli/lib/session_manager.py +120 -0
- package/lib/agent-cli/lib/settings.js +227 -0
- package/lib/agent-cli/lib/skill-learn.js +296 -0
- package/lib/agent-cli/lib/stats.js +132 -0
- package/lib/agent-cli/lib/stats.test.js +94 -0
- package/lib/agent-cli/lib/types.js +33 -0
- package/lib/agent-cli/lib/ui/audit-ui.js +146 -0
- package/lib/agent-cli/lib/ui/backup-ui.js +107 -0
- package/lib/agent-cli/lib/ui/clack-helpers.js +317 -0
- package/lib/agent-cli/lib/ui/common.js +83 -0
- package/lib/agent-cli/lib/ui/completion-ui.js +126 -0
- package/lib/agent-cli/lib/ui/custom-select.js +69 -0
- package/lib/agent-cli/lib/ui/dashboard-ui.js +222 -0
- package/lib/agent-cli/lib/ui/evolution-signals-ui.js +107 -0
- package/lib/agent-cli/lib/ui/export-ui.js +94 -0
- package/lib/agent-cli/lib/ui/fix-all-ui.js +191 -0
- package/lib/agent-cli/lib/ui/help-ui.js +49 -0
- package/lib/agent-cli/lib/ui/index.js +199 -0
- package/lib/agent-cli/lib/ui/init-ui.js +56 -0
- package/lib/agent-cli/lib/ui/knowledge-ui.js +55 -0
- package/lib/agent-cli/lib/ui/learn-ui.js +706 -0
- package/lib/agent-cli/lib/ui/lessons-ui.js +148 -0
- package/lib/agent-cli/lib/ui/pretty.js +145 -0
- package/lib/agent-cli/lib/ui/proposals-ui.js +99 -0
- package/lib/agent-cli/lib/ui/recall-ui.js +342 -0
- package/lib/agent-cli/lib/ui/routing-demo.js +79 -0
- package/lib/agent-cli/lib/ui/routing-ui.js +325 -0
- package/lib/agent-cli/lib/ui/settings-ui.js +381 -0
- package/lib/agent-cli/lib/ui/stats-ui.js +123 -0
- package/lib/agent-cli/lib/ui/watch-ui.js +236 -0
- package/lib/agent-cli/lib/verify_all.py +327 -0
- package/lib/agent-cli/lib/watcher.js +181 -0
- package/lib/agent-cli/lib/watcher.test.js +85 -0
- package/lib/agent-cli/package.json +51 -0
- package/lib/agent-cli/scripts/adaptive_engine.js +381 -0
- package/lib/agent-cli/scripts/dashboard_server.js +224 -0
- package/lib/agent-cli/scripts/error_sensor.js +565 -0
- package/lib/agent-cli/scripts/learn_from_failure.js +225 -0
- package/lib/agent-cli/scripts/pattern_analyzer.js +781 -0
- package/lib/agent-cli/scripts/pre_execution_check.js +623 -0
- package/lib/agent-cli/scripts/rule_sharing.js +374 -0
- package/lib/agent-cli/scripts/skill_injector.js +387 -0
- package/lib/agent-cli/scripts/success_sensor.js +500 -0
- package/lib/agent-cli/scripts/user_correction_sensor.js +426 -0
- package/lib/agent-cli/services/auto-learn-service.js +247 -0
- package/lib/agent-cli/src/MIGRATION.md +418 -0
- package/lib/agent-cli/src/README.md +367 -0
- package/lib/agent-cli/src/core/evolution/evolution-signal.js +42 -0
- package/lib/agent-cli/src/core/evolution/index.js +17 -0
- package/lib/agent-cli/src/core/evolution/review-gate.js +40 -0
- package/lib/agent-cli/src/core/evolution/signal-detector.js +137 -0
- package/lib/agent-cli/src/core/evolution/signal-queue.js +79 -0
- package/lib/agent-cli/src/core/evolution/threshold-checker.js +79 -0
- package/lib/agent-cli/src/core/index.js +15 -0
- package/lib/agent-cli/src/core/learning/cognitive-enhancer.js +282 -0
- package/lib/agent-cli/src/core/learning/index.js +12 -0
- package/lib/agent-cli/src/core/learning/lesson-synthesizer.js +83 -0
- package/lib/agent-cli/src/core/scanning/index.js +14 -0
- package/lib/agent-cli/src/data/index.js +13 -0
- package/lib/agent-cli/src/data/repositories/index.js +8 -0
- package/lib/agent-cli/src/data/repositories/lesson-repository.js +130 -0
- package/lib/agent-cli/src/data/repositories/signal-repository.js +119 -0
- package/lib/agent-cli/src/data/storage/index.js +8 -0
- package/lib/agent-cli/src/data/storage/json-storage.js +64 -0
- package/lib/agent-cli/src/data/storage/yaml-storage.js +66 -0
- package/lib/agent-cli/src/infrastructure/index.js +13 -0
- package/lib/agent-cli/src/presentation/formatters/skill-formatter.js +232 -0
- package/lib/agent-cli/src/services/export-service.js +162 -0
- package/lib/agent-cli/src/services/index.js +13 -0
- package/lib/agent-cli/src/services/learning-service.js +99 -0
- package/lib/agent-cli/types/index.d.ts +343 -0
- package/lib/agent-cli/utils/benchmark.js +269 -0
- package/lib/agent-cli/utils/logger.js +303 -0
- package/lib/agent-cli/utils/ml_patterns.js +300 -0
- package/lib/agent-cli/utils/recovery.js +312 -0
- package/lib/agent-cli/utils/telemetry.js +290 -0
- package/lib/agentskillskit-cli/README.md +21 -0
- package/{node_modules/agentskillskit-cli/bin → lib/agentskillskit-cli}/ag-smart.js +15 -15
- package/lib/agentskillskit-cli/package.json +51 -0
- package/package.json +19 -9
- /package/bin/{cli.js → kit.js} +0 -0
- /package/{node_modules/agentskillskit-cli → lib/agent-cli}/README.md +0 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Tests for recall.js functionality
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
5
|
+
import fs from "fs";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import os from "os";
|
|
8
|
+
|
|
9
|
+
const TEST_DIR = path.join(os.tmpdir(), "agent-skill-kit-recall-test");
|
|
10
|
+
const KNOWLEDGE_DIR = path.join(TEST_DIR, ".agent", "knowledge");
|
|
11
|
+
const LESSONS_PATH = path.join(KNOWLEDGE_DIR, "lessons-learned.yaml");
|
|
12
|
+
const TEST_FILE = path.join(TEST_DIR, "test-code.js");
|
|
13
|
+
|
|
14
|
+
describe("Recall - Pattern Matching", () => {
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
fs.mkdirSync(KNOWLEDGE_DIR, { recursive: true });
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
fs.rmSync(TEST_DIR, { recursive: true, force: true });
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("detects pattern matches in code", () => {
|
|
24
|
+
const codeContent = `
|
|
25
|
+
console.log("debug");
|
|
26
|
+
const x = 1;
|
|
27
|
+
`;
|
|
28
|
+
const pattern = /console\.log/g;
|
|
29
|
+
const matches = codeContent.match(pattern);
|
|
30
|
+
|
|
31
|
+
expect(matches).not.toBeNull();
|
|
32
|
+
expect(matches.length).toBe(1);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("returns null when no pattern matches", () => {
|
|
36
|
+
const codeContent = `const x = 1;`;
|
|
37
|
+
const pattern = /console\.log/g;
|
|
38
|
+
const matches = codeContent.match(pattern);
|
|
39
|
+
|
|
40
|
+
expect(matches).toBeNull();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("counts multiple occurrences", () => {
|
|
44
|
+
const codeContent = `
|
|
45
|
+
console.log("one");
|
|
46
|
+
console.log("two");
|
|
47
|
+
console.log("three");
|
|
48
|
+
`;
|
|
49
|
+
const pattern = /console\.log/g;
|
|
50
|
+
const matches = codeContent.match(pattern);
|
|
51
|
+
|
|
52
|
+
expect(matches).not.toBeNull();
|
|
53
|
+
expect(matches.length).toBe(3);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("can scan files from filesystem", () => {
|
|
57
|
+
const testCode = `console.log("test");`;
|
|
58
|
+
fs.writeFileSync(TEST_FILE, testCode, "utf8");
|
|
59
|
+
|
|
60
|
+
const content = fs.readFileSync(TEST_FILE, "utf8");
|
|
61
|
+
expect(content).toContain("console.log");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("finds line numbers for matches", () => {
|
|
65
|
+
const lines = [
|
|
66
|
+
"const a = 1;",
|
|
67
|
+
"console.log('found');",
|
|
68
|
+
"const b = 2;"
|
|
69
|
+
];
|
|
70
|
+
const pattern = /console\.log/;
|
|
71
|
+
|
|
72
|
+
const matchingLines = lines
|
|
73
|
+
.map((line, idx) => ({ line, num: idx + 1 }))
|
|
74
|
+
.filter(({ line }) => pattern.test(line));
|
|
75
|
+
|
|
76
|
+
expect(matchingLines.length).toBe(1);
|
|
77
|
+
expect(matchingLines[0].num).toBe(2);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe("Recall - Directory Scanning", () => {
|
|
82
|
+
beforeEach(() => {
|
|
83
|
+
fs.mkdirSync(KNOWLEDGE_DIR, { recursive: true });
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
afterEach(() => {
|
|
87
|
+
fs.rmSync(TEST_DIR, { recursive: true, force: true });
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("filters files by extension", () => {
|
|
91
|
+
const extensions = [".js", ".ts", ".tsx"];
|
|
92
|
+
const testFiles = ["app.js", "util.ts", "readme.md", "style.css"];
|
|
93
|
+
|
|
94
|
+
const filtered = testFiles.filter(f =>
|
|
95
|
+
extensions.some(ext => f.endsWith(ext))
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
expect(filtered).toEqual(["app.js", "util.ts"]);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("skips node_modules directory", () => {
|
|
102
|
+
const skipDirs = ["node_modules", ".git", "dist"];
|
|
103
|
+
const testDir = "node_modules";
|
|
104
|
+
|
|
105
|
+
expect(skipDirs.includes(testDir)).toBe(true);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SelfEvolution Bridge Module
|
|
3
|
+
* Connects Settings API keys with SelfEvolution's AI-powered optimization
|
|
4
|
+
*
|
|
5
|
+
* @module selfevolution-bridge
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { getApiKey } from './settings.js';
|
|
9
|
+
import fs from 'fs';
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import { fileURLToPath } from 'url';
|
|
12
|
+
import { spawn } from 'child_process';
|
|
13
|
+
|
|
14
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
15
|
+
const __dirname = path.dirname(__filename);
|
|
16
|
+
const PROJECT_ROOT = path.resolve(__dirname, '../../..');
|
|
17
|
+
const SELFEVOLUTION_DIR = path.join(PROJECT_ROOT, '.agent/skills/SelfEvolution');
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Export API keys from Settings to SelfEvolution .env file
|
|
21
|
+
* This allows Python scripts to auto-detect and use the keys
|
|
22
|
+
*
|
|
23
|
+
* @returns {{success: boolean, exported?: {gemini: boolean, claude: boolean}, path?: string, reason?: string}}
|
|
24
|
+
*/
|
|
25
|
+
export function exportApiKeysToSelfEvolution() {
|
|
26
|
+
try {
|
|
27
|
+
const geminiKey = getApiKey('gemini');
|
|
28
|
+
const claudeKey = getApiKey('claude');
|
|
29
|
+
|
|
30
|
+
// Check if any keys are configured
|
|
31
|
+
if (!geminiKey && !claudeKey) {
|
|
32
|
+
return {
|
|
33
|
+
success: false,
|
|
34
|
+
reason: 'No API keys configured in Settings'
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Ensure SelfEvolution directory exists
|
|
39
|
+
if (!fs.existsSync(SELFEVOLUTION_DIR)) {
|
|
40
|
+
return {
|
|
41
|
+
success: false,
|
|
42
|
+
reason: 'SelfEvolution skill directory not found'
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Build .env content
|
|
47
|
+
const envContent = [];
|
|
48
|
+
|
|
49
|
+
if (geminiKey) {
|
|
50
|
+
envContent.push(`GEMINI_API_KEY=${geminiKey}`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (claudeKey) {
|
|
54
|
+
envContent.push(`CLAUDE_API_KEY=${claudeKey}`);
|
|
55
|
+
envContent.push(`ANTHROPIC_API_KEY=${claudeKey}`); // Alternative name
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
envContent.push('');
|
|
59
|
+
envContent.push('# Auto-generated from Settings');
|
|
60
|
+
envContent.push(`# Last updated: ${new Date().toISOString()}`);
|
|
61
|
+
envContent.push('# DO NOT EDIT - Managed by CLI Settings');
|
|
62
|
+
|
|
63
|
+
// Write .env file
|
|
64
|
+
const envPath = path.join(SELFEVOLUTION_DIR, '.env');
|
|
65
|
+
fs.writeFileSync(envPath, envContent.join('\n'), 'utf8');
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
success: true,
|
|
69
|
+
exported: {
|
|
70
|
+
gemini: !!geminiKey,
|
|
71
|
+
claude: !!claudeKey
|
|
72
|
+
},
|
|
73
|
+
path: envPath
|
|
74
|
+
};
|
|
75
|
+
} catch (error) {
|
|
76
|
+
return {
|
|
77
|
+
success: false,
|
|
78
|
+
reason: `Export failed: ${error.message}`
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Verify that SelfEvolution can access the exported API keys
|
|
85
|
+
* Runs Python api_key_resolver.py --test
|
|
86
|
+
*
|
|
87
|
+
* @returns {Promise<{success: boolean, output?: string, error?: string, keyDetected?: boolean}>}
|
|
88
|
+
*/
|
|
89
|
+
export async function verifySelfEvolutionAccess() {
|
|
90
|
+
return new Promise((resolve) => {
|
|
91
|
+
const scriptPath = path.join(SELFEVOLUTION_DIR, 'scripts/api_key_resolver.py');
|
|
92
|
+
|
|
93
|
+
// Check if script exists
|
|
94
|
+
if (!fs.existsSync(scriptPath)) {
|
|
95
|
+
resolve({
|
|
96
|
+
success: false,
|
|
97
|
+
error: 'api_key_resolver.py not found'
|
|
98
|
+
});
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Run Python script with --test flag
|
|
103
|
+
const python = spawn('python', [scriptPath, '--test'], {
|
|
104
|
+
cwd: PROJECT_ROOT,
|
|
105
|
+
env: { ...process.env }
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
let stdout = '';
|
|
109
|
+
let stderr = '';
|
|
110
|
+
|
|
111
|
+
python.stdout.on('data', (data) => {
|
|
112
|
+
stdout += data.toString();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
python.stderr.on('data', (data) => {
|
|
116
|
+
stderr += data.toString();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
python.on('close', (code) => {
|
|
120
|
+
const success = code === 0;
|
|
121
|
+
const keyDetected = stdout.includes('✓') || stdout.includes('detected');
|
|
122
|
+
|
|
123
|
+
resolve({
|
|
124
|
+
success,
|
|
125
|
+
output: stdout.trim(),
|
|
126
|
+
error: stderr.trim(),
|
|
127
|
+
keyDetected
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
python.on('error', (error) => {
|
|
132
|
+
resolve({
|
|
133
|
+
success: false,
|
|
134
|
+
error: `Failed to run Python: ${error.message}`
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Remove SelfEvolution .env file (cleanup)
|
|
142
|
+
* Called when user removes all API keys from Settings
|
|
143
|
+
*
|
|
144
|
+
* @returns {{success: boolean, reason?: string}}
|
|
145
|
+
*/
|
|
146
|
+
export function cleanupSelfEvolutionEnv() {
|
|
147
|
+
try {
|
|
148
|
+
const envPath = path.join(SELFEVOLUTION_DIR, '.env');
|
|
149
|
+
|
|
150
|
+
if (fs.existsSync(envPath)) {
|
|
151
|
+
fs.unlinkSync(envPath);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return { success: true };
|
|
155
|
+
} catch (error) {
|
|
156
|
+
return {
|
|
157
|
+
success: false,
|
|
158
|
+
reason: `Cleanup failed: ${error.message}`
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export default {
|
|
164
|
+
exportApiKeysToSelfEvolution,
|
|
165
|
+
verifySelfEvolutionAccess,
|
|
166
|
+
cleanupSelfEvolutionEnv
|
|
167
|
+
};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Session Manager - Agent Skill Kit
|
|
4
|
+
=================================
|
|
5
|
+
Analyzes project state, detects tech stack, tracks file statistics, and provides
|
|
6
|
+
a summary of the current session.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
python .agent/scripts/session_manager.py status [path]
|
|
10
|
+
python .agent/scripts/session_manager.py info [path]
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import os
|
|
14
|
+
import json
|
|
15
|
+
import argparse
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import Dict, Any, List
|
|
18
|
+
|
|
19
|
+
def get_project_root(path: str) -> Path:
|
|
20
|
+
return Path(path).resolve()
|
|
21
|
+
|
|
22
|
+
def analyze_package_json(root: Path) -> Dict[str, Any]:
|
|
23
|
+
pkg_file = root / "package.json"
|
|
24
|
+
if not pkg_file.exists():
|
|
25
|
+
return {"type": "unknown", "dependencies": {}}
|
|
26
|
+
|
|
27
|
+
try:
|
|
28
|
+
with open(pkg_file, 'r', encoding='utf-8') as f:
|
|
29
|
+
data = json.load(f)
|
|
30
|
+
|
|
31
|
+
deps = data.get("dependencies", {})
|
|
32
|
+
dev_deps = data.get("devDependencies", {})
|
|
33
|
+
all_deps = {**deps, **dev_deps}
|
|
34
|
+
|
|
35
|
+
stack = []
|
|
36
|
+
if "next" in all_deps: stack.append("Next.js")
|
|
37
|
+
elif "react" in all_deps: stack.append("React")
|
|
38
|
+
elif "vue" in all_deps: stack.append("Vue")
|
|
39
|
+
elif "svelte" in all_deps: stack.append("Svelte")
|
|
40
|
+
elif "express" in all_deps: stack.append("Express")
|
|
41
|
+
elif "nestjs" in all_deps or "@nestjs/core" in all_deps: stack.append("NestJS")
|
|
42
|
+
|
|
43
|
+
if "tailwindcss" in all_deps: stack.append("Tailwind CSS")
|
|
44
|
+
if "prisma" in all_deps: stack.append("Prisma")
|
|
45
|
+
if "typescript" in all_deps: stack.append("TypeScript")
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
"name": data.get("name", "unnamed"),
|
|
49
|
+
"version": data.get("version", "0.0.0"),
|
|
50
|
+
"stack": stack,
|
|
51
|
+
"scripts": list(data.get("scripts", {}).keys())
|
|
52
|
+
}
|
|
53
|
+
except Exception as e:
|
|
54
|
+
return {"error": str(e)}
|
|
55
|
+
|
|
56
|
+
def count_files(root: Path) -> Dict[str, int]:
|
|
57
|
+
stats = {"created": 0, "modified": 0, "total": 0}
|
|
58
|
+
# Simple count for now, comprehensive tracking would require git diff or extensive history
|
|
59
|
+
exclude = {".git", "node_modules", ".next", "dist", "build", ".agent", ".gemini", "__pycache__"}
|
|
60
|
+
|
|
61
|
+
for root_dir, dirs, files in os.walk(root):
|
|
62
|
+
dirs[:] = [d for d in dirs if d not in exclude]
|
|
63
|
+
stats["total"] += len(files)
|
|
64
|
+
|
|
65
|
+
return stats
|
|
66
|
+
|
|
67
|
+
def detect_features(root: Path) -> List[str]:
|
|
68
|
+
# Heuristic: look at folder names in src/
|
|
69
|
+
features = []
|
|
70
|
+
src = root / "src"
|
|
71
|
+
if src.exists():
|
|
72
|
+
possible_dirs = ["components", "modules", "features", "app", "pages", "services"]
|
|
73
|
+
for d in possible_dirs:
|
|
74
|
+
p = src / d
|
|
75
|
+
if p.exists() and p.is_dir():
|
|
76
|
+
# List subdirectories as likely features
|
|
77
|
+
for child in p.iterdir():
|
|
78
|
+
if child.is_dir():
|
|
79
|
+
features.append(child.name)
|
|
80
|
+
return features[:10] # Limit to top 10
|
|
81
|
+
|
|
82
|
+
def print_status(root: Path):
|
|
83
|
+
info = analyze_package_json(root)
|
|
84
|
+
stats = count_files(root)
|
|
85
|
+
features = detect_features(root)
|
|
86
|
+
|
|
87
|
+
print("\n=== Project Status ===")
|
|
88
|
+
print(f"\n📁 Project: {info.get('name', root.name)}")
|
|
89
|
+
print(f"📂 Path: {root}")
|
|
90
|
+
print(f"🏷️ Type: {', '.join(info.get('stack', ['Generic']))}")
|
|
91
|
+
print(f"📊 Status: Active")
|
|
92
|
+
|
|
93
|
+
print("\n🔧 Tech Stack:")
|
|
94
|
+
for tech in info.get('stack', []):
|
|
95
|
+
print(f" • {tech}")
|
|
96
|
+
|
|
97
|
+
print(f"\n✅ Detected Modules/Features ({len(features)}):")
|
|
98
|
+
for feat in features:
|
|
99
|
+
print(f" • {feat}")
|
|
100
|
+
if not features:
|
|
101
|
+
print(" (No distinct feature modules detected)")
|
|
102
|
+
|
|
103
|
+
print(f"\n📄 Files: {stats['total']} total files tracked")
|
|
104
|
+
print("\n====================\n")
|
|
105
|
+
|
|
106
|
+
def main():
|
|
107
|
+
parser = argparse.ArgumentParser(description="Session Manager")
|
|
108
|
+
parser.add_argument("command", choices=["status", "info"], help="Command to run")
|
|
109
|
+
parser.add_argument("path", nargs="?", default=".", help="Project path")
|
|
110
|
+
|
|
111
|
+
args = parser.parse_args()
|
|
112
|
+
root = get_project_root(args.path)
|
|
113
|
+
|
|
114
|
+
if args.command == "status":
|
|
115
|
+
print_status(root)
|
|
116
|
+
elif args.command == "info":
|
|
117
|
+
print(json.dumps(analyze_package_json(root), indent=2))
|
|
118
|
+
|
|
119
|
+
if __name__ == "__main__":
|
|
120
|
+
main()
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Settings management for Agent Skill Kit
|
|
3
|
+
* Handles Auto-Learning and Auto-Updating preferences
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from "fs";
|
|
7
|
+
import yaml from "js-yaml";
|
|
8
|
+
import path from "path";
|
|
9
|
+
import { KNOWLEDGE_DIR } from "./config.js";
|
|
10
|
+
|
|
11
|
+
/** Path to settings file */
|
|
12
|
+
export const SETTINGS_PATH = path.join(KNOWLEDGE_DIR, "settings.yaml");
|
|
13
|
+
|
|
14
|
+
/** Default settings */
|
|
15
|
+
const DEFAULT_SETTINGS = {
|
|
16
|
+
version: 1,
|
|
17
|
+
autoLearning: true, // ON by default - learn from mistakes
|
|
18
|
+
autoUpdating: false, // OFF by default - requires user trust
|
|
19
|
+
updateThreshold: 5, // Hits before proposing update
|
|
20
|
+
lastUpdateCheck: null,
|
|
21
|
+
apiKeys: {
|
|
22
|
+
gemini: null, // Gemini API key for agent coding
|
|
23
|
+
claude: null, // Claude API key (alternative)
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Load settings from YAML file
|
|
29
|
+
* @returns {object} Settings object
|
|
30
|
+
*/
|
|
31
|
+
export function loadSettings() {
|
|
32
|
+
try {
|
|
33
|
+
if (fs.existsSync(SETTINGS_PATH)) {
|
|
34
|
+
const content = fs.readFileSync(SETTINGS_PATH, "utf8");
|
|
35
|
+
return { ...DEFAULT_SETTINGS, ...yaml.load(content) };
|
|
36
|
+
}
|
|
37
|
+
} catch (e) {
|
|
38
|
+
console.error("Failed to load settings:", e.message);
|
|
39
|
+
}
|
|
40
|
+
return { ...DEFAULT_SETTINGS };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Save settings to YAML file
|
|
45
|
+
* @param {object} settings - Settings to save
|
|
46
|
+
*/
|
|
47
|
+
export function saveSettings(settings) {
|
|
48
|
+
try {
|
|
49
|
+
fs.mkdirSync(KNOWLEDGE_DIR, { recursive: true });
|
|
50
|
+
fs.writeFileSync(SETTINGS_PATH, yaml.dump(settings), "utf8");
|
|
51
|
+
return true;
|
|
52
|
+
} catch (e) {
|
|
53
|
+
console.error("Failed to save settings:", e.message);
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Toggle Auto-Learning setting
|
|
60
|
+
* When enabled, runs a quick scan automatically
|
|
61
|
+
* @returns {boolean} New value
|
|
62
|
+
*/
|
|
63
|
+
export function toggleAutoLearning() {
|
|
64
|
+
const settings = loadSettings();
|
|
65
|
+
settings.autoLearning = !settings.autoLearning;
|
|
66
|
+
saveSettings(settings);
|
|
67
|
+
|
|
68
|
+
// When turning ON, run quick scan (async, non-blocking)
|
|
69
|
+
if (settings.autoLearning) {
|
|
70
|
+
import('../services/auto-learn-service.js')
|
|
71
|
+
.then(({ quickScan }) => {
|
|
72
|
+
console.log('\n🧠 Auto-Learning enabled! Running quick scan...\n');
|
|
73
|
+
quickScan().catch(() => { });
|
|
74
|
+
})
|
|
75
|
+
.catch(() => {
|
|
76
|
+
// Silent fail if service not available
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return settings.autoLearning;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Toggle Auto-Updating setting
|
|
85
|
+
* @returns {boolean} New value
|
|
86
|
+
*/
|
|
87
|
+
export function toggleAutoUpdating() {
|
|
88
|
+
const settings = loadSettings();
|
|
89
|
+
settings.autoUpdating = !settings.autoUpdating;
|
|
90
|
+
saveSettings(settings);
|
|
91
|
+
return settings.autoUpdating;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Check if Auto-Learning is enabled
|
|
96
|
+
* @returns {boolean}
|
|
97
|
+
*/
|
|
98
|
+
export function isAutoLearningEnabled() {
|
|
99
|
+
return loadSettings().autoLearning;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Check if Auto-Updating is enabled
|
|
104
|
+
* @returns {boolean}
|
|
105
|
+
*/
|
|
106
|
+
export function isAutoUpdatingEnabled() {
|
|
107
|
+
return loadSettings().autoUpdating;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Get update threshold
|
|
112
|
+
* @returns {number}
|
|
113
|
+
*/
|
|
114
|
+
export function getUpdateThreshold() {
|
|
115
|
+
return loadSettings().updateThreshold;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Initialize settings file if not exists
|
|
120
|
+
*/
|
|
121
|
+
export function initSettings() {
|
|
122
|
+
if (!fs.existsSync(SETTINGS_PATH)) {
|
|
123
|
+
saveSettings(DEFAULT_SETTINGS);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Set API key for a provider
|
|
129
|
+
* Auto-exports to SelfEvolution for AI-powered optimization
|
|
130
|
+
* @param {'gemini' | 'claude'} provider - API provider
|
|
131
|
+
* @param {string} apiKey - The API key
|
|
132
|
+
* @returns {boolean} Success status
|
|
133
|
+
*/
|
|
134
|
+
export function setApiKey(provider, apiKey) {
|
|
135
|
+
try {
|
|
136
|
+
const settings = loadSettings();
|
|
137
|
+
if (!settings.apiKeys) {
|
|
138
|
+
settings.apiKeys = { gemini: null, claude: null };
|
|
139
|
+
}
|
|
140
|
+
settings.apiKeys[provider] = apiKey;
|
|
141
|
+
saveSettings(settings);
|
|
142
|
+
|
|
143
|
+
// Auto-export to SelfEvolution (async, non-blocking)
|
|
144
|
+
import('./selfevolution-bridge.js')
|
|
145
|
+
.then(({ exportApiKeysToSelfEvolution }) => {
|
|
146
|
+
exportApiKeysToSelfEvolution();
|
|
147
|
+
})
|
|
148
|
+
.catch(() => {
|
|
149
|
+
// Silent fail - SelfEvolution might not be present
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
return true;
|
|
153
|
+
} catch (e) {
|
|
154
|
+
console.error(`Failed to set ${provider} API key:`, e.message);
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Get API key for a provider
|
|
161
|
+
* @param {'gemini' | 'claude'} provider - API provider
|
|
162
|
+
* @returns {string | null} The API key or null
|
|
163
|
+
*/
|
|
164
|
+
export function getApiKey(provider) {
|
|
165
|
+
const settings = loadSettings();
|
|
166
|
+
return settings.apiKeys?.[provider] || null;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Remove API key for a provider
|
|
171
|
+
* Auto-syncs with SelfEvolution
|
|
172
|
+
* @param {'gemini' | 'claude'} provider - API provider
|
|
173
|
+
* @returns {boolean} Success status
|
|
174
|
+
*/
|
|
175
|
+
export function removeApiKey(provider) {
|
|
176
|
+
try {
|
|
177
|
+
const settings = loadSettings();
|
|
178
|
+
if (settings.apiKeys) {
|
|
179
|
+
settings.apiKeys[provider] = null;
|
|
180
|
+
saveSettings(settings);
|
|
181
|
+
|
|
182
|
+
// Re-export or cleanup if no keys left
|
|
183
|
+
import('./selfevolution-bridge.js')
|
|
184
|
+
.then(({ exportApiKeysToSelfEvolution, cleanupSelfEvolutionEnv }) => {
|
|
185
|
+
const hasAnyKey = settings.apiKeys.gemini || settings.apiKeys.claude;
|
|
186
|
+
if (hasAnyKey) {
|
|
187
|
+
exportApiKeysToSelfEvolution();
|
|
188
|
+
} else {
|
|
189
|
+
cleanupSelfEvolutionEnv();
|
|
190
|
+
}
|
|
191
|
+
})
|
|
192
|
+
.catch(() => {
|
|
193
|
+
// Silent fail
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
return true;
|
|
197
|
+
} catch (e) {
|
|
198
|
+
console.error(`Failed to remove ${provider} API key:`, e.message);
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Run full Auto-Learn cycle manually
|
|
205
|
+
* @returns {Promise<object>} Results from all scripts
|
|
206
|
+
*/
|
|
207
|
+
export async function runAutoLearnCycle() {
|
|
208
|
+
const { runFullCycle } = await import('../services/auto-learn-service.js');
|
|
209
|
+
return runFullCycle();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export default {
|
|
213
|
+
loadSettings,
|
|
214
|
+
saveSettings,
|
|
215
|
+
toggleAutoLearning,
|
|
216
|
+
toggleAutoUpdating,
|
|
217
|
+
isAutoLearningEnabled,
|
|
218
|
+
isAutoUpdatingEnabled,
|
|
219
|
+
getUpdateThreshold,
|
|
220
|
+
initSettings,
|
|
221
|
+
setApiKey,
|
|
222
|
+
getApiKey,
|
|
223
|
+
removeApiKey,
|
|
224
|
+
runAutoLearnCycle,
|
|
225
|
+
SETTINGS_PATH
|
|
226
|
+
};
|
|
227
|
+
|