thatgfsj-code 0.2.1
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/.patches/0001-fix-repl-replace-readline-with-inquirer-input-for-ke.patch +279 -0
- package/.patches/0002-fix-repl-stream-AI-output-directly-to-stdout-so-term.patch +564 -0
- package/.patches/0003-fix-session-break-the-hallucination-loop-in-assistan.patch +194 -0
- package/.patches/0004-chore-release-bump-version-to-0.2.1.patch +24 -0
- package/LICENSE +21 -0
- package/README.md +100 -0
- package/ROADMAP.md +107 -0
- package/dist/agent/core.d.ts +56 -0
- package/dist/agent/core.d.ts.map +1 -0
- package/dist/agent/core.js +142 -0
- package/dist/agent/core.js.map +1 -0
- package/dist/agent/index.d.ts +8 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +8 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/intent.d.ts +36 -0
- package/dist/agent/intent.d.ts.map +1 -0
- package/dist/agent/intent.js +146 -0
- package/dist/agent/intent.js.map +1 -0
- package/dist/agent/streaming.d.ts +50 -0
- package/dist/agent/streaming.d.ts.map +1 -0
- package/dist/agent/streaming.js +110 -0
- package/dist/agent/streaming.js.map +1 -0
- package/dist/core/ai-engine.d.ts +59 -0
- package/dist/core/ai-engine.d.ts.map +1 -0
- package/dist/core/ai-engine.js +378 -0
- package/dist/core/ai-engine.js.map +1 -0
- package/dist/core/cli.d.ts +21 -0
- package/dist/core/cli.d.ts.map +1 -0
- package/dist/core/cli.js +143 -0
- package/dist/core/cli.js.map +1 -0
- package/dist/core/config.d.ts +38 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +129 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/context-compactor.d.ts +54 -0
- package/dist/core/context-compactor.d.ts.map +1 -0
- package/dist/core/context-compactor.js +197 -0
- package/dist/core/context-compactor.js.map +1 -0
- package/dist/core/hooks.d.ts +75 -0
- package/dist/core/hooks.d.ts.map +1 -0
- package/dist/core/hooks.js +146 -0
- package/dist/core/hooks.js.map +1 -0
- package/dist/core/permissions.d.ts +52 -0
- package/dist/core/permissions.d.ts.map +1 -0
- package/dist/core/permissions.js +237 -0
- package/dist/core/permissions.js.map +1 -0
- package/dist/core/session.d.ts +54 -0
- package/dist/core/session.d.ts.map +1 -0
- package/dist/core/session.js +147 -0
- package/dist/core/session.js.map +1 -0
- package/dist/core/skills.d.ts +60 -0
- package/dist/core/skills.d.ts.map +1 -0
- package/dist/core/skills.js +175 -0
- package/dist/core/skills.js.map +1 -0
- package/dist/core/state.d.ts +60 -0
- package/dist/core/state.d.ts.map +1 -0
- package/dist/core/state.js +106 -0
- package/dist/core/state.js.map +1 -0
- package/dist/core/subagent.d.ts +68 -0
- package/dist/core/subagent.d.ts.map +1 -0
- package/dist/core/subagent.js +142 -0
- package/dist/core/subagent.js.map +1 -0
- package/dist/core/system-prompt.d.ts +40 -0
- package/dist/core/system-prompt.d.ts.map +1 -0
- package/dist/core/system-prompt.js +138 -0
- package/dist/core/system-prompt.js.map +1 -0
- package/dist/core/tool-registry.d.ts +53 -0
- package/dist/core/tool-registry.d.ts.map +1 -0
- package/dist/core/tool-registry.js +138 -0
- package/dist/core/tool-registry.js.map +1 -0
- package/dist/core/types.d.ts +206 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +127 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +481 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/client.d.ts +83 -0
- package/dist/mcp/client.d.ts.map +1 -0
- package/dist/mcp/client.js +267 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/repl/index.d.ts +8 -0
- package/dist/repl/index.d.ts.map +1 -0
- package/dist/repl/index.js +8 -0
- package/dist/repl/index.js.map +1 -0
- package/dist/repl/input.d.ts +61 -0
- package/dist/repl/input.d.ts.map +1 -0
- package/dist/repl/input.js +127 -0
- package/dist/repl/input.js.map +1 -0
- package/dist/repl/loop.d.ts +53 -0
- package/dist/repl/loop.d.ts.map +1 -0
- package/dist/repl/loop.js +241 -0
- package/dist/repl/loop.js.map +1 -0
- package/dist/repl/output.d.ts +105 -0
- package/dist/repl/output.d.ts.map +1 -0
- package/dist/repl/output.js +197 -0
- package/dist/repl/output.js.map +1 -0
- package/dist/repl/welcome.d.ts +68 -0
- package/dist/repl/welcome.d.ts.map +1 -0
- package/dist/repl/welcome.js +249 -0
- package/dist/repl/welcome.js.map +1 -0
- package/dist/tools/file.d.ts +46 -0
- package/dist/tools/file.d.ts.map +1 -0
- package/dist/tools/file.js +100 -0
- package/dist/tools/file.js.map +1 -0
- package/dist/tools/git.d.ts +52 -0
- package/dist/tools/git.d.ts.map +1 -0
- package/dist/tools/git.js +112 -0
- package/dist/tools/git.js.map +1 -0
- package/dist/tools/index.d.ts +22 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +43 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/search.d.ts +36 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +223 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/shell.d.ts +57 -0
- package/dist/tools/shell.d.ts.map +1 -0
- package/dist/tools/shell.js +153 -0
- package/dist/tools/shell.js.map +1 -0
- package/dist/utils/diff-preview.d.ts +42 -0
- package/dist/utils/diff-preview.d.ts.map +1 -0
- package/dist/utils/diff-preview.js +174 -0
- package/dist/utils/diff-preview.js.map +1 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +8 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/memory.d.ts +81 -0
- package/dist/utils/memory.d.ts.map +1 -0
- package/dist/utils/memory.js +186 -0
- package/dist/utils/memory.js.map +1 -0
- package/dist/utils/project-context.d.ts +62 -0
- package/dist/utils/project-context.d.ts.map +1 -0
- package/dist/utils/project-context.js +197 -0
- package/dist/utils/project-context.js.map +1 -0
- package/docs/API_KEY_GUIDE.md +236 -0
- package/docs/FAQ.md +182 -0
- package/install.bat +63 -0
- package/install.ps1 +238 -0
- package/install.sh +113 -0
- package/package.json +36 -0
- package/src/agent/core.ts +179 -0
- package/src/agent/index.ts +8 -0
- package/src/agent/intent.ts +181 -0
- package/src/agent/streaming.ts +132 -0
- package/src/core/ai-engine.ts +437 -0
- package/src/core/cli.ts +171 -0
- package/src/core/config.ts +147 -0
- package/src/core/context-compactor.ts +245 -0
- package/src/core/hooks.ts +196 -0
- package/src/core/permissions.ts +308 -0
- package/src/core/session.ts +165 -0
- package/src/core/skills.ts +208 -0
- package/src/core/state.ts +120 -0
- package/src/core/subagent.ts +195 -0
- package/src/core/system-prompt.ts +163 -0
- package/src/core/tool-registry.ts +157 -0
- package/src/core/types.ts +280 -0
- package/src/index.ts +544 -0
- package/src/mcp/client.ts +330 -0
- package/src/repl/index.ts +8 -0
- package/src/repl/input.ts +139 -0
- package/src/repl/loop.ts +280 -0
- package/src/repl/output.ts +222 -0
- package/src/repl/welcome.ts +296 -0
- package/src/tools/file.ts +117 -0
- package/src/tools/git.ts +132 -0
- package/src/tools/index.ts +48 -0
- package/src/tools/search.ts +263 -0
- package/src/tools/shell.ts +181 -0
- package/src/utils/diff-preview.ts +202 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/memory.ts +223 -0
- package/src/utils/project-context.ts +207 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S03: Permissions System
|
|
3
|
+
* 6-stage permission pipeline for tool execution
|
|
4
|
+
* Core principle: permissions are first-class citizens, not an afterthought
|
|
5
|
+
*/
|
|
6
|
+
import { ToolContext } from './types.js';
|
|
7
|
+
export type PermissionMode = 'accept' | 'deny' | 'ask';
|
|
8
|
+
export type PermissionLevel = 'none' | 'low' | 'medium' | 'high' | 'critical';
|
|
9
|
+
export interface PermissionResult {
|
|
10
|
+
allowed: boolean;
|
|
11
|
+
reason: string;
|
|
12
|
+
level: PermissionLevel;
|
|
13
|
+
requiresConfirmation: boolean;
|
|
14
|
+
stage: 1 | 2 | 3 | 4 | 5 | 6;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Permission rule — pattern-based allow/deny rules
|
|
18
|
+
*/
|
|
19
|
+
export interface PermissionRule {
|
|
20
|
+
pattern: RegExp;
|
|
21
|
+
action: 'allow' | 'deny';
|
|
22
|
+
reason: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* S03: Permission Checker — 6-stage pipeline
|
|
26
|
+
*/
|
|
27
|
+
export declare class PermissionChecker {
|
|
28
|
+
private mode;
|
|
29
|
+
private rules;
|
|
30
|
+
private workspaceRoot;
|
|
31
|
+
private static BLOCKED_PATTERNS;
|
|
32
|
+
private static CONFIRM_REQUIRED;
|
|
33
|
+
private static BORDERLINE_PATTERNS;
|
|
34
|
+
constructor(workspaceRoot?: string);
|
|
35
|
+
/**
|
|
36
|
+
* S03: 6-Stage Permission Pipeline
|
|
37
|
+
* Every tool execution passes through all 6 stages
|
|
38
|
+
*/
|
|
39
|
+
check(toolName: string, params: Record<string, any>, ctx: ToolContext): Promise<PermissionResult>;
|
|
40
|
+
private stage1PatternBlock;
|
|
41
|
+
private stage2Rules;
|
|
42
|
+
private stage3PathSandbox;
|
|
43
|
+
private stage4AIClassify;
|
|
44
|
+
private stage5Confirmation;
|
|
45
|
+
setMode(mode: PermissionMode): void;
|
|
46
|
+
getMode(): PermissionMode;
|
|
47
|
+
addRule(pattern: RegExp, action: 'allow' | 'deny', reason: string): void;
|
|
48
|
+
clearRules(): void;
|
|
49
|
+
setWorkspaceRoot(path: string): void;
|
|
50
|
+
}
|
|
51
|
+
export declare function printPermissionResult(result: PermissionResult, command?: string): void;
|
|
52
|
+
//# sourceMappingURL=permissions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../src/core/permissions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,WAAW,EAAgB,MAAM,YAAY,CAAC;AAIvD,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,CAAC;AACvD,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;AAE9E,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,eAAe,CAAC;IACvB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,IAAI,CAAyB;IACrC,OAAO,CAAC,KAAK,CAAwB;IACrC,OAAO,CAAC,aAAa,CAAS;IAG9B,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAgB7B;IAGF,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAmB7B;IAGF,OAAO,CAAC,MAAM,CAAC,mBAAmB,CAWhC;gBAEU,aAAa,GAAE,MAAsB;IAIjD;;;OAGG;IACG,KAAK,CACT,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,gBAAgB,CAAC;IAmC5B,OAAO,CAAC,kBAAkB;IAmB1B,OAAO,CAAC,WAAW;IAkBnB,OAAO,CAAC,iBAAiB;YAoBX,gBAAgB;IA0B9B,OAAO,CAAC,kBAAkB;IA+C1B,OAAO,CAAC,IAAI,EAAE,cAAc;IAI5B,OAAO,IAAI,cAAc;IAIzB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,EAAE,MAAM,EAAE,MAAM;IAIjE,UAAU;IAIV,gBAAgB,CAAC,IAAI,EAAE,MAAM;CAG9B;AAID,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE,MAAM,QAa/E"}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S03: Permissions System
|
|
3
|
+
* 6-stage permission pipeline for tool execution
|
|
4
|
+
* Core principle: permissions are first-class citizens, not an afterthought
|
|
5
|
+
*/
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
/**
|
|
8
|
+
* S03: Permission Checker — 6-stage pipeline
|
|
9
|
+
*/
|
|
10
|
+
export class PermissionChecker {
|
|
11
|
+
mode = 'ask';
|
|
12
|
+
rules = [];
|
|
13
|
+
workspaceRoot;
|
|
14
|
+
// Stage 1: Blocked patterns
|
|
15
|
+
static BLOCKED_PATTERNS = [
|
|
16
|
+
/^rm\s+-rf\s+\//i,
|
|
17
|
+
/^rm\s+-rf\s+\$HOME/i,
|
|
18
|
+
/^rm\s+-rf\s+%USERPROFILE%/i,
|
|
19
|
+
/^del\s+\/f\s+\/s\s+\/q/i,
|
|
20
|
+
/^format\s+[a-z]:/i,
|
|
21
|
+
/^mkfs/i,
|
|
22
|
+
/^dd\s+if=/i,
|
|
23
|
+
/^shred/i,
|
|
24
|
+
/>\s*\/dev\/sda/i,
|
|
25
|
+
/^curl\s+.*\||^wget\s+.*\|/i,
|
|
26
|
+
/^eval\s+/i,
|
|
27
|
+
/^exec\s+/i,
|
|
28
|
+
/base64\s+-d\s+.*\|/i,
|
|
29
|
+
/\$\(.*\)/i,
|
|
30
|
+
/`.*`/i,
|
|
31
|
+
];
|
|
32
|
+
// Stage 2: Commands needing confirmation
|
|
33
|
+
static CONFIRM_REQUIRED = [
|
|
34
|
+
'rm -rf',
|
|
35
|
+
'rmdir',
|
|
36
|
+
'del /s /q',
|
|
37
|
+
'format',
|
|
38
|
+
'mkfs',
|
|
39
|
+
'dd',
|
|
40
|
+
'shutdown',
|
|
41
|
+
'init 0',
|
|
42
|
+
'init 6',
|
|
43
|
+
'poweroff',
|
|
44
|
+
'reboot',
|
|
45
|
+
'pkill',
|
|
46
|
+
'killall',
|
|
47
|
+
'mv .* /tmp',
|
|
48
|
+
'chmod 777',
|
|
49
|
+
'chmod -R 777',
|
|
50
|
+
'git push --force',
|
|
51
|
+
'git push -f',
|
|
52
|
+
];
|
|
53
|
+
// Stage 4: AI borderline commands (use LLM to classify)
|
|
54
|
+
static BORDERLINE_PATTERNS = [
|
|
55
|
+
/curl\s+https?:\/\//i,
|
|
56
|
+
/wget\s+/i,
|
|
57
|
+
/npm\s+install\s+-g/i,
|
|
58
|
+
/pip\s+install\s+/i,
|
|
59
|
+
/yarn\s+add\s+/i,
|
|
60
|
+
/sudo\s+/i,
|
|
61
|
+
/chown\s+/i,
|
|
62
|
+
/chmod\s+[67]/i,
|
|
63
|
+
/^git\s+reset/i,
|
|
64
|
+
/^git\s+clean/i,
|
|
65
|
+
];
|
|
66
|
+
constructor(workspaceRoot = process.cwd()) {
|
|
67
|
+
this.workspaceRoot = workspaceRoot;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* S03: 6-Stage Permission Pipeline
|
|
71
|
+
* Every tool execution passes through all 6 stages
|
|
72
|
+
*/
|
|
73
|
+
async check(toolName, params, ctx) {
|
|
74
|
+
// Stage 1: Pattern block — reject known dangerous commands immediately
|
|
75
|
+
const stage1 = this.stage1PatternBlock(toolName, params);
|
|
76
|
+
if (!stage1.allowed)
|
|
77
|
+
return stage1;
|
|
78
|
+
// Stage 2: Permission rules — check user-defined allow/deny rules
|
|
79
|
+
const stage2 = this.stage2Rules(toolName, params);
|
|
80
|
+
if (!stage2.allowed)
|
|
81
|
+
return stage2;
|
|
82
|
+
// Stage 3: Path sandboxing — prevent workspace escape
|
|
83
|
+
const stage3 = this.stage3PathSandbox(toolName, params);
|
|
84
|
+
if (!stage3.allowed)
|
|
85
|
+
return stage3;
|
|
86
|
+
// Stage 4: AI classification for borderline cases
|
|
87
|
+
const stage4 = await this.stage4AIClassify(toolName, params, ctx);
|
|
88
|
+
if (!stage4.allowed)
|
|
89
|
+
return stage4;
|
|
90
|
+
// Stage 5: User confirmation for medium/high risk
|
|
91
|
+
const stage5 = this.stage5Confirmation(toolName, params, ctx);
|
|
92
|
+
if (stage5.requiresConfirmation) {
|
|
93
|
+
return stage5;
|
|
94
|
+
}
|
|
95
|
+
// Stage 6: Pass through
|
|
96
|
+
return {
|
|
97
|
+
allowed: true,
|
|
98
|
+
reason: 'Allowed',
|
|
99
|
+
level: stage5.level,
|
|
100
|
+
requiresConfirmation: false,
|
|
101
|
+
stage: 6
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
// Stage 1: Pattern block
|
|
105
|
+
stage1PatternBlock(toolName, params) {
|
|
106
|
+
if (toolName !== 'shell')
|
|
107
|
+
return { allowed: true, reason: 'Stage 1: N/A', level: 'none', requiresConfirmation: false, stage: 1 };
|
|
108
|
+
const command = params.command || '';
|
|
109
|
+
for (const pattern of PermissionChecker.BLOCKED_PATTERNS) {
|
|
110
|
+
if (pattern.test(command.trim())) {
|
|
111
|
+
return {
|
|
112
|
+
allowed: false,
|
|
113
|
+
reason: `Blocked: command matches dangerous pattern ${pattern}`,
|
|
114
|
+
level: 'critical',
|
|
115
|
+
requiresConfirmation: false,
|
|
116
|
+
stage: 1
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return { allowed: true, reason: 'Stage 1: Passed pattern check', level: 'none', requiresConfirmation: false, stage: 1 };
|
|
121
|
+
}
|
|
122
|
+
// Stage 2: User-defined rules
|
|
123
|
+
stage2Rules(toolName, params) {
|
|
124
|
+
const command = params.command || '';
|
|
125
|
+
for (const rule of this.rules) {
|
|
126
|
+
if (rule.pattern.test(command)) {
|
|
127
|
+
return {
|
|
128
|
+
allowed: rule.action === 'allow',
|
|
129
|
+
reason: `Rule matched: ${rule.reason}`,
|
|
130
|
+
level: rule.action === 'deny' ? 'high' : 'none',
|
|
131
|
+
requiresConfirmation: false,
|
|
132
|
+
stage: 2
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return { allowed: true, reason: 'Stage 2: No rules matched', level: 'none', requiresConfirmation: false, stage: 2 };
|
|
137
|
+
}
|
|
138
|
+
// Stage 3: Path sandboxing
|
|
139
|
+
stage3PathSandbox(toolName, params) {
|
|
140
|
+
if (toolName !== 'shell' && toolName !== 'file')
|
|
141
|
+
return { allowed: true, reason: 'Stage 3: N/A', level: 'none', requiresConfirmation: false, stage: 3 };
|
|
142
|
+
const path = params.path || params.command || '';
|
|
143
|
+
// Check for path traversal attempts
|
|
144
|
+
if (/^\.\.\//.test(path) || /\%00/.test(path) || /\0/.test(path)) {
|
|
145
|
+
return {
|
|
146
|
+
allowed: false,
|
|
147
|
+
reason: 'Blocked: path traversal attempt detected',
|
|
148
|
+
level: 'high',
|
|
149
|
+
requiresConfirmation: false,
|
|
150
|
+
stage: 3
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
return { allowed: true, reason: 'Stage 3: Path sandbox passed', level: 'none', requiresConfirmation: false, stage: 3 };
|
|
154
|
+
}
|
|
155
|
+
// Stage 4: AI classification for borderline commands
|
|
156
|
+
async stage4AIClassify(toolName, params, ctx) {
|
|
157
|
+
if (toolName !== 'shell')
|
|
158
|
+
return { allowed: true, reason: 'Stage 4: N/A', level: 'none', requiresConfirmation: false, stage: 4 };
|
|
159
|
+
const command = params.command || '';
|
|
160
|
+
// Check if borderline
|
|
161
|
+
const isBorderline = PermissionChecker.BORDERLINE_PATTERNS.some(p => p.test(command));
|
|
162
|
+
if (!isBorderline) {
|
|
163
|
+
return { allowed: true, reason: 'Stage 4: Not borderline', level: 'none', requiresConfirmation: false, stage: 4 };
|
|
164
|
+
}
|
|
165
|
+
// For CLI, mark as medium risk (actual AI classification skipped for perf)
|
|
166
|
+
return {
|
|
167
|
+
allowed: true,
|
|
168
|
+
reason: 'Stage 4: Borderline — escalated to confirmation',
|
|
169
|
+
level: 'medium',
|
|
170
|
+
requiresConfirmation: false,
|
|
171
|
+
stage: 4
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
// Stage 5: User confirmation
|
|
175
|
+
stage5Confirmation(toolName, params, ctx) {
|
|
176
|
+
if (this.mode === 'accept') {
|
|
177
|
+
return { allowed: true, reason: 'Mode: accept all', level: 'none', requiresConfirmation: false, stage: 5 };
|
|
178
|
+
}
|
|
179
|
+
if (this.mode === 'deny') {
|
|
180
|
+
return { allowed: false, reason: 'Mode: deny all', level: 'high', requiresConfirmation: false, stage: 5 };
|
|
181
|
+
}
|
|
182
|
+
// mode === 'ask'
|
|
183
|
+
const command = params.command || '';
|
|
184
|
+
// Critical: auto-deny
|
|
185
|
+
if (/rm\s+-rf/.test(command) && !command.includes('node_modules')) {
|
|
186
|
+
return {
|
|
187
|
+
allowed: false,
|
|
188
|
+
reason: 'Auto-deny: rm -rf without node_modules is too risky',
|
|
189
|
+
level: 'critical',
|
|
190
|
+
requiresConfirmation: false,
|
|
191
|
+
stage: 5
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
// Check confirm required list
|
|
195
|
+
const needsConfirm = PermissionChecker.CONFIRM_REQUIRED.some(cmd => command.toLowerCase().includes(cmd.toLowerCase()));
|
|
196
|
+
if (needsConfirm) {
|
|
197
|
+
return {
|
|
198
|
+
allowed: true,
|
|
199
|
+
reason: 'Requires user confirmation',
|
|
200
|
+
level: 'medium',
|
|
201
|
+
requiresConfirmation: true,
|
|
202
|
+
stage: 5
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
return { allowed: true, reason: 'Stage 5: No confirmation needed', level: 'low', requiresConfirmation: false, stage: 5 };
|
|
206
|
+
}
|
|
207
|
+
// ==================== Config Methods ====================
|
|
208
|
+
setMode(mode) {
|
|
209
|
+
this.mode = mode;
|
|
210
|
+
}
|
|
211
|
+
getMode() {
|
|
212
|
+
return this.mode;
|
|
213
|
+
}
|
|
214
|
+
addRule(pattern, action, reason) {
|
|
215
|
+
this.rules.push({ pattern, action, reason });
|
|
216
|
+
}
|
|
217
|
+
clearRules() {
|
|
218
|
+
this.rules = [];
|
|
219
|
+
}
|
|
220
|
+
setWorkspaceRoot(path) {
|
|
221
|
+
this.workspaceRoot = path;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// ==================== Permission Mode CLI ====================
|
|
225
|
+
export function printPermissionResult(result, command) {
|
|
226
|
+
if (!result.allowed) {
|
|
227
|
+
console.log(chalk.red(`\n🚫 BLOCKED [Stage ${result.stage}]: ${result.reason}`));
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
if (result.requiresConfirmation && command) {
|
|
231
|
+
console.log(chalk.yellow(`\n⚠️ Requires confirmation [Stage ${result.stage}]: ${result.reason}`));
|
|
232
|
+
console.log(chalk.gray(` Command: ${command}`));
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
console.log(chalk.green(`\n✅ Allowed [Stage ${result.stage}]: ${result.reason}`));
|
|
236
|
+
}
|
|
237
|
+
//# sourceMappingURL=permissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../src/core/permissions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Manager - Manages conversation history
|
|
3
|
+
*
|
|
4
|
+
* F4 (anti-[已中断]):
|
|
5
|
+
* - addMessage 拦截含"已中断" / 链形 think 块等污染字符串
|
|
6
|
+
* (之前 AI 在失败重试时会把这些字面写进 history 造成病毒循环)
|
|
7
|
+
* - sanitize() 在 lastMessages 输出到 LLM 前再做一次去噪
|
|
8
|
+
*/
|
|
9
|
+
import { ChatMessage, Session } from './types.js';
|
|
10
|
+
export declare class SessionManager {
|
|
11
|
+
private messages;
|
|
12
|
+
private sessionId;
|
|
13
|
+
private createdAt;
|
|
14
|
+
private droppedCount;
|
|
15
|
+
constructor();
|
|
16
|
+
/**
|
|
17
|
+
* Add a message to the session.
|
|
18
|
+
* Returns true if accepted, false if dropped because it looked polluted.
|
|
19
|
+
*/
|
|
20
|
+
addMessage(role: ChatMessage['role'], content: string): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Add a message WITHOUT any sanitization (for trusted callers, e.g. system prompt)
|
|
23
|
+
*/
|
|
24
|
+
addMessageRaw(role: ChatMessage['role'], content: string): void;
|
|
25
|
+
/**
|
|
26
|
+
* How many polluted messages have we filtered out? Useful for debugging
|
|
27
|
+
* the "AI keeps saying interrupted" loop.
|
|
28
|
+
*/
|
|
29
|
+
getDroppedCount(): number;
|
|
30
|
+
/**
|
|
31
|
+
* Return messages ready to send to the LLM. We additionally dedupe
|
|
32
|
+
* adjacent identical assistant messages (a recovery hack against the
|
|
33
|
+
* "AI repeats the same paragraph each turn" loop).
|
|
34
|
+
*/
|
|
35
|
+
getMessages(): ChatMessage[];
|
|
36
|
+
/**
|
|
37
|
+
* Get message count (raw, includes internal notes)
|
|
38
|
+
*/
|
|
39
|
+
getMessageCount(): number;
|
|
40
|
+
/**
|
|
41
|
+
* Clear session history
|
|
42
|
+
*/
|
|
43
|
+
clear(): void;
|
|
44
|
+
/**
|
|
45
|
+
* Get session info
|
|
46
|
+
*/
|
|
47
|
+
getSession(): Session;
|
|
48
|
+
/**
|
|
49
|
+
* Truncate messages to fit token limit
|
|
50
|
+
*/
|
|
51
|
+
truncate(maxMessages?: number): void;
|
|
52
|
+
private generateId;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/core/session.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAkClD,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAAO;IACxB,OAAO,CAAC,YAAY,CAAK;;IAOzB;;;OAGG;IACH,UAAU,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IAqB/D;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAI/D;;;OAGG;IACH,eAAe,IAAI,MAAM;IAIzB;;;;OAIG;IACH,WAAW,IAAI,WAAW,EAAE;IAoB5B;;OAEG;IACH,eAAe,IAAI,MAAM;IAIzB;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb;;OAEG;IACH,UAAU,IAAI,OAAO;IASrB;;OAEG;IACH,QAAQ,CAAC,WAAW,GAAE,MAAW,GAAG,IAAI;IAYxC,OAAO,CAAC,UAAU;CAGnB"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Manager - Manages conversation history
|
|
3
|
+
*
|
|
4
|
+
* F4 (anti-[已中断]):
|
|
5
|
+
* - addMessage 拦截含"已中断" / 链形 think 块等污染字符串
|
|
6
|
+
* (之前 AI 在失败重试时会把这些字面写进 history 造成病毒循环)
|
|
7
|
+
* - sanitize() 在 lastMessages 输出到 LLM 前再做一次去噪
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Patterns that indicate the message is polluted by a previous broken
|
|
11
|
+
* tool/stream retry loop. These should never be re-sent to the LLM.
|
|
12
|
+
*/
|
|
13
|
+
const POLLUTION_PATTERNS = [
|
|
14
|
+
/\[已中断/, // literally "[已中断" - sentinel from bad run
|
|
15
|
+
/\u5df2\u4e2d\u65ad/, // 已中断 (escaped form)
|
|
16
|
+
/^\s*\[已中断\s*$/m, // line that is exactly [已中断
|
|
17
|
+
/^<think>[\s\S]*?<\/think>\s*$/m, // entire message that is just a think block
|
|
18
|
+
/\u{1F6AB}/u, // ⛔ emoji sometimes used as interrupt marker
|
|
19
|
+
];
|
|
20
|
+
function looksPolluted(content) {
|
|
21
|
+
if (!content)
|
|
22
|
+
return false;
|
|
23
|
+
// Strip obvious thinking fences and check the *remaining* core content.
|
|
24
|
+
const stripped = content
|
|
25
|
+
.replace(/<think>[\s\S]*?<\/think>/g, '')
|
|
26
|
+
.replace(/<\/?think>/g, '')
|
|
27
|
+
.trim();
|
|
28
|
+
for (const p of POLLUTION_PATTERNS) {
|
|
29
|
+
if (p.test(content))
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
// A message whose entire stripped form is shorter than 6 chars AND
|
|
33
|
+
// contains an interruption-related token is also suspect.
|
|
34
|
+
if (stripped.length < 6 && /(中断|interrupted|cancelled|已取消)/i.test(stripped)) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
export class SessionManager {
|
|
40
|
+
messages = [];
|
|
41
|
+
sessionId;
|
|
42
|
+
createdAt;
|
|
43
|
+
droppedCount = 0;
|
|
44
|
+
constructor() {
|
|
45
|
+
this.sessionId = this.generateId();
|
|
46
|
+
this.createdAt = new Date();
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Add a message to the session.
|
|
50
|
+
* Returns true if accepted, false if dropped because it looked polluted.
|
|
51
|
+
*/
|
|
52
|
+
addMessage(role, content) {
|
|
53
|
+
if (role !== 'system' && looksPolluted(content)) {
|
|
54
|
+
this.droppedCount++;
|
|
55
|
+
// Keep a 1-line internal note so the user can see *something* happened,
|
|
56
|
+
// but the original polluted text does NOT go to the LLM context.
|
|
57
|
+
this.messages.push({
|
|
58
|
+
role: 'user',
|
|
59
|
+
content: '[system: dropped a polluted prior message containing "已中断" markers. Continue with the original task.]',
|
|
60
|
+
name: 'system'
|
|
61
|
+
});
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
this.messages.push({
|
|
65
|
+
role,
|
|
66
|
+
content,
|
|
67
|
+
name: role === 'user' ? 'user' : undefined
|
|
68
|
+
});
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Add a message WITHOUT any sanitization (for trusted callers, e.g. system prompt)
|
|
73
|
+
*/
|
|
74
|
+
addMessageRaw(role, content) {
|
|
75
|
+
this.messages.push({ role, content });
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* How many polluted messages have we filtered out? Useful for debugging
|
|
79
|
+
* the "AI keeps saying interrupted" loop.
|
|
80
|
+
*/
|
|
81
|
+
getDroppedCount() {
|
|
82
|
+
return this.droppedCount;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Return messages ready to send to the LLM. We additionally dedupe
|
|
86
|
+
* adjacent identical assistant messages (a recovery hack against the
|
|
87
|
+
* "AI repeats the same paragraph each turn" loop).
|
|
88
|
+
*/
|
|
89
|
+
getMessages() {
|
|
90
|
+
const out = [];
|
|
91
|
+
for (let i = 0; i < this.messages.length; i++) {
|
|
92
|
+
const m = this.messages[i];
|
|
93
|
+
const prev = out[out.length - 1];
|
|
94
|
+
if (prev &&
|
|
95
|
+
m.role === 'assistant' &&
|
|
96
|
+
prev.role === 'assistant' &&
|
|
97
|
+
m.content.length > 0 &&
|
|
98
|
+
m.content === prev.content) {
|
|
99
|
+
// collapse identical neighbour
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
out.push(m);
|
|
103
|
+
}
|
|
104
|
+
return out;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Get message count (raw, includes internal notes)
|
|
108
|
+
*/
|
|
109
|
+
getMessageCount() {
|
|
110
|
+
return this.messages.length;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Clear session history
|
|
114
|
+
*/
|
|
115
|
+
clear() {
|
|
116
|
+
this.messages = [];
|
|
117
|
+
this.droppedCount = 0;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Get session info
|
|
121
|
+
*/
|
|
122
|
+
getSession() {
|
|
123
|
+
return {
|
|
124
|
+
id: this.sessionId,
|
|
125
|
+
messages: this.messages,
|
|
126
|
+
createdAt: this.createdAt,
|
|
127
|
+
lastActiveAt: new Date()
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Truncate messages to fit token limit
|
|
132
|
+
*/
|
|
133
|
+
truncate(maxMessages = 20) {
|
|
134
|
+
if (this.messages.length > maxMessages) {
|
|
135
|
+
const systemMsg = this.messages.find(m => m.role === 'system');
|
|
136
|
+
const otherMsgs = this.messages.filter(m => m.role !== 'system');
|
|
137
|
+
this.messages = [
|
|
138
|
+
...(systemMsg ? [systemMsg] : []),
|
|
139
|
+
...otherMsgs.slice(-(maxMessages - 1))
|
|
140
|
+
];
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
generateId() {
|
|
144
|
+
return `session_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/core/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S10: Skills System
|
|
3
|
+
* Load skills from CLAUDE.md files and expose them as available commands
|
|
4
|
+
*
|
|
5
|
+
* Skills are domain-specific knowledge packages that extend agent capabilities.
|
|
6
|
+
*/
|
|
7
|
+
export interface Skill {
|
|
8
|
+
name: string;
|
|
9
|
+
description: string;
|
|
10
|
+
prompt: string;
|
|
11
|
+
source: string;
|
|
12
|
+
tags: string[];
|
|
13
|
+
}
|
|
14
|
+
export interface SkillsCatalog {
|
|
15
|
+
skills: Skill[];
|
|
16
|
+
loadedAt: Date;
|
|
17
|
+
sources: string[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* S10: Skills Loader — discovers and loads skills from filesystem
|
|
21
|
+
*/
|
|
22
|
+
export declare class SkillsLoader {
|
|
23
|
+
private skills;
|
|
24
|
+
private sources;
|
|
25
|
+
/**
|
|
26
|
+
* S10: Load skills from a directory
|
|
27
|
+
* Looks for .md files with # SkillName header
|
|
28
|
+
*/
|
|
29
|
+
loadFromDir(dirPath: string): number;
|
|
30
|
+
/**
|
|
31
|
+
* S10: Load a single skill file
|
|
32
|
+
*/
|
|
33
|
+
loadFromFile(filePath: string): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* S10: Parse a skill file — extract name, description, prompt from markdown
|
|
36
|
+
*/
|
|
37
|
+
private parseSkillFile;
|
|
38
|
+
private extractTags;
|
|
39
|
+
/**
|
|
40
|
+
* S10: Get all skills
|
|
41
|
+
*/
|
|
42
|
+
getAll(): Skill[];
|
|
43
|
+
/**
|
|
44
|
+
* S10: Get skill by name
|
|
45
|
+
*/
|
|
46
|
+
get(name: string): Skill | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* S10: Search skills by tag or name
|
|
49
|
+
*/
|
|
50
|
+
search(query: string): Skill[];
|
|
51
|
+
/**
|
|
52
|
+
* S10: Get catalog
|
|
53
|
+
*/
|
|
54
|
+
getCatalog(): SkillsCatalog;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* S10: Built-in skills
|
|
58
|
+
*/
|
|
59
|
+
export declare const BUILT_IN_SKILLS: Skill[];
|
|
60
|
+
//# sourceMappingURL=skills.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/core/skills.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,QAAQ,EAAE,IAAI,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,OAAO,CAA0B;IAEzC;;;OAGG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAwBpC;;OAEG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAevC;;OAEG;IACH,OAAO,CAAC,cAAc;IAwDtB,OAAO,CAAC,WAAW;IAQnB;;OAEG;IACH,MAAM,IAAI,KAAK,EAAE;IAIjB;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAIpC;;OAEG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,EAAE;IAS9B;;OAEG;IACH,UAAU,IAAI,aAAa;CAO5B;AAED;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,EAsBlC,CAAC"}
|