pilot-ai 0.1.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/dist/agent/claude.d.ts +45 -0
- package/dist/agent/claude.d.ts.map +1 -0
- package/dist/agent/claude.js +114 -0
- package/dist/agent/claude.js.map +1 -0
- package/dist/agent/core.d.ts +17 -0
- package/dist/agent/core.d.ts.map +1 -0
- package/dist/agent/core.js +129 -0
- package/dist/agent/core.js.map +1 -0
- package/dist/agent/heartbeat.d.ts +51 -0
- package/dist/agent/heartbeat.d.ts.map +1 -0
- package/dist/agent/heartbeat.js +253 -0
- package/dist/agent/heartbeat.js.map +1 -0
- package/dist/agent/memory-commands.d.ts +11 -0
- package/dist/agent/memory-commands.d.ts.map +1 -0
- package/dist/agent/memory-commands.js +55 -0
- package/dist/agent/memory-commands.js.map +1 -0
- package/dist/agent/memory.d.ts +11 -0
- package/dist/agent/memory.d.ts.map +1 -0
- package/dist/agent/memory.js +109 -0
- package/dist/agent/memory.js.map +1 -0
- package/dist/agent/multi-agent.d.ts +47 -0
- package/dist/agent/multi-agent.d.ts.map +1 -0
- package/dist/agent/multi-agent.js +117 -0
- package/dist/agent/multi-agent.js.map +1 -0
- package/dist/agent/pipeline.d.ts +27 -0
- package/dist/agent/pipeline.d.ts.map +1 -0
- package/dist/agent/pipeline.js +52 -0
- package/dist/agent/pipeline.js.map +1 -0
- package/dist/agent/planner.d.ts +21 -0
- package/dist/agent/planner.d.ts.map +1 -0
- package/dist/agent/planner.js +51 -0
- package/dist/agent/planner.js.map +1 -0
- package/dist/agent/preference-detector.d.ts +6 -0
- package/dist/agent/preference-detector.d.ts.map +1 -0
- package/dist/agent/preference-detector.js +50 -0
- package/dist/agent/preference-detector.js.map +1 -0
- package/dist/agent/project-analyzer.d.ts +6 -0
- package/dist/agent/project-analyzer.d.ts.map +1 -0
- package/dist/agent/project-analyzer.js +108 -0
- package/dist/agent/project-analyzer.js.map +1 -0
- package/dist/agent/project.d.ts +28 -0
- package/dist/agent/project.d.ts.map +1 -0
- package/dist/agent/project.js +121 -0
- package/dist/agent/project.js.map +1 -0
- package/dist/agent/queue.d.ts +61 -0
- package/dist/agent/queue.d.ts.map +1 -0
- package/dist/agent/queue.js +167 -0
- package/dist/agent/queue.js.map +1 -0
- package/dist/agent/safety.d.ts +25 -0
- package/dist/agent/safety.d.ts.map +1 -0
- package/dist/agent/safety.js +77 -0
- package/dist/agent/safety.js.map +1 -0
- package/dist/agent/semantic-search.d.ts +34 -0
- package/dist/agent/semantic-search.d.ts.map +1 -0
- package/dist/agent/semantic-search.js +183 -0
- package/dist/agent/semantic-search.js.map +1 -0
- package/dist/agent/skills.d.ts +59 -0
- package/dist/agent/skills.d.ts.map +1 -0
- package/dist/agent/skills.js +161 -0
- package/dist/agent/skills.js.map +1 -0
- package/dist/agent/tool-descriptions.d.ts +7 -0
- package/dist/agent/tool-descriptions.d.ts.map +1 -0
- package/dist/agent/tool-descriptions.js +51 -0
- package/dist/agent/tool-descriptions.js.map +1 -0
- package/dist/agent/worktree.d.ts +28 -0
- package/dist/agent/worktree.d.ts.map +1 -0
- package/dist/agent/worktree.js +59 -0
- package/dist/agent/worktree.js.map +1 -0
- package/dist/api/server.d.ts +30 -0
- package/dist/api/server.d.ts.map +1 -0
- package/dist/api/server.js +135 -0
- package/dist/api/server.js.map +1 -0
- package/dist/cli/connection-test.d.ts +14 -0
- package/dist/cli/connection-test.d.ts.map +1 -0
- package/dist/cli/connection-test.js +82 -0
- package/dist/cli/connection-test.js.map +1 -0
- package/dist/cli/init.d.ts +2 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +287 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/logs.d.ts +5 -0
- package/dist/cli/logs.d.ts.map +1 -0
- package/dist/cli/logs.js +32 -0
- package/dist/cli/logs.js.map +1 -0
- package/dist/cli/project.d.ts +3 -0
- package/dist/cli/project.d.ts.map +1 -0
- package/dist/cli/project.js +58 -0
- package/dist/cli/project.js.map +1 -0
- package/dist/cli/start.d.ts +5 -0
- package/dist/cli/start.d.ts.map +1 -0
- package/dist/cli/start.js +82 -0
- package/dist/cli/start.js.map +1 -0
- package/dist/cli/status.d.ts +8 -0
- package/dist/cli/status.d.ts.map +1 -0
- package/dist/cli/status.js +39 -0
- package/dist/cli/status.js.map +1 -0
- package/dist/cli/stop.d.ts +2 -0
- package/dist/cli/stop.d.ts.map +1 -0
- package/dist/cli/stop.js +28 -0
- package/dist/cli/stop.js.map +1 -0
- package/dist/config/keychain.d.ts +4 -0
- package/dist/config/keychain.d.ts.map +1 -0
- package/dist/config/keychain.js +54 -0
- package/dist/config/keychain.js.map +1 -0
- package/dist/config/schema.d.ts +60 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +88 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/store.d.ts +8 -0
- package/dist/config/store.d.ts.map +1 -0
- package/dist/config/store.js +48 -0
- package/dist/config/store.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +47 -0
- package/dist/index.js.map +1 -0
- package/dist/messenger/adapter.d.ts +30 -0
- package/dist/messenger/adapter.d.ts.map +1 -0
- package/dist/messenger/adapter.js +2 -0
- package/dist/messenger/adapter.js.map +1 -0
- package/dist/messenger/factory.d.ts +4 -0
- package/dist/messenger/factory.d.ts.map +1 -0
- package/dist/messenger/factory.js +19 -0
- package/dist/messenger/factory.js.map +1 -0
- package/dist/messenger/slack.d.ts +21 -0
- package/dist/messenger/slack.d.ts.map +1 -0
- package/dist/messenger/slack.js +127 -0
- package/dist/messenger/slack.js.map +1 -0
- package/dist/messenger/telegram.d.ts +21 -0
- package/dist/messenger/telegram.d.ts.map +1 -0
- package/dist/messenger/telegram.js +118 -0
- package/dist/messenger/telegram.js.map +1 -0
- package/dist/security/audit.d.ts +15 -0
- package/dist/security/audit.d.ts.map +1 -0
- package/dist/security/audit.js +41 -0
- package/dist/security/audit.js.map +1 -0
- package/dist/security/auth.d.ts +8 -0
- package/dist/security/auth.d.ts.map +1 -0
- package/dist/security/auth.js +15 -0
- package/dist/security/auth.js.map +1 -0
- package/dist/security/prompt-guard.d.ts +11 -0
- package/dist/security/prompt-guard.d.ts.map +1 -0
- package/dist/security/prompt-guard.js +30 -0
- package/dist/security/prompt-guard.js.map +1 -0
- package/dist/security/sandbox.d.ts +11 -0
- package/dist/security/sandbox.d.ts.map +1 -0
- package/dist/security/sandbox.js +76 -0
- package/dist/security/sandbox.js.map +1 -0
- package/dist/tools/browser.d.ts +61 -0
- package/dist/tools/browser.d.ts.map +1 -0
- package/dist/tools/browser.js +196 -0
- package/dist/tools/browser.js.map +1 -0
- package/dist/tools/calendar.d.ts +36 -0
- package/dist/tools/calendar.d.ts.map +1 -0
- package/dist/tools/calendar.js +146 -0
- package/dist/tools/calendar.js.map +1 -0
- package/dist/tools/clipboard.d.ts +13 -0
- package/dist/tools/clipboard.d.ts.map +1 -0
- package/dist/tools/clipboard.js +47 -0
- package/dist/tools/clipboard.js.map +1 -0
- package/dist/tools/email.d.ts +52 -0
- package/dist/tools/email.d.ts.map +1 -0
- package/dist/tools/email.js +211 -0
- package/dist/tools/email.js.map +1 -0
- package/dist/tools/figma-mcp.d.ts +30 -0
- package/dist/tools/figma-mcp.d.ts.map +1 -0
- package/dist/tools/figma-mcp.js +58 -0
- package/dist/tools/figma-mcp.js.map +1 -0
- package/dist/tools/figma.d.ts +52 -0
- package/dist/tools/figma.d.ts.map +1 -0
- package/dist/tools/figma.js +62 -0
- package/dist/tools/figma.js.map +1 -0
- package/dist/tools/filesystem.d.ts +9 -0
- package/dist/tools/filesystem.d.ts.map +1 -0
- package/dist/tools/filesystem.js +62 -0
- package/dist/tools/filesystem.js.map +1 -0
- package/dist/tools/github.d.ts +36 -0
- package/dist/tools/github.d.ts.map +1 -0
- package/dist/tools/github.js +93 -0
- package/dist/tools/github.js.map +1 -0
- package/dist/tools/image.d.ts +14 -0
- package/dist/tools/image.d.ts.map +1 -0
- package/dist/tools/image.js +57 -0
- package/dist/tools/image.js.map +1 -0
- package/dist/tools/linear.d.ts +41 -0
- package/dist/tools/linear.d.ts.map +1 -0
- package/dist/tools/linear.js +87 -0
- package/dist/tools/linear.js.map +1 -0
- package/dist/tools/notification.d.ts +8 -0
- package/dist/tools/notification.d.ts.map +1 -0
- package/dist/tools/notification.js +49 -0
- package/dist/tools/notification.js.map +1 -0
- package/dist/tools/notion.d.ts +23 -0
- package/dist/tools/notion.d.ts.map +1 -0
- package/dist/tools/notion.js +91 -0
- package/dist/tools/notion.js.map +1 -0
- package/dist/tools/obsidian.d.ts +17 -0
- package/dist/tools/obsidian.d.ts.map +1 -0
- package/dist/tools/obsidian.js +100 -0
- package/dist/tools/obsidian.js.map +1 -0
- package/dist/tools/shell.d.ts +10 -0
- package/dist/tools/shell.d.ts.map +1 -0
- package/dist/tools/shell.js +37 -0
- package/dist/tools/shell.js.map +1 -0
- package/dist/tools/voice.d.ts +28 -0
- package/dist/tools/voice.d.ts.map +1 -0
- package/dist/tools/voice.js +88 -0
- package/dist/tools/voice.js.map +1 -0
- package/dist/tools/vscode.d.ts +42 -0
- package/dist/tools/vscode.d.ts.map +1 -0
- package/dist/tools/vscode.js +80 -0
- package/dist/tools/vscode.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { readProjectMemory, writeProjectMemory } from './memory.js';
|
|
4
|
+
const STACK_DETECTORS = [
|
|
5
|
+
{ file: 'package.json', label: 'Node.js' },
|
|
6
|
+
{ file: 'tsconfig.json', label: 'TypeScript' },
|
|
7
|
+
{ file: 'Cargo.toml', label: 'Rust' },
|
|
8
|
+
{ file: 'pyproject.toml', label: 'Python' },
|
|
9
|
+
{ file: 'go.mod', label: 'Go' },
|
|
10
|
+
{ file: 'pom.xml', label: 'Java (Maven)' },
|
|
11
|
+
{ file: 'build.gradle', label: 'Java (Gradle)' },
|
|
12
|
+
{ file: 'Gemfile', label: 'Ruby' },
|
|
13
|
+
{ file: 'docker-compose.yml', label: 'Docker Compose' },
|
|
14
|
+
{ file: 'Dockerfile', label: 'Docker' },
|
|
15
|
+
{ file: '.github/workflows', label: 'GitHub Actions' },
|
|
16
|
+
];
|
|
17
|
+
const FRAMEWORK_DETECTORS = [
|
|
18
|
+
{ dep: 'next', label: 'Next.js' },
|
|
19
|
+
{ dep: 'react', label: 'React' },
|
|
20
|
+
{ dep: 'vue', label: 'Vue.js' },
|
|
21
|
+
{ dep: 'express', label: 'Express' },
|
|
22
|
+
{ dep: 'fastify', label: 'Fastify' },
|
|
23
|
+
{ dep: 'nestjs', label: 'NestJS' },
|
|
24
|
+
{ dep: '@angular/core', label: 'Angular' },
|
|
25
|
+
{ dep: 'svelte', label: 'Svelte' },
|
|
26
|
+
{ dep: 'vitest', label: 'Vitest' },
|
|
27
|
+
{ dep: 'jest', label: 'Jest' },
|
|
28
|
+
{ dep: 'mocha', label: 'Mocha' },
|
|
29
|
+
{ dep: 'prisma', label: 'Prisma' },
|
|
30
|
+
{ dep: 'drizzle-orm', label: 'Drizzle' },
|
|
31
|
+
{ dep: 'tailwindcss', label: 'Tailwind CSS' },
|
|
32
|
+
];
|
|
33
|
+
/**
|
|
34
|
+
* Analyzes a project directory and generates a summary.
|
|
35
|
+
* Only runs if project memory is empty (first time).
|
|
36
|
+
*/
|
|
37
|
+
export async function analyzeProjectIfNew(projectName, projectPath) {
|
|
38
|
+
const existing = await readProjectMemory(projectName);
|
|
39
|
+
if (existing)
|
|
40
|
+
return null; // Already analyzed
|
|
41
|
+
const analysis = await analyzeProject(projectName, projectPath);
|
|
42
|
+
if (analysis.stack.length === 0 && analysis.structure.length === 0) {
|
|
43
|
+
return null; // Nothing detected
|
|
44
|
+
}
|
|
45
|
+
const lines = [`# ${projectName}`];
|
|
46
|
+
if (analysis.stack.length > 0) {
|
|
47
|
+
lines.push('', `## Stack`, analysis.stack.map((s) => `- ${s}`).join('\n'));
|
|
48
|
+
}
|
|
49
|
+
if (analysis.structure.length > 0) {
|
|
50
|
+
lines.push('', `## Structure`, analysis.structure.map((s) => `- ${s}`).join('\n'));
|
|
51
|
+
}
|
|
52
|
+
const content = lines.join('\n');
|
|
53
|
+
await writeProjectMemory(projectName, content);
|
|
54
|
+
return content;
|
|
55
|
+
}
|
|
56
|
+
async function analyzeProject(name, projectPath) {
|
|
57
|
+
const stack = [];
|
|
58
|
+
const structure = [];
|
|
59
|
+
// Detect stack from marker files
|
|
60
|
+
for (const { file, label } of STACK_DETECTORS) {
|
|
61
|
+
try {
|
|
62
|
+
await fs.access(path.join(projectPath, file));
|
|
63
|
+
stack.push(label);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Not found
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Detect frameworks from package.json
|
|
70
|
+
try {
|
|
71
|
+
const pkgContent = await fs.readFile(path.join(projectPath, 'package.json'), 'utf-8');
|
|
72
|
+
const pkg = JSON.parse(pkgContent);
|
|
73
|
+
const allDeps = {
|
|
74
|
+
...pkg.dependencies,
|
|
75
|
+
...pkg.devDependencies,
|
|
76
|
+
};
|
|
77
|
+
for (const { dep, label } of FRAMEWORK_DETECTORS) {
|
|
78
|
+
if (dep in allDeps) {
|
|
79
|
+
stack.push(label);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (pkg.scripts) {
|
|
83
|
+
const scripts = Object.keys(pkg.scripts);
|
|
84
|
+
if (scripts.length > 0) {
|
|
85
|
+
structure.push(`Scripts: ${scripts.slice(0, 8).join(', ')}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// No package.json or invalid
|
|
91
|
+
}
|
|
92
|
+
// Detect top-level directory structure
|
|
93
|
+
try {
|
|
94
|
+
const entries = await fs.readdir(projectPath, { withFileTypes: true });
|
|
95
|
+
const dirs = entries
|
|
96
|
+
.filter((e) => e.isDirectory() && !e.name.startsWith('.') && e.name !== 'node_modules')
|
|
97
|
+
.map((e) => e.name)
|
|
98
|
+
.slice(0, 10);
|
|
99
|
+
if (dirs.length > 0) {
|
|
100
|
+
structure.push(`Directories: ${dirs.join(', ')}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// Can't read
|
|
105
|
+
}
|
|
106
|
+
return { name, stack, structure };
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=project-analyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-analyzer.js","sourceRoot":"","sources":["../../src/agent/project-analyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface ProjectEntry {
|
|
2
|
+
path: string;
|
|
3
|
+
description?: string;
|
|
4
|
+
lastUsed?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface ProjectRegistry {
|
|
7
|
+
scanRoots: string[];
|
|
8
|
+
detectBy: string[];
|
|
9
|
+
projects: Record<string, ProjectEntry>;
|
|
10
|
+
}
|
|
11
|
+
export declare function loadRegistry(): Promise<ProjectRegistry>;
|
|
12
|
+
export declare function addProject(name: string, projectPath: string, description?: string): Promise<void>;
|
|
13
|
+
export declare function removeProject(name: string): Promise<boolean>;
|
|
14
|
+
export declare function listProjects(): Promise<Record<string, ProjectEntry>>;
|
|
15
|
+
/**
|
|
16
|
+
* 지정된 루트 디렉토리들을 스캔하여 프로젝트를 자동 감지한다.
|
|
17
|
+
*/
|
|
18
|
+
export declare function scanProjects(roots: string[]): Promise<Record<string, string>>;
|
|
19
|
+
/**
|
|
20
|
+
* 사용자 메시지에서 프로젝트를 매칭한다.
|
|
21
|
+
* 우선순위: 정확한 이름 → 절대경로 → fuzzy match
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolveProject(query: string): Promise<{
|
|
24
|
+
name: string;
|
|
25
|
+
path: string;
|
|
26
|
+
} | null>;
|
|
27
|
+
export declare function touchProject(name: string): Promise<void>;
|
|
28
|
+
//# sourceMappingURL=project.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/agent/project.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CACxC;AAQD,wBAAsB,YAAY,IAAI,OAAO,CAAC,eAAe,CAAC,CAO7D;AAOD,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQvG;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAMlE;AAED,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAG1E;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAmCnF;AAcD;;;GAGG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAuBlG;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM9D"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { getPilotDir } from '../config/store.js';
|
|
4
|
+
const DEFAULT_DETECT_BY = ['package.json', '.git', 'Cargo.toml', 'pyproject.toml', 'go.mod'];
|
|
5
|
+
function getRegistryPath() {
|
|
6
|
+
return path.join(getPilotDir(), 'projects.json');
|
|
7
|
+
}
|
|
8
|
+
export async function loadRegistry() {
|
|
9
|
+
try {
|
|
10
|
+
const content = await fs.readFile(getRegistryPath(), 'utf-8');
|
|
11
|
+
return JSON.parse(content);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return { scanRoots: [], detectBy: DEFAULT_DETECT_BY, projects: {} };
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
async function saveRegistry(registry) {
|
|
18
|
+
const content = JSON.stringify(registry, null, 2) + '\n';
|
|
19
|
+
await fs.writeFile(getRegistryPath(), content);
|
|
20
|
+
}
|
|
21
|
+
export async function addProject(name, projectPath, description) {
|
|
22
|
+
const registry = await loadRegistry();
|
|
23
|
+
registry.projects[name] = {
|
|
24
|
+
path: projectPath,
|
|
25
|
+
description,
|
|
26
|
+
lastUsed: new Date().toISOString(),
|
|
27
|
+
};
|
|
28
|
+
await saveRegistry(registry);
|
|
29
|
+
}
|
|
30
|
+
export async function removeProject(name) {
|
|
31
|
+
const registry = await loadRegistry();
|
|
32
|
+
if (!(name in registry.projects))
|
|
33
|
+
return false;
|
|
34
|
+
delete registry.projects[name];
|
|
35
|
+
await saveRegistry(registry);
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
export async function listProjects() {
|
|
39
|
+
const registry = await loadRegistry();
|
|
40
|
+
return registry.projects;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 지정된 루트 디렉토리들을 스캔하여 프로젝트를 자동 감지한다.
|
|
44
|
+
*/
|
|
45
|
+
export async function scanProjects(roots) {
|
|
46
|
+
const registry = await loadRegistry();
|
|
47
|
+
const detected = {};
|
|
48
|
+
for (const root of roots) {
|
|
49
|
+
const resolvedRoot = path.resolve(root);
|
|
50
|
+
let entries;
|
|
51
|
+
try {
|
|
52
|
+
entries = await fs.readdir(resolvedRoot, { withFileTypes: true });
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
for (const entry of entries) {
|
|
58
|
+
if (!entry.isDirectory() || entry.name.startsWith('.'))
|
|
59
|
+
continue;
|
|
60
|
+
const dirPath = path.join(resolvedRoot, entry.name);
|
|
61
|
+
const isProject = await detectProject(dirPath, registry.detectBy);
|
|
62
|
+
if (isProject) {
|
|
63
|
+
const name = entry.name;
|
|
64
|
+
if (!(name in registry.projects)) {
|
|
65
|
+
registry.projects[name] = { path: dirPath, lastUsed: new Date().toISOString() };
|
|
66
|
+
detected[name] = dirPath;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// scanRoots에 추가
|
|
71
|
+
if (!registry.scanRoots.includes(resolvedRoot)) {
|
|
72
|
+
registry.scanRoots.push(resolvedRoot);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
await saveRegistry(registry);
|
|
76
|
+
return detected;
|
|
77
|
+
}
|
|
78
|
+
async function detectProject(dirPath, markers) {
|
|
79
|
+
for (const marker of markers) {
|
|
80
|
+
try {
|
|
81
|
+
await fs.access(path.join(dirPath, marker));
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// 다음 마커 시도
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* 사용자 메시지에서 프로젝트를 매칭한다.
|
|
92
|
+
* 우선순위: 정확한 이름 → 절대경로 → fuzzy match
|
|
93
|
+
*/
|
|
94
|
+
export async function resolveProject(query) {
|
|
95
|
+
const registry = await loadRegistry();
|
|
96
|
+
const projects = registry.projects;
|
|
97
|
+
// 1. 정확한 이름 매칭
|
|
98
|
+
if (query in projects) {
|
|
99
|
+
return { name: query, path: projects[query].path };
|
|
100
|
+
}
|
|
101
|
+
// 2. 절대경로 포함 여부
|
|
102
|
+
if (query.startsWith('/') || query.startsWith('~')) {
|
|
103
|
+
return { name: path.basename(query), path: path.resolve(query) };
|
|
104
|
+
}
|
|
105
|
+
// 3. Fuzzy match (부분 문자열)
|
|
106
|
+
const lowerQuery = query.toLowerCase();
|
|
107
|
+
for (const [name, entry] of Object.entries(projects)) {
|
|
108
|
+
if (name.toLowerCase().includes(lowerQuery) || lowerQuery.includes(name.toLowerCase())) {
|
|
109
|
+
return { name, path: entry.path };
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
export async function touchProject(name) {
|
|
115
|
+
const registry = await loadRegistry();
|
|
116
|
+
if (name in registry.projects) {
|
|
117
|
+
registry.projects[name].lastUsed = new Date().toISOString();
|
|
118
|
+
await saveRegistry(registry);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/agent/project.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { type WorktreeInfo } from './worktree.js';
|
|
2
|
+
export type TaskStatus = 'queued' | 'running' | 'waiting_approval' | 'completed' | 'failed' | 'cancelled';
|
|
3
|
+
export interface Task {
|
|
4
|
+
id: string;
|
|
5
|
+
status: TaskStatus;
|
|
6
|
+
project: string | null;
|
|
7
|
+
projectPath?: string;
|
|
8
|
+
command: string;
|
|
9
|
+
threadId?: string;
|
|
10
|
+
channelId: string;
|
|
11
|
+
userId: string;
|
|
12
|
+
createdAt: Date;
|
|
13
|
+
startedAt: Date | null;
|
|
14
|
+
completedAt: Date | null;
|
|
15
|
+
result?: string;
|
|
16
|
+
error?: string;
|
|
17
|
+
worktree?: WorktreeInfo;
|
|
18
|
+
}
|
|
19
|
+
export type TaskHandler = (task: Task) => Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Task queue with project-based parallel execution.
|
|
22
|
+
* - Different projects run in parallel
|
|
23
|
+
* - Same project tasks run sequentially
|
|
24
|
+
* - Null-project tasks (Notion, browser) run in parallel with everything
|
|
25
|
+
* - Max concurrent limit to respect Claude CLI rate limits
|
|
26
|
+
*/
|
|
27
|
+
export declare class TaskQueue {
|
|
28
|
+
private queue;
|
|
29
|
+
private runningTasks;
|
|
30
|
+
private handler;
|
|
31
|
+
private maxConcurrent;
|
|
32
|
+
private worktreeEnabled;
|
|
33
|
+
constructor(maxConcurrent?: number, worktreeEnabled?: boolean);
|
|
34
|
+
onTask(handler: TaskHandler): void;
|
|
35
|
+
enqueue(params: {
|
|
36
|
+
command: string;
|
|
37
|
+
project?: string;
|
|
38
|
+
projectPath?: string;
|
|
39
|
+
channelId: string;
|
|
40
|
+
userId: string;
|
|
41
|
+
threadId?: string;
|
|
42
|
+
}): Task;
|
|
43
|
+
private processNext;
|
|
44
|
+
/**
|
|
45
|
+
* Finds the next task that can run based on project parallelism rules.
|
|
46
|
+
* With worktree enabled, same-project tasks can run in parallel via worktrees.
|
|
47
|
+
*/
|
|
48
|
+
private findNextRunnable;
|
|
49
|
+
private executeTask;
|
|
50
|
+
cancel(taskId: string): boolean;
|
|
51
|
+
getStatus(): {
|
|
52
|
+
running: Task[];
|
|
53
|
+
queued: Task[];
|
|
54
|
+
completed: Task[];
|
|
55
|
+
};
|
|
56
|
+
getTask(taskId: string): Task | undefined;
|
|
57
|
+
getQueueLength(): number;
|
|
58
|
+
getRunningCount(): number;
|
|
59
|
+
formatStatus(): string;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../../src/agent/queue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkC,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAElF,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,SAAS,GAAG,kBAAkB,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;AAE1G,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,UAAU,CAAC;IACnB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,GAAG,IAAI,CAAC;IACvB,WAAW,EAAE,IAAI,GAAG,IAAI,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB;AAED,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAQxD;;;;;;GAMG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,YAAY,CAAwB;IAC5C,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,eAAe,CAAU;gBAErB,aAAa,GAAE,MAAU,EAAE,eAAe,GAAE,OAAe;IAKvE,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAIlC,OAAO,CAAC,MAAM,EAAE;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,IAAI;YAoBM,WAAW;IAuBzB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;YAsBV,WAAW;IAoCzB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAQ/B,SAAS,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAAC,MAAM,EAAE,IAAI,EAAE,CAAC;QAAC,SAAS,EAAE,IAAI,EAAE,CAAA;KAAE;IAQnE,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS;IAIzC,cAAc,IAAI,MAAM;IAIxB,eAAe,IAAI,MAAM;IAIzB,YAAY,IAAI,MAAM;CAqBvB"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { createWorktree, removeWorktree } from './worktree.js';
|
|
2
|
+
let taskCounter = 0;
|
|
3
|
+
function generateTaskId() {
|
|
4
|
+
return `task-${Date.now()}-${++taskCounter}`;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Task queue with project-based parallel execution.
|
|
8
|
+
* - Different projects run in parallel
|
|
9
|
+
* - Same project tasks run sequentially
|
|
10
|
+
* - Null-project tasks (Notion, browser) run in parallel with everything
|
|
11
|
+
* - Max concurrent limit to respect Claude CLI rate limits
|
|
12
|
+
*/
|
|
13
|
+
export class TaskQueue {
|
|
14
|
+
queue = [];
|
|
15
|
+
runningTasks = new Set();
|
|
16
|
+
handler = null;
|
|
17
|
+
maxConcurrent;
|
|
18
|
+
worktreeEnabled;
|
|
19
|
+
constructor(maxConcurrent = 3, worktreeEnabled = false) {
|
|
20
|
+
this.maxConcurrent = maxConcurrent;
|
|
21
|
+
this.worktreeEnabled = worktreeEnabled;
|
|
22
|
+
}
|
|
23
|
+
onTask(handler) {
|
|
24
|
+
this.handler = handler;
|
|
25
|
+
}
|
|
26
|
+
enqueue(params) {
|
|
27
|
+
const task = {
|
|
28
|
+
id: generateTaskId(),
|
|
29
|
+
status: 'queued',
|
|
30
|
+
project: params.project ?? null,
|
|
31
|
+
projectPath: params.projectPath,
|
|
32
|
+
command: params.command,
|
|
33
|
+
channelId: params.channelId,
|
|
34
|
+
userId: params.userId,
|
|
35
|
+
threadId: params.threadId,
|
|
36
|
+
createdAt: new Date(),
|
|
37
|
+
startedAt: null,
|
|
38
|
+
completedAt: null,
|
|
39
|
+
};
|
|
40
|
+
this.queue.push(task);
|
|
41
|
+
this.processNext();
|
|
42
|
+
return task;
|
|
43
|
+
}
|
|
44
|
+
async processNext() {
|
|
45
|
+
if (this.runningTasks.size >= this.maxConcurrent)
|
|
46
|
+
return;
|
|
47
|
+
const nextTask = this.findNextRunnable();
|
|
48
|
+
if (!nextTask)
|
|
49
|
+
return;
|
|
50
|
+
this.runningTasks.add(nextTask);
|
|
51
|
+
nextTask.status = 'running';
|
|
52
|
+
nextTask.startedAt = new Date();
|
|
53
|
+
// Run async without blocking processNext
|
|
54
|
+
this.executeTask(nextTask).finally(() => {
|
|
55
|
+
this.runningTasks.delete(nextTask);
|
|
56
|
+
// Try to start more tasks
|
|
57
|
+
this.processNext();
|
|
58
|
+
});
|
|
59
|
+
// Try to start more parallel tasks immediately
|
|
60
|
+
if (this.runningTasks.size < this.maxConcurrent) {
|
|
61
|
+
this.processNext();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Finds the next task that can run based on project parallelism rules.
|
|
66
|
+
* With worktree enabled, same-project tasks can run in parallel via worktrees.
|
|
67
|
+
*/
|
|
68
|
+
findNextRunnable() {
|
|
69
|
+
const runningProjects = new Set();
|
|
70
|
+
for (const task of this.runningTasks) {
|
|
71
|
+
if (task.project)
|
|
72
|
+
runningProjects.add(task.project);
|
|
73
|
+
}
|
|
74
|
+
for (const task of this.queue) {
|
|
75
|
+
if (task.status !== 'queued')
|
|
76
|
+
continue;
|
|
77
|
+
// Null-project tasks can always run (no project conflict)
|
|
78
|
+
if (task.project === null)
|
|
79
|
+
return task;
|
|
80
|
+
// No conflict - run directly
|
|
81
|
+
if (!runningProjects.has(task.project))
|
|
82
|
+
return task;
|
|
83
|
+
// Worktree mode: allow same-project if projectPath is available
|
|
84
|
+
if (this.worktreeEnabled && task.projectPath)
|
|
85
|
+
return task;
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
async executeTask(task) {
|
|
90
|
+
// If same project is already running and worktree is enabled, create worktree
|
|
91
|
+
if (this.worktreeEnabled && task.project && task.projectPath) {
|
|
92
|
+
const alreadyRunning = [...this.runningTasks].some((t) => t !== task && t.project === task.project && !t.worktree);
|
|
93
|
+
if (alreadyRunning) {
|
|
94
|
+
try {
|
|
95
|
+
task.worktree = await createWorktree(task.projectPath, task.id);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// Worktree creation failed - fall back to sequential wait handled elsewhere
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
if (this.handler) {
|
|
104
|
+
await this.handler(task);
|
|
105
|
+
}
|
|
106
|
+
task.status = 'completed';
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
task.status = 'failed';
|
|
110
|
+
task.error = err instanceof Error ? err.message : String(err);
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
task.completedAt = new Date();
|
|
114
|
+
// Clean up worktree
|
|
115
|
+
if (task.worktree && task.projectPath) {
|
|
116
|
+
try {
|
|
117
|
+
await removeWorktree(task.projectPath, task.worktree.path, task.worktree.branch);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
// Best-effort cleanup
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
cancel(taskId) {
|
|
126
|
+
const task = this.queue.find((t) => t.id === taskId && t.status === 'queued');
|
|
127
|
+
if (!task)
|
|
128
|
+
return false;
|
|
129
|
+
task.status = 'cancelled';
|
|
130
|
+
task.completedAt = new Date();
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
getStatus() {
|
|
134
|
+
return {
|
|
135
|
+
running: [...this.runningTasks],
|
|
136
|
+
queued: this.queue.filter((t) => t.status === 'queued'),
|
|
137
|
+
completed: this.queue.filter((t) => t.status === 'completed' || t.status === 'failed'),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
getTask(taskId) {
|
|
141
|
+
return this.queue.find((t) => t.id === taskId);
|
|
142
|
+
}
|
|
143
|
+
getQueueLength() {
|
|
144
|
+
return this.queue.filter((t) => t.status === 'queued').length;
|
|
145
|
+
}
|
|
146
|
+
getRunningCount() {
|
|
147
|
+
return this.runningTasks.size;
|
|
148
|
+
}
|
|
149
|
+
formatStatus() {
|
|
150
|
+
const { running, queued } = this.getStatus();
|
|
151
|
+
const lines = ['Task Queue:'];
|
|
152
|
+
for (const task of running) {
|
|
153
|
+
const elapsed = Math.floor((Date.now() - (task.startedAt?.getTime() ?? Date.now())) / 1000);
|
|
154
|
+
const proj = task.project ? `[${task.project}] ` : '';
|
|
155
|
+
lines.push(` [${task.id}] running - ${proj}${task.command} (${elapsed}s)`);
|
|
156
|
+
}
|
|
157
|
+
for (const task of queued) {
|
|
158
|
+
const proj = task.project ? `[${task.project}] ` : '';
|
|
159
|
+
lines.push(` [${task.id}] queued - ${proj}${task.command}`);
|
|
160
|
+
}
|
|
161
|
+
if (running.length === 0 && queued.length === 0) {
|
|
162
|
+
lines.push(' No pending tasks.');
|
|
163
|
+
}
|
|
164
|
+
return lines.join('\n');
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.js","sourceRoot":"","sources":["../../src/agent/queue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type SafetyLevel = 'safe' | 'moderate' | 'dangerous';
|
|
2
|
+
export declare function classifySafety(action: string): SafetyLevel;
|
|
3
|
+
/**
|
|
4
|
+
* 승인 대기 상태를 관리한다.
|
|
5
|
+
*/
|
|
6
|
+
export interface PendingApproval {
|
|
7
|
+
taskId: string;
|
|
8
|
+
action: string;
|
|
9
|
+
resolve: (approved: boolean) => void;
|
|
10
|
+
timer: ReturnType<typeof setTimeout>;
|
|
11
|
+
}
|
|
12
|
+
export declare class ApprovalManager {
|
|
13
|
+
private pending;
|
|
14
|
+
/**
|
|
15
|
+
* 승인을 요청하고, 승인/거부/타임아웃까지 대기한다.
|
|
16
|
+
*/
|
|
17
|
+
requestApproval(taskId: string, action: string, timeoutMs: number): Promise<boolean>;
|
|
18
|
+
/**
|
|
19
|
+
* 사용자의 승인/거부 응답을 처리한다.
|
|
20
|
+
*/
|
|
21
|
+
handleResponse(taskId: string, approved: boolean): boolean;
|
|
22
|
+
hasPending(taskId: string): boolean;
|
|
23
|
+
getPendingCount(): number;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=safety.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safety.d.ts","sourceRoot":"","sources":["../../src/agent/safety.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,UAAU,GAAG,WAAW,CAAC;AAmC5D,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,CAc1D;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;IACrC,KAAK,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;CACtC;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,OAAO,CAAsC;IAErD;;OAEG;IACH,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWpF;;OAEG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO;IAU1D,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAInC,eAAe,IAAI,MAAM;CAG1B"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 작업 계획의 위험도를 분류한다.
|
|
3
|
+
*/
|
|
4
|
+
const DANGEROUS_PATTERNS = [
|
|
5
|
+
/\bgit\s+push\b/,
|
|
6
|
+
/\bgit\s+push\s+--force\b/,
|
|
7
|
+
/\bgit\s+reset\s+--hard\b/,
|
|
8
|
+
/\brm\s+(-[a-zA-Z]*r|-[a-zA-Z]*f)/, // rm -r, rm -f, rm -rf
|
|
9
|
+
/\bdrop\s+(table|database)\b/i,
|
|
10
|
+
/\btruncate\s+table\b/i,
|
|
11
|
+
/\bformat\s/,
|
|
12
|
+
/\bdeploy\b/,
|
|
13
|
+
/\bnpm\s+publish\b/,
|
|
14
|
+
/\bsend\s*(email|mail|message)\b/i,
|
|
15
|
+
/\bsubmit\s*(form)\b/i,
|
|
16
|
+
];
|
|
17
|
+
const MODERATE_PATTERNS = [
|
|
18
|
+
/\bgit\s+commit\b/,
|
|
19
|
+
/\bgit\s+merge\b/,
|
|
20
|
+
/\bgit\s+checkout\b/,
|
|
21
|
+
/\bnpm\s+install\b/,
|
|
22
|
+
/\bmkdir\b/,
|
|
23
|
+
/\btouch\b/,
|
|
24
|
+
/\bcp\b/,
|
|
25
|
+
/\bmv\b/,
|
|
26
|
+
/\bwrite\b/i,
|
|
27
|
+
/\bcreate\b/i,
|
|
28
|
+
/\bmodify\b/i,
|
|
29
|
+
/\bedit\b/i,
|
|
30
|
+
];
|
|
31
|
+
export function classifySafety(action) {
|
|
32
|
+
for (const pattern of DANGEROUS_PATTERNS) {
|
|
33
|
+
if (pattern.test(action)) {
|
|
34
|
+
return 'dangerous';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
for (const pattern of MODERATE_PATTERNS) {
|
|
38
|
+
if (pattern.test(action)) {
|
|
39
|
+
return 'moderate';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return 'safe';
|
|
43
|
+
}
|
|
44
|
+
export class ApprovalManager {
|
|
45
|
+
pending = new Map();
|
|
46
|
+
/**
|
|
47
|
+
* 승인을 요청하고, 승인/거부/타임아웃까지 대기한다.
|
|
48
|
+
*/
|
|
49
|
+
requestApproval(taskId, action, timeoutMs) {
|
|
50
|
+
return new Promise((resolve) => {
|
|
51
|
+
const timer = setTimeout(() => {
|
|
52
|
+
this.pending.delete(taskId);
|
|
53
|
+
resolve(false); // 타임아웃 → 거부 처리
|
|
54
|
+
}, timeoutMs);
|
|
55
|
+
this.pending.set(taskId, { taskId, action, resolve, timer });
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* 사용자의 승인/거부 응답을 처리한다.
|
|
60
|
+
*/
|
|
61
|
+
handleResponse(taskId, approved) {
|
|
62
|
+
const entry = this.pending.get(taskId);
|
|
63
|
+
if (!entry)
|
|
64
|
+
return false;
|
|
65
|
+
clearTimeout(entry.timer);
|
|
66
|
+
this.pending.delete(taskId);
|
|
67
|
+
entry.resolve(approved);
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
hasPending(taskId) {
|
|
71
|
+
return this.pending.has(taskId);
|
|
72
|
+
}
|
|
73
|
+
getPendingCount() {
|
|
74
|
+
return this.pending.size;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=safety.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safety.js","sourceRoot":"","sources":["../../src/agent/safety.ts"],"names":[],"mappings":"AAEA;;GAEG;AAEH,MAAM,kBAAkB,GAAG;IACzB,gBAAgB;IAChB,0BAA0B;IAC1B,0BAA0B;IAC1B,kCAAkC,EAAI,uBAAuB;IAC7D,8BAA8B;IAC9B,uBAAuB;IACvB,YAAY;IACZ,YAAY;IACZ,mBAAmB;IACnB,kCAAkC;IAClC,sBAAsB;CACvB,CAAC;AAEF,MAAM,iBAAiB,GAAG;IACxB,kBAAkB;IAClB,iBAAiB;IACjB,oBAAoB;IACpB,mBAAmB;IACnB,WAAW;IACX,WAAW;IACX,QAAQ;IACR,QAAQ;IACR,YAAY;IACZ,aAAa;IACb,aAAa;IACb,WAAW;CACZ,CAAC;AAEF,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,KAAK,MAAM,OAAO,IAAI,kBAAkB,EAAE,CAAC;QACzC,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YACzB,OAAO,WAAW,CAAC;QACrB,CAAC;IACH,CAAC;IAED,KAAK,MAAM,OAAO,IAAI,iBAAiB,EAAE,CAAC;QACxC,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YACzB,OAAO,UAAU,CAAC;QACpB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAYD,MAAM,OAAO,eAAe;IAClB,OAAO,GAAG,IAAI,GAAG,EAA2B,CAAC;IAErD;;OAEG;IACH,eAAe,CAAC,MAAc,EAAE,MAAc,EAAE,SAAiB;QAC/D,OAAO,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,EAAE;YACtC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC5B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBAC5B,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,eAAe;YACjC,CAAC,EAAE,SAAS,CAAC,CAAC;YAEd,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,cAAc,CAAC,MAAc,EAAE,QAAiB;QAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK;YAAE,OAAO,KAAK,CAAC;QAEzB,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC5B,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,UAAU,CAAC,MAAc;QACvB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAClC,CAAC;IAED,eAAe;QACb,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;CACF"}
|