@curie-agent/core 0.1.2 → 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.
@@ -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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"}
@@ -1,4 +1,4 @@
1
- export interface HopperSettings {
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: HopperSettings;
40
+ export declare const DEFAULT_SETTINGS: CurieSettings;
37
41
  export declare class SettingsManager {
38
42
  private settings;
39
43
  constructor();
40
- load(): HopperSettings;
44
+ load(): CurieSettings;
41
45
  save(): void;
42
- update(partial: Partial<HopperSettings>): HopperSettings;
43
- get(): HopperSettings;
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,cAAc;IAC7B,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;CAC/B;AAED,eAAO,MAAM,gBAAgB,EAAE,cAoB9B,CAAC;AAgBF,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAiB;;IAMjC,IAAI,IAAI,cAAc;IAsEtB,IAAI,IAAI,IAAI;IAOZ,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,cAAc;IAMxD,GAAG,IAAI,cAAc;CAGtB"}
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"}
@@ -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: 'tokyo-night',
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
  }
@@ -1 +1 @@
1
- {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/settings.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/settings.ts"],"names":[],"mappings":"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"}
@@ -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 { HopperSettings } from './settings.js';
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: HopperSettings;
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":"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"}
1
+ {"version":3,"file":"turn-loop.d.ts","sourceRoot":"","sources":["../../src/turn-loop.ts"],"names":[],"mappings":"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"}
@@ -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';