@curie-agent/core 0.1.0 → 0.2.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/LICENSE +179 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/src/heartbeat-executor.d.ts +2 -2
- package/dist/src/heartbeat-executor.d.ts.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/permission.d.ts.map +1 -1
- package/dist/src/permission.js +13 -0
- package/dist/src/permission.js.map +1 -1
- package/dist/src/safety/command-guard.d.ts +8 -0
- package/dist/src/safety/command-guard.d.ts.map +1 -0
- package/dist/src/safety/command-guard.js +95 -0
- package/dist/src/safety/command-guard.js.map +1 -0
- package/dist/src/safety/path-guard.d.ts +16 -0
- package/dist/src/safety/path-guard.d.ts.map +1 -0
- package/dist/src/safety/path-guard.js +55 -0
- package/dist/src/safety/path-guard.js.map +1 -0
- package/dist/src/safety/snapshot.d.ts +36 -0
- package/dist/src/safety/snapshot.d.ts.map +1 -0
- package/dist/src/safety/snapshot.js +164 -0
- package/dist/src/safety/snapshot.js.map +1 -0
- package/dist/src/settings.d.ts +9 -5
- package/dist/src/settings.d.ts.map +1 -1
- package/dist/src/settings.js +9 -1
- package/dist/src/settings.js.map +1 -1
- package/dist/src/turn-loop.d.ts +5 -3
- package/dist/src/turn-loop.d.ts.map +1 -1
- package/dist/src/turn-loop.js +13 -1
- package/dist/src/turn-loop.js.map +1 -1
- package/package.json +22 -10
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
const HARD_DENY_PATTERNS = [
|
|
2
|
+
{
|
|
3
|
+
regex: /rm\s+(-[rf]+\s+)*\//i,
|
|
4
|
+
reason: 'rm: deletion of filesystem root (/)',
|
|
5
|
+
},
|
|
6
|
+
{
|
|
7
|
+
regex: /rm\s+(-[rf]+\s+)*~/i,
|
|
8
|
+
reason: 'rm: deletion of home directory (~)',
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
regex: /cd\s+\/[\s;|&]([^;|&]*)?\s*(?:&&\s*)?(?:rm|del|format|mkfs|dd)/i,
|
|
12
|
+
reason: 'cd / followed by destructive command',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
regex: /del\s+\/[sSqQfF]\s+/,
|
|
16
|
+
reason: 'del: Windows delete with /S /Q flags',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
regex: /format\s+[a-z]:/i,
|
|
20
|
+
reason: 'format: Windows drive formatting',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
regex: /mkfs(\.\w+)?\s+\/dev\//,
|
|
24
|
+
reason: 'mkfs: filesystem creation on block device',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
regex: /dd\s+.*of=\/dev\/(sd|nvme|hd)/,
|
|
28
|
+
reason: 'dd: raw disk write to block device',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
regex: /:\(\)\s*\{\s*:\s*\|\s*:\s*&\s*\}\s*;\s*:/,
|
|
32
|
+
reason: 'fork bomb detected (:() { :|:& };:)',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
regex: /^(shutdown|reboot|halt|poweroff)\b/i,
|
|
36
|
+
reason: 'system shutdown/reboot/halt/poweroff command',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
regex: /sudo\s+(rm|dd|mkfs)\s/i,
|
|
40
|
+
reason: 'sudo escalation combined with destructive command',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
regex: /(?:cat|grep|less|more|head|tail)\s+.*\/\.curie-agent\/settings\.json/i,
|
|
44
|
+
reason: 'reading curie-agent settings file (contains API keys and secrets)',
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
const ASK_PATTERNS = [
|
|
48
|
+
{
|
|
49
|
+
regex: /curl\s+.*\|\s*(sh|bash|zsh|pwsh|powershell)/i,
|
|
50
|
+
reason: 'pipe curl output to a shell (remote code execution risk)',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
regex: /wget\s+.*\|\s*(sh|bash|zsh|pwsh|powershell)/i,
|
|
54
|
+
reason: 'pipe wget output to a shell (remote code execution risk)',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
regex: /\bsudo\b/i,
|
|
58
|
+
reason: 'sudo: privilege escalation',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
regex: /chmod\s+-R\s+(777|0777)/,
|
|
62
|
+
reason: 'chmod -R 777/0777: dangerous recursive permissions change',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
regex: /git\s+push\s+--force(?:-with-lease)?\s+(?:\S+\s+)?(main|master|HEAD)\b/i,
|
|
66
|
+
reason: 'git push --force/--force-with-lease on a protected branch',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
regex: /\b(npm|pnpm|yarn)\s+publish\b/i,
|
|
70
|
+
reason: 'irreversible npm/pnpm/yarn publish action',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
regex: /(?:grep|cat)\s+.*\/(?:\.ssh\/|\.aws\/|id_rsa|credentials\.json)/i,
|
|
74
|
+
reason: 'credential file read: SSH keys, AWS credentials, or secrets',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
regex: /(?:grep|cat)\s+.*\/\.env\b/i,
|
|
78
|
+
reason: 'env file read: accessing .env file contents',
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
export function classifyCommand(command) {
|
|
82
|
+
const normalized = command.replace(/\s+/g, ' ').trim();
|
|
83
|
+
for (const p of HARD_DENY_PATTERNS) {
|
|
84
|
+
if (p.regex.test(normalized)) {
|
|
85
|
+
return { decision: 'deny', reason: p.reason, pattern: 'destructive' };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
for (const p of ASK_PATTERNS) {
|
|
89
|
+
if (p.regex.test(normalized)) {
|
|
90
|
+
return { decision: 'ask', reason: p.reason, pattern: 'risky' };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return { decision: 'allow', reason: 'no risky patterns detected' };
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=command-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-guard.js","sourceRoot":"","sources":["../../../src/safety/command-guard.ts"],"names":[],"mappings":"AAaA,MAAM,kBAAkB,GAAqB;IAC3C;QACE,KAAK,EAAE,sBAAsB;QAC7B,MAAM,EAAE,qCAAqC;KAC9C;IACD;QACE,KAAK,EAAE,qBAAqB;QAC5B,MAAM,EAAE,oCAAoC;KAC7C;IACD;QACE,KAAK,EAAE,iEAAiE;QACxE,MAAM,EAAE,sCAAsC;KAC/C;IACD;QACE,KAAK,EAAE,qBAAqB;QAC5B,MAAM,EAAE,sCAAsC;KAC/C;IACD;QACE,KAAK,EAAE,kBAAkB;QACzB,MAAM,EAAE,kCAAkC;KAC3C;IACD;QACE,KAAK,EAAE,wBAAwB;QAC/B,MAAM,EAAE,2CAA2C;KACpD;IACD;QACE,KAAK,EAAE,+BAA+B;QACtC,MAAM,EAAE,oCAAoC;KAC7C;IACD;QACE,KAAK,EAAE,0CAA0C;QACjD,MAAM,EAAE,qCAAqC;KAC9C;IACD;QACE,KAAK,EAAE,qCAAqC;QAC5C,MAAM,EAAE,8CAA8C;KACvD;IACD;QACE,KAAK,EAAE,wBAAwB;QAC/B,MAAM,EAAE,mDAAmD;KAC5D;IACD;QACE,KAAK,EAAE,uEAAuE;QAC9E,MAAM,EAAE,mEAAmE;KAC5E;CACF,CAAC;AAEF,MAAM,YAAY,GAAqB;IACrC;QACE,KAAK,EAAE,8CAA8C;QACrD,MAAM,EAAE,0DAA0D;KACnE;IACD;QACE,KAAK,EAAE,8CAA8C;QACrD,MAAM,EAAE,0DAA0D;KACnE;IACD;QACE,KAAK,EAAE,WAAW;QAClB,MAAM,EAAE,4BAA4B;KACrC;IACD;QACE,KAAK,EAAE,yBAAyB;QAChC,MAAM,EAAE,2DAA2D;KACpE;IACD;QACE,KAAK,EAAE,yEAAyE;QAChF,MAAM,EAAE,2DAA2D;KACpE;IACD;QACE,KAAK,EAAE,gCAAgC;QACvC,MAAM,EAAE,2CAA2C;KACpD;IACD;QACE,KAAK,EAAE,kEAAkE;QACzE,MAAM,EAAE,6DAA6D;KACtE;IACD;QACE,KAAK,EAAE,6BAA6B;QACpC,MAAM,EAAE,6CAA6C;KACtD;CACF,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAEvD,KAAK,MAAM,CAAC,IAAI,kBAAkB,EAAE,CAAC;QACnC,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC;QACxE,CAAC;IACH,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,YAAY,EAAE,CAAC;QAC7B,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YAC7B,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;QACjE,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,4BAA4B,EAAE,CAAC;AACrE,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Parse comma-separated allowlist string into absolute path array. */
|
|
2
|
+
export declare function parseAllowlist(raw: string): string[];
|
|
3
|
+
/**
|
|
4
|
+
* Check whether `targetPath` is inside `cwd` or any path in `allowlist`.
|
|
5
|
+
*/
|
|
6
|
+
export declare function isPathAllowed(targetPath: string, cwd: string, allowlist: string[]): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Resolve a user-provided path and check against allowlist.
|
|
9
|
+
* Returns `{ path }` on success or `{ error }` on failure.
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveSafePath(userInput: string, cwd: string, allowlist: string[]): {
|
|
12
|
+
path: string;
|
|
13
|
+
} | {
|
|
14
|
+
error: string;
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=path-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-guard.d.ts","sourceRoot":"","sources":["../../../src/safety/path-guard.ts"],"names":[],"mappings":"AAIA,uEAAuE;AACvE,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAGpD;AAuBD;;GAEG;AACH,wBAAgB,aAAa,CAC3B,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,EAAE,GAClB,OAAO,CAKT;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,EAAE,GAClB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAYtC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
/** Parse comma-separated allowlist string into absolute path array. */
|
|
5
|
+
export function parseAllowlist(raw) {
|
|
6
|
+
if (!raw)
|
|
7
|
+
return [];
|
|
8
|
+
return raw.split(',').map(s => s.trim()).filter(Boolean).map(expandPath);
|
|
9
|
+
}
|
|
10
|
+
function expandPath(p) {
|
|
11
|
+
if (p.startsWith('~/') || p === '~')
|
|
12
|
+
return homedir() + p.slice(1);
|
|
13
|
+
return p;
|
|
14
|
+
}
|
|
15
|
+
/** Resolve a path via realpathSync (resolves symlinks) or fall back to resolve. */
|
|
16
|
+
function normalize(p) {
|
|
17
|
+
try {
|
|
18
|
+
return fs.realpathSync(p);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return path.resolve(p);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/** Check if `haystack` starts with `prefix` (cross-platform, separator-aware). */
|
|
25
|
+
function startsWith(haystack, prefix) {
|
|
26
|
+
const a = process.platform === 'win32' ? haystack.toLowerCase() : haystack;
|
|
27
|
+
const b = process.platform === 'win32' ? prefix.toLowerCase() : prefix;
|
|
28
|
+
return a === b || a.startsWith(b + path.sep);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Check whether `targetPath` is inside `cwd` or any path in `allowlist`.
|
|
32
|
+
*/
|
|
33
|
+
export function isPathAllowed(targetPath, cwd, allowlist) {
|
|
34
|
+
const t = normalize(targetPath);
|
|
35
|
+
const c = normalize(cwd);
|
|
36
|
+
if (startsWith(t, c))
|
|
37
|
+
return true;
|
|
38
|
+
return allowlist.some(a => startsWith(t, normalize(a)));
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Resolve a user-provided path and check against allowlist.
|
|
42
|
+
* Returns `{ path }` on success or `{ error }` on failure.
|
|
43
|
+
*/
|
|
44
|
+
export function resolveSafePath(userInput, cwd, allowlist) {
|
|
45
|
+
const expanded = expandPath(userInput);
|
|
46
|
+
const resolved = path.isAbsolute(expanded) ? expanded : path.resolve(cwd, expanded);
|
|
47
|
+
const normalized = normalize(resolved);
|
|
48
|
+
if (!isPathAllowed(normalized, cwd, allowlist)) {
|
|
49
|
+
return {
|
|
50
|
+
error: `PathGuard: path '${normalized}' is outside the allowed directories (project: '${cwd}')`,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return { path: normalized };
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=path-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-guard.js","sourceRoot":"","sources":["../../../src/safety/path-guard.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,uEAAuE;AACvE,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IACpB,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;AAC3E,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG;QAAE,OAAO,OAAO,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnE,OAAO,CAAC,CAAC;AACX,CAAC;AAED,mFAAmF;AACnF,SAAS,SAAS,CAAC,CAAS;IAC1B,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACzB,CAAC;AACH,CAAC;AAED,kFAAkF;AAClF,SAAS,UAAU,CAAC,QAAgB,EAAE,MAAc;IAClD,MAAM,CAAC,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC3E,MAAM,CAAC,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACvE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAC3B,UAAkB,EAClB,GAAW,EACX,SAAmB;IAEnB,MAAM,CAAC,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;IAChC,MAAM,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IACzB,IAAI,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAClC,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,SAAiB,EACjB,GAAW,EACX,SAAmB;IAEnB,MAAM,QAAQ,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACpF,MAAM,UAAU,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IAEvC,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE,GAAG,EAAE,SAAS,CAAC,EAAE,CAAC;QAC/C,OAAO;YACL,KAAK,EAAE,oBAAoB,UAAU,mDAAmD,GAAG,IAAI;SAChG,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** A single git snapshot entry. */
|
|
2
|
+
export interface Snapshot {
|
|
3
|
+
sha: string;
|
|
4
|
+
timestamp: string;
|
|
5
|
+
cwd: string;
|
|
6
|
+
label: string;
|
|
7
|
+
changedFiles: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Create a git snapshot of the current working tree.
|
|
11
|
+
* Uses `git stash create` to produce a dangling commit.
|
|
12
|
+
* Returns the commit SHA on success, or an error string on failure.
|
|
13
|
+
*
|
|
14
|
+
* @param prompt - User message used as the snapshot label (first 25 chars).
|
|
15
|
+
*/
|
|
16
|
+
export declare function createSnapshot(cwd: string, prompt?: string): Promise<{
|
|
17
|
+
sha: string;
|
|
18
|
+
} | {
|
|
19
|
+
error: string;
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* List recent snapshots for a given cwd.
|
|
23
|
+
* Returns up to 20 entries sorted newest-first.
|
|
24
|
+
*/
|
|
25
|
+
export declare function listSnapshots(cwd: string): Snapshot[];
|
|
26
|
+
/**
|
|
27
|
+
* Revert to a specific snapshot by SHA.
|
|
28
|
+
* Uses `git checkout <sha> -- .` to restore files from the snapshot tree.
|
|
29
|
+
*/
|
|
30
|
+
export declare function revertTo(cwd: string, sha: string): Promise<{
|
|
31
|
+
success: true;
|
|
32
|
+
} | {
|
|
33
|
+
success: false;
|
|
34
|
+
error: string;
|
|
35
|
+
}>;
|
|
36
|
+
//# sourceMappingURL=snapshot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../../../src/safety/snapshot.ts"],"names":[],"mappings":"AAmBA,mCAAmC;AACnC,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;CACtB;AAiBD;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CA+E9C;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,EAAE,CAwBrD;AAED;;;GAGG;AACH,wBAAsB,QAAQ,CAC5B,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAWhE"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { mkdirSync, readFileSync, existsSync, appendFileSync } from 'node:fs';
|
|
5
|
+
import { join, dirname, basename } from 'node:path';
|
|
6
|
+
function execFileAsync(command, args, options) {
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
execFile(command, args, { cwd: options.cwd }, (err, stdout, stderr) => {
|
|
9
|
+
if (err)
|
|
10
|
+
return reject(err);
|
|
11
|
+
resolve({ stdout: stdout.toString(), stderr: stderr.toString() });
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
const SNAPSHOTS_DIR = join(homedir(), '.curie-agent', 'snapshots');
|
|
16
|
+
function getDirHash(cwd) {
|
|
17
|
+
return createHash('md5').update(cwd).digest('hex').substring(0, 8);
|
|
18
|
+
}
|
|
19
|
+
function getProjectLogPath(cwd) {
|
|
20
|
+
const dirName = basename(cwd);
|
|
21
|
+
return join(SNAPSHOTS_DIR, `snapshot-${dirName}-${getDirHash(cwd)}.log`);
|
|
22
|
+
}
|
|
23
|
+
function sanitizeRef(s) {
|
|
24
|
+
return s.replace(/[^a-zA-Z0-9_.-]/g, '_').substring(0, 50);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Create a git snapshot of the current working tree.
|
|
28
|
+
* Uses `git stash create` to produce a dangling commit.
|
|
29
|
+
* Returns the commit SHA on success, or an error string on failure.
|
|
30
|
+
*
|
|
31
|
+
* @param prompt - User message used as the snapshot label (first 25 chars).
|
|
32
|
+
*/
|
|
33
|
+
export async function createSnapshot(cwd, prompt) {
|
|
34
|
+
try {
|
|
35
|
+
// Check we're inside a git repo
|
|
36
|
+
const isWorkTree = await execFileAsync('git', ['rev-parse', '--is-inside-work-tree'], { cwd });
|
|
37
|
+
if (isWorkTree.stdout.trim() !== 'true') {
|
|
38
|
+
return { error: 'Not a git repository' };
|
|
39
|
+
}
|
|
40
|
+
// Create snapshot for tracked + staged changes
|
|
41
|
+
let result = await execFileAsync('git', ['stash', 'create'], { cwd });
|
|
42
|
+
let sha = result.stdout.trim();
|
|
43
|
+
// Also capture untracked files via a second stash create with --include-untracked
|
|
44
|
+
try {
|
|
45
|
+
const untracked = await execFileAsync('git', ['stash', 'create', '--include-untracked'], { cwd });
|
|
46
|
+
const untrackedSha = untracked.stdout.trim();
|
|
47
|
+
if (untrackedSha) {
|
|
48
|
+
sha = untrackedSha; // prefer the more complete snapshot
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// If --include-untracked fails, fall back to tracked-only snapshot
|
|
53
|
+
}
|
|
54
|
+
// If no changes at all, use the initial commit as snapshot baseline
|
|
55
|
+
if (!sha) {
|
|
56
|
+
try {
|
|
57
|
+
const initial = await execFileAsync('git', ['rev-list', '--max-parents=0', 'HEAD'], { cwd });
|
|
58
|
+
sha = initial.stdout.trim().split('\n')[0];
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return { error: 'Failed to create snapshot (no changes detected)' };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Count changed files: tracked changes + untracked files
|
|
65
|
+
// Exclude the snapshots.log file from the count (it's the metadata store, not a project change)
|
|
66
|
+
const statusResult = await execFileAsync('git', ['status', '--porcelain'], { cwd });
|
|
67
|
+
const changedFiles = statusResult.stdout
|
|
68
|
+
.split('\n')
|
|
69
|
+
.filter(Boolean)
|
|
70
|
+
.filter(line => !line.includes('snapshots.log'))
|
|
71
|
+
.length;
|
|
72
|
+
// Build label from prompt (first 25 chars) or fallback
|
|
73
|
+
let label;
|
|
74
|
+
if (prompt) {
|
|
75
|
+
label = prompt.replace(/\s+/g, ' ').trim().substring(0, 25);
|
|
76
|
+
if (label.length === 25 && prompt.length > 25) {
|
|
77
|
+
// Try to break on a word boundary
|
|
78
|
+
const lastSpace = label.lastIndexOf(' ');
|
|
79
|
+
if (lastSpace > 0)
|
|
80
|
+
label = prompt.substring(0, lastSpace).trim();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
label = 'auto';
|
|
85
|
+
}
|
|
86
|
+
// Register snapshot in per-project log file
|
|
87
|
+
const logPath = getProjectLogPath(cwd);
|
|
88
|
+
ensureDir(logPath);
|
|
89
|
+
const timestamp = new Date().toISOString();
|
|
90
|
+
const logLine = `${timestamp}\t${sha}\t${changedFiles}\t${label}\n`;
|
|
91
|
+
try {
|
|
92
|
+
appendFileSync(logPath, logLine);
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// Append failure is non-fatal — snapshot still exists as dangling commit
|
|
96
|
+
}
|
|
97
|
+
// Create a lightweight ref so git gc doesn't reclaim for 90 days
|
|
98
|
+
const refName = `refs/curie/snapshots/${sanitizeRef(timestamp)}-${changedFiles}`;
|
|
99
|
+
try {
|
|
100
|
+
await execFileAsync('git', ['update-ref', refName, sha], { cwd });
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// Ref creation failure is non-fatal
|
|
104
|
+
}
|
|
105
|
+
return { sha };
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
109
|
+
return { error: `Snapshot failed: ${msg}` };
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* List recent snapshots for a given cwd.
|
|
114
|
+
* Returns up to 20 entries sorted newest-first.
|
|
115
|
+
*/
|
|
116
|
+
export function listSnapshots(cwd) {
|
|
117
|
+
const logPath = getProjectLogPath(cwd);
|
|
118
|
+
if (!existsSync(logPath))
|
|
119
|
+
return [];
|
|
120
|
+
const content = readFileSync(logPath, 'utf-8');
|
|
121
|
+
const lines = content.split('\n').filter(Boolean);
|
|
122
|
+
// Format: timestamp\tsha\tchangedFiles\tlabel
|
|
123
|
+
const snapshots = [];
|
|
124
|
+
for (const line of lines) {
|
|
125
|
+
const parts = line.split('\t');
|
|
126
|
+
if (parts.length < 4)
|
|
127
|
+
continue;
|
|
128
|
+
const [timestamp, sha, changedFilesStr, ...labelParts] = parts;
|
|
129
|
+
if (!sha || !changedFilesStr)
|
|
130
|
+
continue;
|
|
131
|
+
snapshots.push({
|
|
132
|
+
sha,
|
|
133
|
+
timestamp: timestamp,
|
|
134
|
+
cwd,
|
|
135
|
+
label: labelParts.join('\t'),
|
|
136
|
+
changedFiles: parseInt(changedFilesStr, 10) || 0,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return snapshots.reverse().slice(0, 20);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Revert to a specific snapshot by SHA.
|
|
143
|
+
* Uses `git checkout <sha> -- .` to restore files from the snapshot tree.
|
|
144
|
+
*/
|
|
145
|
+
export async function revertTo(cwd, sha) {
|
|
146
|
+
try {
|
|
147
|
+
await execFileAsync('git', ['checkout', sha, '--', '.'], { cwd });
|
|
148
|
+
return { success: true };
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
152
|
+
return {
|
|
153
|
+
success: false,
|
|
154
|
+
error: `Revert failed: ${msg}`,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function ensureDir(filePath) {
|
|
159
|
+
const dir = dirname(filePath);
|
|
160
|
+
if (!existsSync(dir)) {
|
|
161
|
+
mkdirSync(dir, { recursive: true });
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=snapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../../src/safety/snapshot.ts"],"names":[],"mappings":"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"}
|
package/dist/src/settings.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export interface
|
|
1
|
+
export interface CurieSettings {
|
|
2
2
|
model: string;
|
|
3
3
|
effort: 'low' | 'medium' | 'high' | 'max' | 'auto';
|
|
4
4
|
mode: 'plan' | 'edit' | 'auto' | 'yolo';
|
|
@@ -32,14 +32,18 @@ export interface HopperSettings {
|
|
|
32
32
|
HEARTBEAT_MONTHLY?: string;
|
|
33
33
|
MODEL_COST?: string;
|
|
34
34
|
MODEL_CONTEXT_WINDOW?: number;
|
|
35
|
+
SAFETY_PATH_GUARD?: 'on' | 'off';
|
|
36
|
+
SAFETY_PATH_ALLOWLIST?: string;
|
|
37
|
+
SAFETY_COMMAND_GUARD?: 'on' | 'off';
|
|
38
|
+
SAFETY_SNAPSHOTS?: 'on' | 'off';
|
|
35
39
|
}
|
|
36
|
-
export declare const DEFAULT_SETTINGS:
|
|
40
|
+
export declare const DEFAULT_SETTINGS: CurieSettings;
|
|
37
41
|
export declare class SettingsManager {
|
|
38
42
|
private settings;
|
|
39
43
|
constructor();
|
|
40
|
-
load():
|
|
44
|
+
load(): CurieSettings;
|
|
41
45
|
save(): void;
|
|
42
|
-
update(partial: Partial<
|
|
43
|
-
get():
|
|
46
|
+
update(partial: Partial<CurieSettings>): CurieSettings;
|
|
47
|
+
get(): CurieSettings;
|
|
44
48
|
}
|
|
45
49
|
//# sourceMappingURL=settings.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/settings.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/settings.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;IACnD,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IAEf,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEtC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B,SAAS,CAAC,EAAE,IAAI,GAAG,KAAK,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B,iBAAiB,CAAC,EAAE,IAAI,GAAG,KAAK,CAAC;IAEjC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAE/B,oBAAoB,CAAC,EAAE,IAAI,GAAG,KAAK,CAAC;IAEpC,gBAAgB,CAAC,EAAE,IAAI,GAAG,KAAK,CAAC;CACjC;AAED,eAAO,MAAM,gBAAgB,EAAE,aAwB9B,CAAC;AAgBF,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAgB;;IAMhC,IAAI,IAAI,aAAa;IA0ErB,IAAI,IAAI,IAAI;IAOZ,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,aAAa;IAMtD,GAAG,IAAI,aAAa;CAGrB"}
|
package/dist/src/settings.js
CHANGED
|
@@ -5,7 +5,7 @@ export const DEFAULT_SETTINGS = {
|
|
|
5
5
|
model: 'claude-sonnet-4-6',
|
|
6
6
|
effort: 'auto',
|
|
7
7
|
mode: 'auto',
|
|
8
|
-
theme: '
|
|
8
|
+
theme: 'nord',
|
|
9
9
|
statusline: true,
|
|
10
10
|
debug: false,
|
|
11
11
|
BRAVE_SEARCH_API_KEY: '',
|
|
@@ -21,6 +21,10 @@ export const DEFAULT_SETTINGS = {
|
|
|
21
21
|
HEARTBEAT_DAILY: '6:00',
|
|
22
22
|
HEARTBEAT_WEEKLY: 'monday@6:00',
|
|
23
23
|
HEARTBEAT_MONTHLY: '1@6:00',
|
|
24
|
+
SAFETY_PATH_GUARD: 'on',
|
|
25
|
+
SAFETY_PATH_ALLOWLIST: '',
|
|
26
|
+
SAFETY_COMMAND_GUARD: 'on',
|
|
27
|
+
SAFETY_SNAPSHOTS: 'on',
|
|
24
28
|
};
|
|
25
29
|
function migrateMode(raw) {
|
|
26
30
|
if (typeof raw !== 'string')
|
|
@@ -105,6 +109,10 @@ export class SettingsManager {
|
|
|
105
109
|
MODEL_COST: parsed.MODEL_COST ?? parsed.model_cost,
|
|
106
110
|
MODEL_CONTEXT_WINDOW: (typeof parsed.MODEL_CONTEXT_WINDOW === 'number' && parsed.MODEL_CONTEXT_WINDOW > 0)
|
|
107
111
|
? parsed.MODEL_CONTEXT_WINDOW : undefined,
|
|
112
|
+
SAFETY_PATH_GUARD: parsed.SAFETY_PATH_GUARD ?? DEFAULT_SETTINGS.SAFETY_PATH_GUARD,
|
|
113
|
+
SAFETY_PATH_ALLOWLIST: parsed.SAFETY_PATH_ALLOWLIST ?? '',
|
|
114
|
+
SAFETY_COMMAND_GUARD: parsed.SAFETY_COMMAND_GUARD ?? DEFAULT_SETTINGS.SAFETY_COMMAND_GUARD,
|
|
115
|
+
SAFETY_SNAPSHOTS: parsed.SAFETY_SNAPSHOTS ?? DEFAULT_SETTINGS.SAFETY_SNAPSHOTS,
|
|
108
116
|
};
|
|
109
117
|
this.settings = merged;
|
|
110
118
|
}
|
package/dist/src/settings.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/settings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/settings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AA2DjC,MAAM,CAAC,MAAM,gBAAgB,GAAkB;IAC7C,KAAK,EAAE,mBAAmB;IAC1B,MAAM,EAAE,MAAM;IACd,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,MAAM;IACb,UAAU,EAAE,IAAI;IAChB,KAAK,EAAE,KAAK;IACZ,oBAAoB,EAAE,EAAE;IACxB,kBAAkB,EAAE,EAAE;IACtB,gBAAgB,EAAE,EAAE;IACpB,gBAAgB,EAAE,EAAE;IACpB,qBAAqB,EAAE,KAAK;IAC5B,kBAAkB,EAAE,MAAM;IAC1B,cAAc,EAAE,EAAE;IAClB,kBAAkB,EAAE,CAAC;IACrB,SAAS,EAAE,KAAK;IAChB,eAAe,EAAE,EAAE;IACnB,eAAe,EAAE,MAAM;IACvB,gBAAgB,EAAE,aAAa;IAC/B,iBAAiB,EAAE,QAAQ;IAC3B,iBAAiB,EAAE,IAAI;IACvB,qBAAqB,EAAE,EAAE;IACzB,oBAAoB,EAAE,IAAI;IAC1B,gBAAgB,EAAE,IAAI;CACvB,CAAC;AAEF,SAAS,WAAW,CAAC,GAAY;IAC/B,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,gBAAgB,CAAC,IAAI,CAAC;IAC1D,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,MAAM,CAAC;QAAC,KAAK,MAAM,CAAC;QAAC,KAAK,MAAM,CAAC;QAAC,KAAK,MAAM,CAAC,CAAC,OAAO,GAAG,CAAC;QAC/D,KAAK,WAAW,CAAC,CAAC,OAAO,MAAM,CAAC;QAChC,KAAK,QAAQ,CAAC,CAAC,OAAO,MAAM,CAAC;QAC7B,KAAK,WAAW,CAAC,CAAC,OAAO,MAAM,CAAC;QAChC,OAAO,CAAC,CAAC,OAAO,gBAAgB,CAAC,IAAI,CAAC;IACxC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,cAAc,CAAC,CAAC;AACnD,MAAM,aAAa,GAAG,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;AAExD,MAAM,OAAO,eAAe;IAClB,QAAQ,CAAgB;IAEhC;QACE,IAAI,CAAC,QAAQ,GAAG,EAAE,GAAG,gBAAgB,EAAE,CAAC;IAC1C,CAAC;IAED,IAAI;QACF,IAAI,CAAC,QAAQ,GAAG,EAAE,GAAG,gBAAgB,EAAE,CAAC;QACxC,IAAI,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;gBACjD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAmC,CAAC;gBACjE,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;oBACzC,+DAA+D;oBAC/D,wDAAwD;oBACxD,MAAM,IAAI,GAAG,CAAC,GAAG,IAAc,EAAsB,EAAE;wBACrD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;4BACvB,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;4BAC3B,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;gCAAE,OAAO,MAAM,CAAC;wBACrE,CAAC;wBACD,MAAM,SAAS,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;wBACtE,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;wBACpC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;4BAC5C,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;gCAAE,SAAS;4BACtD,IAAI,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;gCAAE,OAAO,CAAC,CAAC;wBAC/C,CAAC;wBACD,OAAO,SAAS,CAAC;oBACnB,CAAC,CAAC;oBAEF,MAAM,MAAM,GAAkB;wBAC5B,KAAK,EAAG,MAAM,CAAC,KAAgB,IAAI,gBAAgB,CAAC,KAAK;wBACzD,MAAM,EAAG,MAAM,CAAC,MAAkC,IAAI,gBAAgB,CAAC,MAAM;wBAC7E,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC;wBAC9B,KAAK,EAAG,MAAM,CAAC,KAAgB,IAAI,gBAAgB,CAAC,KAAK;wBACzD,UAAU,EAAG,MAAM,CAAC,UAAsB,IAAI,gBAAgB,CAAC,UAAU;wBACzE,KAAK,EAAG,MAAM,CAAC,KAAiB,IAAI,gBAAgB,CAAC,KAAK;wBAC1D,oBAAoB,EAAE,IAAI,CAAC,sBAAsB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,eAAe,CAAC;wBAChH,SAAS,EAAE,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,gBAAgB,EAAE,SAAS,CAAC;wBAClF,aAAa,EAAE,IAAI,CAAC,eAAe,EAAE,eAAe,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,CAAC;wBACnH,cAAc,EAAE,IAAI,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,CAAC;wBACzE,cAAc,EAAE,IAAI,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,cAAc,CAAC;wBACxE,UAAU,EAAE,IAAI,CAAC,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,iBAAiB,CAAC;wBACnG,iBAAiB,EAAE,IAAI,CAAC,mBAAmB,EAAE,mBAAmB,EAAE,iBAAiB,CAAC;wBACpF,aAAa,EAAE,IAAI,CAAC,eAAe,EAAE,eAAe,EAAE,cAAc,CAAC;wBACrE,kBAAkB,EAAE,IAAI,CAAC,oBAAoB,EAAE,oBAAoB,EAAE,kBAAkB,CAAC;wBACxF,cAAc,EAAE,IAAI,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,CAAC;wBACzE,cAAc,EAAE,IAAI,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,cAAc,CAAC;wBACxE,UAAU,EAAE,IAAI,CAAC,YAAY,EAAE,YAAY,EAAE,eAAe,CAAC;wBAC7D,kBAAkB,EAAE,IAAI,CAAC,oBAAoB,EAAE,oBAAoB,EAAE,kBAAkB,CAAC;wBACxF,gBAAgB,EAAE,IAAI,CAAC,kBAAkB,EAAE,kBAAkB,EAAE,gBAAgB,CAAC;wBAChF,gBAAgB,EAAE,IAAI,CAAC,kBAAkB,EAAE,kBAAkB,EAAE,gBAAgB,CAAC;wBAChF,qBAAqB,EAAG,MAAM,CAAC,qBAAiC,IAAI,KAAK;wBACzE,kBAAkB,EAAG,MAAM,CAAC,kBAA6B,IAAI,MAAM;wBACnE,WAAW,EAAG,MAAM,CAAC,WAAuC,IAAK,MAAM,CAAC,WAAuC;wBAC/G,cAAc,EAAE,CAAC,OAAO,MAAM,CAAC,cAAc,KAAK,QAAQ,IAAI,MAAM,CAAC,cAAc,GAAG,CAAC,CAAC;4BACtF,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,gBAAgB,CAAC,cAAc;wBAC3D,kBAAkB,EAAE,CAAC,OAAO,MAAM,CAAC,kBAAkB,KAAK,QAAQ,IAAI,MAAM,CAAC,kBAAkB,GAAG,CAAC,CAAC;4BAClG,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC,gBAAgB,CAAC,kBAAkB;wBACnE,SAAS,EAAG,MAAM,CAAC,SAA0B,IAAI,gBAAgB,CAAC,SAAS;wBAC3E,eAAe,EAAG,MAAM,CAAC,eAA0B,IAAK,MAAM,CAAC,gBAA2B,IAAI,gBAAgB,CAAC,eAAe;wBAC9H,eAAe,EAAG,MAAM,CAAC,eAA0B,IAAI,gBAAgB,CAAC,eAAe;wBACvF,gBAAgB,EAAG,MAAM,CAAC,gBAA2B,IAAI,gBAAgB,CAAC,gBAAgB;wBAC1F,iBAAiB,EAAG,MAAM,CAAC,iBAA4B,IAAI,gBAAgB,CAAC,iBAAiB;wBAC7F,UAAU,EAAG,MAAM,CAAC,UAAqB,IAAK,MAAM,CAAC,UAAqB;wBAC1E,oBAAoB,EAAE,CAAC,OAAO,MAAM,CAAC,oBAAoB,KAAK,QAAQ,IAAI,MAAM,CAAC,oBAAoB,GAAG,CAAC,CAAC;4BACxG,CAAC,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,CAAC,SAAS;wBAC3C,iBAAiB,EAAG,MAAM,CAAC,iBAAkC,IAAI,gBAAgB,CAAC,iBAAiB;wBACnG,qBAAqB,EAAG,MAAM,CAAC,qBAAgC,IAAI,EAAE;wBACrE,oBAAoB,EAAG,MAAM,CAAC,oBAAqC,IAAI,gBAAgB,CAAC,oBAAoB;wBAC5G,gBAAgB,EAAG,MAAM,CAAC,gBAAiC,IAAI,gBAAgB,CAAC,gBAAgB;qBACjG,CAAC;oBACF,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC;gBACzB,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,oCAAoC;YACtC,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED,IAAI;QACF,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC5B,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,CAAC;QACD,aAAa,CAAC,aAAa,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC9E,CAAC;IAED,MAAM,CAAC,OAA+B;QACpC,IAAI,CAAC,QAAQ,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAC;QACjD,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED,GAAG;QACD,OAAO,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;IAC9B,CAAC;CACF"}
|
package/dist/src/turn-loop.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EventBus, type Event } from './event-bus.js';
|
|
2
2
|
import { SessionStore } from './session-store.js';
|
|
3
3
|
import { type ApprovalMode } from './permission.js';
|
|
4
|
-
import type {
|
|
4
|
+
import type { CurieSettings } from './settings.js';
|
|
5
5
|
export type ReasoningEffort = 'low' | 'medium' | 'high' | 'max' | 'auto';
|
|
6
6
|
export interface CancelableIterable<T> {
|
|
7
7
|
iterable: AsyncIterable<T>;
|
|
@@ -36,7 +36,7 @@ export interface Tool {
|
|
|
36
36
|
description: string;
|
|
37
37
|
inputSchema: unknown;
|
|
38
38
|
};
|
|
39
|
-
execute: (input: Record<string, unknown>, settings: any) => Promise<{
|
|
39
|
+
execute: (input: Record<string, unknown>, settings: any, cwd?: string) => Promise<{
|
|
40
40
|
output: unknown;
|
|
41
41
|
error?: string;
|
|
42
42
|
}>;
|
|
@@ -72,7 +72,7 @@ export interface TurnLoopConfig {
|
|
|
72
72
|
model: string;
|
|
73
73
|
tools: Tool[];
|
|
74
74
|
cwd: string;
|
|
75
|
-
settings:
|
|
75
|
+
settings: CurieSettings;
|
|
76
76
|
approvalMode?: ApprovalMode;
|
|
77
77
|
permissions?: Record<string, string[]>;
|
|
78
78
|
maxTurns?: number;
|
|
@@ -126,6 +126,7 @@ export declare class TurnLoop {
|
|
|
126
126
|
private store;
|
|
127
127
|
private permission;
|
|
128
128
|
private config;
|
|
129
|
+
private _cwd;
|
|
129
130
|
private abort;
|
|
130
131
|
private abortController;
|
|
131
132
|
private messages;
|
|
@@ -137,6 +138,7 @@ export declare class TurnLoop {
|
|
|
137
138
|
getSessionId(): string | undefined;
|
|
138
139
|
getMessages(): Message[];
|
|
139
140
|
cancel(): void;
|
|
141
|
+
setCwd(newCwd: string): void;
|
|
140
142
|
private evaluateHarm;
|
|
141
143
|
private reconstructMessages;
|
|
142
144
|
private buildTurnMessages;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"turn-loop.d.ts","sourceRoot":"","sources":["../../src/turn-loop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAoB,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAoB,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"turn-loop.d.ts","sourceRoot":"","sources":["../../src/turn-loop.ts"],"names":[],"mappings":"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"}
|
package/dist/src/turn-loop.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { EventBus } from './event-bus.js';
|
|
2
2
|
import { SessionStore } from './session-store.js';
|
|
3
3
|
import { PermissionEngine } from './permission.js';
|
|
4
|
+
import { createSnapshot } from './safety/snapshot.js';
|
|
4
5
|
// The provider's stream() returns a CancelableIterable with a cancel() method
|
|
5
6
|
// that synchronously aborts the underlying HTTP connection (e.g., Anthropic's
|
|
6
7
|
// stream.abort()). The TurnLoop wires this cancel() to the AbortSignal's abort
|
|
@@ -11,6 +12,7 @@ export class TurnLoop {
|
|
|
11
12
|
store;
|
|
12
13
|
permission;
|
|
13
14
|
config;
|
|
15
|
+
_cwd;
|
|
14
16
|
abort = false;
|
|
15
17
|
abortController = null;
|
|
16
18
|
messages = [];
|
|
@@ -18,6 +20,7 @@ export class TurnLoop {
|
|
|
18
20
|
recoveredTurns = 0;
|
|
19
21
|
constructor(config, store) {
|
|
20
22
|
this.config = config;
|
|
23
|
+
this._cwd = config.cwd;
|
|
21
24
|
this.bus = new EventBus();
|
|
22
25
|
this.store = store ?? new SessionStore();
|
|
23
26
|
this.permission = new PermissionEngine(config.permissions, config.approvalMode ?? 'auto');
|
|
@@ -38,6 +41,9 @@ export class TurnLoop {
|
|
|
38
41
|
this.abort = true;
|
|
39
42
|
this.abortController?.abort();
|
|
40
43
|
}
|
|
44
|
+
setCwd(newCwd) {
|
|
45
|
+
this._cwd = newCwd;
|
|
46
|
+
}
|
|
41
47
|
async evaluateHarm(toolName, input) {
|
|
42
48
|
const inputJson = JSON.stringify(input);
|
|
43
49
|
const systemPrompt = 'You are a safety evaluator. Given a tool call, determine if it is potentially harmful to the user\'s system. Harmful means: deleting files, executing arbitrary shell commands, sending data to external services, modifying system configuration, or any action that could cause data loss or security compromise. Your response must be exactly one of these two strings: APPROVE or DENY. Do not add any other text.';
|
|
@@ -163,6 +169,12 @@ export class TurnLoop {
|
|
|
163
169
|
try {
|
|
164
170
|
while (turn < maxTurns && !this.abort) {
|
|
165
171
|
turn++;
|
|
172
|
+
// Create git snapshot before each turn (best-effort).
|
|
173
|
+
if (this.config.settings.SAFETY_SNAPSHOTS !== 'off') {
|
|
174
|
+
await createSnapshot(this._cwd, prompt).catch(() => {
|
|
175
|
+
// Silently ignore — snapshots are recovery, not enforcement
|
|
176
|
+
});
|
|
177
|
+
}
|
|
166
178
|
let fullText = '';
|
|
167
179
|
const toolCalls = [];
|
|
168
180
|
let totalToolCalls = 0;
|
|
@@ -364,7 +376,7 @@ export class TurnLoop {
|
|
|
364
376
|
continue;
|
|
365
377
|
}
|
|
366
378
|
try {
|
|
367
|
-
const result = await tool.execute(tc.input, this.config.settings);
|
|
379
|
+
const result = await tool.execute(tc.input, this.config.settings, this.config.cwd);
|
|
368
380
|
emit({ type: 'tool-result', id: session.id, toolCallId: tc.id, output: result.output, error: result.error, timestamp: Date.now() });
|
|
369
381
|
const outputStr = result.error ? `Error: ${result.error}` : JSON.stringify(result.output);
|
|
370
382
|
const decisionLabel = toolDecisionBy === 'llm' ? 'LLM-approved' : toolDecisionBy === 'user' ? 'Approved by user' : 'Auto Approved';
|