cmdr-agent 1.2.2 → 1.3.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.
Files changed (56) hide show
  1. package/README.md +19 -0
  2. package/dist/bin/cmdr.js +2 -1
  3. package/dist/bin/cmdr.js.map +1 -1
  4. package/dist/src/cli/args.d.ts +1 -0
  5. package/dist/src/cli/args.d.ts.map +1 -1
  6. package/dist/src/cli/args.js +4 -0
  7. package/dist/src/cli/args.js.map +1 -1
  8. package/dist/src/cli/repl.d.ts +1 -0
  9. package/dist/src/cli/repl.d.ts.map +1 -1
  10. package/dist/src/cli/repl.js +5 -1
  11. package/dist/src/cli/repl.js.map +1 -1
  12. package/dist/src/core/agent-runner.d.ts.map +1 -1
  13. package/dist/src/core/agent-runner.js +10 -1
  14. package/dist/src/core/agent-runner.js.map +1 -1
  15. package/dist/src/core/intent.d.ts +2 -0
  16. package/dist/src/core/intent.d.ts.map +1 -1
  17. package/dist/src/core/intent.js +12 -0
  18. package/dist/src/core/intent.js.map +1 -1
  19. package/dist/src/core/presets.d.ts.map +1 -1
  20. package/dist/src/core/presets.js +49 -15
  21. package/dist/src/core/presets.js.map +1 -1
  22. package/dist/src/core/types.d.ts +4 -0
  23. package/dist/src/core/types.d.ts.map +1 -1
  24. package/dist/src/index.d.ts +3 -2
  25. package/dist/src/index.d.ts.map +1 -1
  26. package/dist/src/index.js +2 -2
  27. package/dist/src/index.js.map +1 -1
  28. package/dist/src/llm/model-registry.d.ts.map +1 -1
  29. package/dist/src/llm/model-registry.js +9 -1
  30. package/dist/src/llm/model-registry.js.map +1 -1
  31. package/dist/src/llm/ollama.d.ts +8 -1
  32. package/dist/src/llm/ollama.d.ts.map +1 -1
  33. package/dist/src/llm/ollama.js +199 -94
  34. package/dist/src/llm/ollama.js.map +1 -1
  35. package/dist/src/session/compaction.js +4 -0
  36. package/dist/src/session/compaction.js.map +1 -1
  37. package/dist/src/session/prompt-builder.d.ts +28 -1
  38. package/dist/src/session/prompt-builder.d.ts.map +1 -1
  39. package/dist/src/session/prompt-builder.js +97 -23
  40. package/dist/src/session/prompt-builder.js.map +1 -1
  41. package/dist/src/session/session-manager.d.ts +10 -3
  42. package/dist/src/session/session-manager.d.ts.map +1 -1
  43. package/dist/src/session/session-manager.js +53 -16
  44. package/dist/src/session/session-manager.js.map +1 -1
  45. package/dist/src/session/session-persistence.d.ts +12 -0
  46. package/dist/src/session/session-persistence.d.ts.map +1 -1
  47. package/dist/src/session/session-persistence.js +94 -4
  48. package/dist/src/session/session-persistence.js.map +1 -1
  49. package/dist/src/tools/built-in/bash-security.d.ts +13 -0
  50. package/dist/src/tools/built-in/bash-security.d.ts.map +1 -0
  51. package/dist/src/tools/built-in/bash-security.js +53 -0
  52. package/dist/src/tools/built-in/bash-security.js.map +1 -0
  53. package/dist/src/tools/built-in/bash.d.ts.map +1 -1
  54. package/dist/src/tools/built-in/bash.js +7 -1
  55. package/dist/src/tools/built-in/bash.js.map +1 -1
  56. package/package.json +1 -1
@@ -1,39 +1,113 @@
1
1
  /**
2
- * PromptBuilder — composable prompt construction pipeline.
2
+ * PromptBuilder — modular prompt construction pipeline.
3
+ *
4
+ * Each module has a priority (lower = earlier) and a static flag.
5
+ * Static modules are identical across turns, enabling Ollama KV cache reuse.
3
6
  */
4
- export function buildSystemPrompt(options) {
5
- const parts = [options.basePrompt];
6
- // Inject project context
7
- const ctx = options.projectContext;
8
- const contextParts = [];
9
- if (ctx.language !== 'unknown') {
10
- contextParts.push(`Language: ${ctx.language}`);
7
+ /* ── Priority constants ────────────────────────────────────────────── */
8
+ export const PROMPT_PRIORITIES = {
9
+ ROLE: 10,
10
+ TOOL_POLICY: 20,
11
+ PROJECT_INSTRUCTIONS: 30,
12
+ SKILLS: 40,
13
+ PROJECT_CONTEXT: 50,
14
+ RUNTIME_CONTEXT: 60,
15
+ CONVERSATION_STATE: 70,
16
+ };
17
+ /* ── PromptBuilder class ───────────────────────────────────────────── */
18
+ export class PromptBuilder {
19
+ modules = new Map();
20
+ addModule(mod) {
21
+ this.modules.set(mod.id, mod);
11
22
  }
12
- if (ctx.framework) {
13
- contextParts.push(`Framework: ${ctx.framework}`);
23
+ updateModule(id, content) {
24
+ const existing = this.modules.get(id);
25
+ if (existing) {
26
+ existing.content = content;
27
+ }
14
28
  }
15
- if (ctx.packageManager) {
16
- contextParts.push(`Package manager: ${ctx.packageManager}`);
29
+ removeModule(id) {
30
+ this.modules.delete(id);
17
31
  }
18
- if (ctx.gitBranch) {
19
- contextParts.push(`Git branch: ${ctx.gitBranch}`);
32
+ build() {
33
+ return [...this.modules.values()]
34
+ .sort((a, b) => a.priority - b.priority)
35
+ .map(m => m.content)
36
+ .filter(c => c.length > 0)
37
+ .join('\n\n');
20
38
  }
21
- if (contextParts.length > 0) {
22
- parts.push(`\n\nProject context:\n${contextParts.join('\n')}\nRoot: ${ctx.rootDir}`);
39
+ /** Returns only static modules — for KV cache prefix estimation. */
40
+ getStaticPrefix() {
41
+ return [...this.modules.values()]
42
+ .filter(m => m.isStatic)
43
+ .sort((a, b) => a.priority - b.priority)
44
+ .map(m => m.content)
45
+ .filter(c => c.length > 0)
46
+ .join('\n\n');
23
47
  }
24
- // Inject CMDR.md workspace instructions
48
+ }
49
+ export function buildSystemPrompt(options) {
50
+ const builder = new PromptBuilder();
51
+ const ctx = options.projectContext;
52
+ // 10: Role — base system prompt (STATIC)
53
+ builder.addModule({
54
+ id: 'role',
55
+ content: options.basePrompt,
56
+ priority: PROMPT_PRIORITIES.ROLE,
57
+ isStatic: true,
58
+ });
59
+ // 30: Project instructions — CMDR.md (STATIC per session)
25
60
  if (ctx.cmdrInstructions) {
26
- parts.push(`\n\n<project_instructions>\nThe user has provided the following instructions for this project. Follow them unless they conflict with safety:\n\n${ctx.cmdrInstructions}\n</project_instructions>`);
61
+ builder.addModule({
62
+ id: 'project_instructions',
63
+ content: `<project_instructions>\nThe user has provided the following instructions for this project. Follow them unless they conflict with safety:\n\n${ctx.cmdrInstructions}\n</project_instructions>`,
64
+ priority: PROMPT_PRIORITIES.PROJECT_INSTRUCTIONS,
65
+ isStatic: true,
66
+ });
27
67
  }
28
- // Inject active skills
68
+ // 40: Skills (STATIC per turn)
29
69
  if (ctx.activeSkills && ctx.activeSkills.length > 0) {
30
- for (const skill of ctx.activeSkills) {
70
+ const skillBlocks = ctx.activeSkills.map(skill => {
31
71
  const scriptNote = skill.scripts.length > 0
32
72
  ? `\n\nHelper scripts available at:\n${skill.scripts.map(s => ` - ${s}`).join('\n')}`
33
73
  : '';
34
- parts.push(`\n\n<skill name="${skill.name}">\n${skill.instructions}${scriptNote}\n</skill>`);
35
- }
74
+ return `<skill name="${skill.name}">\n${skill.instructions}${scriptNote}\n</skill>`;
75
+ });
76
+ builder.addModule({
77
+ id: 'skills',
78
+ content: skillBlocks.join('\n\n'),
79
+ priority: PROMPT_PRIORITIES.SKILLS,
80
+ isStatic: true,
81
+ });
82
+ }
83
+ // 50: Project context (STATIC per session)
84
+ const contextParts = [];
85
+ if (ctx.language !== 'unknown')
86
+ contextParts.push(`Language: ${ctx.language}`);
87
+ if (ctx.framework)
88
+ contextParts.push(`Framework: ${ctx.framework}`);
89
+ if (ctx.packageManager)
90
+ contextParts.push(`Package manager: ${ctx.packageManager}`);
91
+ if (contextParts.length > 0) {
92
+ builder.addModule({
93
+ id: 'project_context',
94
+ content: `Project context:\n${contextParts.join('\n')}\nRoot: ${ctx.rootDir}`,
95
+ priority: PROMPT_PRIORITIES.PROJECT_CONTEXT,
96
+ isStatic: true,
97
+ });
98
+ }
99
+ // 60: Runtime context — dynamic per turn (git branch, etc.)
100
+ const runtimeParts = [];
101
+ if (ctx.gitBranch)
102
+ runtimeParts.push(`Git branch: ${ctx.gitBranch}`);
103
+ if (runtimeParts.length > 0) {
104
+ builder.addModule({
105
+ id: 'runtime_context',
106
+ content: `Runtime:\n${runtimeParts.join('\n')}`,
107
+ priority: PROMPT_PRIORITIES.RUNTIME_CONTEXT,
108
+ isStatic: false,
109
+ });
36
110
  }
37
- return parts.join('');
111
+ return builder.build();
38
112
  }
39
113
  //# sourceMappingURL=prompt-builder.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"prompt-builder.js","sourceRoot":"","sources":["../../../src/session/prompt-builder.ts"],"names":[],"mappings":"AAAA;;GAEG;AAUH,MAAM,UAAU,iBAAiB,CAAC,OAA2B;IAC3D,MAAM,KAAK,GAAa,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;IAE5C,yBAAyB;IACzB,MAAM,GAAG,GAAG,OAAO,CAAC,cAAc,CAAA;IAClC,MAAM,YAAY,GAAa,EAAE,CAAA;IAEjC,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC/B,YAAY,CAAC,IAAI,CAAC,aAAa,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAA;IAChD,CAAC;IACD,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;QAClB,YAAY,CAAC,IAAI,CAAC,cAAc,GAAG,CAAC,SAAS,EAAE,CAAC,CAAA;IAClD,CAAC;IACD,IAAI,GAAG,CAAC,cAAc,EAAE,CAAC;QACvB,YAAY,CAAC,IAAI,CAAC,oBAAoB,GAAG,CAAC,cAAc,EAAE,CAAC,CAAA;IAC7D,CAAC;IACD,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;QAClB,YAAY,CAAC,IAAI,CAAC,eAAe,GAAG,CAAC,SAAS,EAAE,CAAC,CAAA;IACnD,CAAC;IAED,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC,yBAAyB,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,OAAO,EAAE,CAAC,CAAA;IACtF,CAAC;IAED,wCAAwC;IACxC,IAAI,GAAG,CAAC,gBAAgB,EAAE,CAAC;QACzB,KAAK,CAAC,IAAI,CAAC,mJAAmJ,GAAG,CAAC,gBAAgB,2BAA2B,CAAC,CAAA;IAChN,CAAC;IAED,uBAAuB;IACvB,IAAI,GAAG,CAAC,YAAY,IAAI,GAAG,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpD,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,YAAY,EAAE,CAAC;YACrC,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;gBACzC,CAAC,CAAC,qCAAqC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gBACtF,CAAC,CAAC,EAAE,CAAA;YACN,KAAK,CAAC,IAAI,CAAC,oBAAoB,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,YAAY,GAAG,UAAU,YAAY,CAAC,CAAA;QAC9F,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AACvB,CAAC"}
1
+ {"version":3,"file":"prompt-builder.js","sourceRoot":"","sources":["../../../src/session/prompt-builder.ts"],"names":[],"mappings":"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"}
@@ -1,21 +1,28 @@
1
1
  /**
2
- * SessionManager — conversation history with token counting and compaction.
2
+ * SessionManager — append-only conversation history with token counting and compaction.
3
+ *
4
+ * Messages are never deleted. On compaction, old messages are flagged as
5
+ * transcript-only and a compact summary is inserted as a boundary.
3
6
  */
4
7
  import type { LLMMessage, LLMAdapter, SessionState, ProjectContext, TokenUsage } from '../core/types.js';
5
8
  export declare class SessionManager {
6
9
  private session;
7
10
  private compactionConfig;
11
+ private consecutiveCompactFailures;
8
12
  constructor(projectContext: ProjectContext, maxContextTokens?: number);
9
13
  get id(): string;
10
- get messages(): LLMMessage[];
11
14
  get tokenCount(): number;
12
15
  get projectContext(): ProjectContext;
16
+ /** All messages including transcript-only (full history). */
17
+ get messages(): LLMMessage[];
18
+ /** Messages that should be sent to the LLM API (excludes transcript-only and meta). */
19
+ getApiMessages(): LLMMessage[];
13
20
  addMessage(message: LLMMessage): void;
14
21
  addMessages(messages: LLMMessage[]): void;
15
22
  shouldCompact(): boolean;
16
23
  /**
17
24
  * Multi-stage compaction: truncate tool results → LLM summary → hard truncation.
18
- * Returns the number of tokens saved.
25
+ * Uses append-only pattern: old messages are flagged, not removed.
19
26
  */
20
27
  compact(adapter: LLMAdapter, model: string): Promise<{
21
28
  before: number;
@@ -1 +1 @@
1
- {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../../src/session/session-manager.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AASxG,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,gBAAgB,CAAkB;gBAE9B,cAAc,EAAE,cAAc,EAAE,gBAAgB,SAAQ;IAgBpE,IAAI,EAAE,IAAI,MAAM,CAA2B;IAC3C,IAAI,QAAQ,IAAI,UAAU,EAAE,CAAiC;IAC7D,IAAI,UAAU,IAAI,MAAM,CAAmC;IAC3D,IAAI,cAAc,IAAI,cAAc,CAAuC;IAE3E,UAAU,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI;IAMrC,WAAW,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,IAAI;IAQzC,aAAa,IAAI,OAAO;IAIxB;;;OAGG;IACG,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAqBlH,KAAK,IAAI,IAAI;IAKb,mEAAmE;IACnE,mBAAmB,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI;IAQnD,aAAa,IAAI,UAAU;IAO3B,QAAQ,IAAI,YAAY;IAIxB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAMnC,iEAAiE;IACjE,aAAa,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,IAAI;CAK5C"}
1
+ {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../../src/session/session-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAWxG,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,gBAAgB,CAAkB;IAC1C,OAAO,CAAC,0BAA0B,CAAI;gBAE1B,cAAc,EAAE,cAAc,EAAE,gBAAgB,SAAQ;IAgBpE,IAAI,EAAE,IAAI,MAAM,CAA2B;IAC3C,IAAI,UAAU,IAAI,MAAM,CAAmC;IAC3D,IAAI,cAAc,IAAI,cAAc,CAAuC;IAE3E,6DAA6D;IAC7D,IAAI,QAAQ,IAAI,UAAU,EAAE,CAAiC;IAE7D,uFAAuF;IACvF,cAAc,IAAI,UAAU,EAAE;IAM9B,UAAU,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI;IAMrC,WAAW,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,IAAI;IAQzC,aAAa,IAAI,OAAO;IAOxB;;;OAGG;IACG,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IA6ClH,KAAK,IAAI,IAAI;IAMb,mEAAmE;IACnE,mBAAmB,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI;IAQnD,aAAa,IAAI,UAAU;IAO3B,QAAQ,IAAI,YAAY;IAIxB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAMnC,iEAAiE;IACjE,aAAa,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,IAAI;CAK5C"}
@@ -1,11 +1,16 @@
1
1
  /**
2
- * SessionManager — conversation history with token counting and compaction.
2
+ * SessionManager — append-only conversation history with token counting and compaction.
3
+ *
4
+ * Messages are never deleted. On compaction, old messages are flagged as
5
+ * transcript-only and a compact summary is inserted as a boundary.
3
6
  */
4
7
  import { countMessageTokens } from '../llm/token-counter.js';
5
8
  import { shouldCompact as checkCompact, compactHistory, DEFAULT_COMPACTION_CONFIG, } from './compaction.js';
9
+ const MAX_COMPACT_FAILURES = 3;
6
10
  export class SessionManager {
7
11
  session;
8
12
  compactionConfig;
13
+ consecutiveCompactFailures = 0;
9
14
  constructor(projectContext, maxContextTokens = 32768) {
10
15
  this.session = {
11
16
  id: `session_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
@@ -22,43 +27,75 @@ export class SessionManager {
22
27
  };
23
28
  }
24
29
  get id() { return this.session.id; }
25
- get messages() { return this.session.messages; }
26
30
  get tokenCount() { return this.session.tokenCount; }
27
31
  get projectContext() { return this.session.projectContext; }
32
+ /** All messages including transcript-only (full history). */
33
+ get messages() { return this.session.messages; }
34
+ /** Messages that should be sent to the LLM API (excludes transcript-only and meta). */
35
+ getApiMessages() {
36
+ return this.session.messages.filter(m => !m.isVisibleInTranscriptOnly && !m.isMeta);
37
+ }
28
38
  addMessage(message) {
29
39
  this.session.messages.push(message);
30
- this.session.tokenCount = countMessageTokens(this.session.messages);
40
+ this.session.tokenCount = countMessageTokens(this.getApiMessages());
31
41
  this.session.lastActivity = new Date();
32
42
  }
33
43
  addMessages(messages) {
34
44
  for (const msg of messages) {
35
45
  this.session.messages.push(msg);
36
46
  }
37
- this.session.tokenCount = countMessageTokens(this.session.messages);
47
+ this.session.tokenCount = countMessageTokens(this.getApiMessages());
38
48
  this.session.lastActivity = new Date();
39
49
  }
40
50
  shouldCompact() {
41
- return checkCompact(this.session.messages, this.session.tokenCount, this.compactionConfig);
51
+ if (this.consecutiveCompactFailures >= MAX_COMPACT_FAILURES) {
52
+ return false; // Circuit breaker: stop trying after repeated failures
53
+ }
54
+ return checkCompact(this.getApiMessages(), this.session.tokenCount, this.compactionConfig);
42
55
  }
43
56
  /**
44
57
  * Multi-stage compaction: truncate tool results → LLM summary → hard truncation.
45
- * Returns the number of tokens saved.
58
+ * Uses append-only pattern: old messages are flagged, not removed.
46
59
  */
47
60
  async compact(adapter, model) {
48
- const before = this.session.tokenCount;
49
- const beforeCount = this.session.messages.length;
50
- const result = await compactHistory(this.session.messages, this.compactionConfig, adapter, model);
51
- this.session.messages = result.messages;
52
- this.session.tokenCount = countMessageTokens(this.session.messages);
53
- return {
54
- before: beforeCount,
55
- after: this.session.messages.length,
56
- tokensSaved: result.tokensSaved,
57
- };
61
+ const apiMessages = this.getApiMessages();
62
+ const before = apiMessages.length;
63
+ const beforeTokens = this.session.tokenCount;
64
+ try {
65
+ const result = await compactHistory(apiMessages, this.compactionConfig, adapter, model);
66
+ // Flag old API messages as transcript-only
67
+ for (const msg of this.session.messages) {
68
+ if (!msg.isVisibleInTranscriptOnly && !msg.isMeta) {
69
+ // If this message isn't in the compacted result, flag it
70
+ if (!result.messages.includes(msg)) {
71
+ msg.isVisibleInTranscriptOnly = true;
72
+ }
73
+ }
74
+ }
75
+ // Insert new messages from compaction (summary boundary etc.)
76
+ for (const msg of result.messages) {
77
+ if (msg.isCompactSummary || msg.isCompactBoundary) {
78
+ // Find insertion point: after all existing messages
79
+ this.session.messages.push(msg);
80
+ }
81
+ }
82
+ this.session.tokenCount = countMessageTokens(this.getApiMessages());
83
+ this.consecutiveCompactFailures = 0;
84
+ return {
85
+ before,
86
+ after: this.getApiMessages().length,
87
+ tokensSaved: beforeTokens - this.session.tokenCount,
88
+ };
89
+ }
90
+ catch (err) {
91
+ this.consecutiveCompactFailures++;
92
+ throw err;
93
+ }
58
94
  }
59
95
  clear() {
60
96
  this.session.messages = [];
61
97
  this.session.tokenCount = 0;
98
+ this.consecutiveCompactFailures = 0;
62
99
  }
63
100
  /** Update the max context tokens (e.g. after switching models). */
64
101
  updateContextLength(maxContextTokens) {
@@ -1 +1 @@
1
- {"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../../src/session/session-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../../src/session/session-manager.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,11 @@
1
1
  /**
2
2
  * Session persistence — save/load conversation sessions to ~/.cmdr/sessions/.
3
+ *
4
+ * Uses append-only JSONL (one JSON object per line) for crash-safe writes.
5
+ * Each line is one of:
6
+ * {"type":"meta","sessionId":"...","model":"...","projectRoot":"...","createdAt":"..."}
7
+ * {"type":"message","role":"user","content":[...],"timestamp":"..."}
8
+ * {"type":"compact","boundaryIndex":42,"summary":"...","timestamp":"..."}
3
9
  */
4
10
  import type { LLMMessage, SessionState } from '../core/types.js';
5
11
  export interface SavedSession {
@@ -12,6 +18,12 @@ export interface SavedSession {
12
18
  toolsUsed?: string[];
13
19
  summary?: string;
14
20
  }
21
+ /** Append a single message to the JSONL session file. */
22
+ export declare function appendSessionMessage(sessionId: string, msg: LLMMessage): Promise<void>;
23
+ /** Write session meta header (called once at session start). */
24
+ export declare function writeSessionMeta(sessionId: string, model: string, projectRoot: string): Promise<void>;
25
+ /** Append a compaction marker to the journal. */
26
+ export declare function appendCompactMarker(sessionId: string, boundaryIndex: number, summary: string): Promise<void>;
15
27
  export declare function saveSession(sessionState: SessionState, model: string): Promise<string>;
16
28
  export declare function loadSession(sessionId: string): Promise<SavedSession | null>;
17
29
  /** Find the most recent session for a given project directory. */
@@ -1 +1 @@
1
- {"version":3,"file":"session-persistence.d.ts","sourceRoot":"","sources":["../../../src/session/session-persistence.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAkB,MAAM,kBAAkB,CAAA;AAKhF,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE,UAAU,EAAE,CAAA;IACtB,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAoCD,wBAAsB,WAAW,CAC/B,YAAY,EAAE,YAAY,EAC1B,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,CAiBjB;AAED,wBAAsB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAQjF;AAED,kEAAkE;AAClE,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAKzF;AAED,wBAAsB,YAAY,IAAI,OAAO,CAAC,KAAK,CAAC;IAClD,EAAE,EAAE,MAAM,CAAA;IACV,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAC,CAAC,CAuCF;AAED,sCAAsC;AACtC,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAMD,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAA6C;IAC1D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;gBAEvB,UAAU,SAAO;IAI7B;;;OAGG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAYvC,+BAA+B;IAC/B,MAAM,IAAI,IAAI;IAOd,yCAAyC;IACnC,KAAK,CAAC,EAAE,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;CAIpD"}
1
+ {"version":3,"file":"session-persistence.d.ts","sourceRoot":"","sources":["../../../src/session/session-persistence.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAkB,MAAM,kBAAkB,CAAA;AAKhF,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE,UAAU,EAAE,CAAA;IACtB,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAwED,yDAAyD;AACzD,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,UAAU,GACd,OAAO,CAAC,IAAI,CAAC,CAaf;AAED,gEAAgE;AAChE,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAUf;AAED,iDAAiD;AACjD,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAQf;AAMD,wBAAsB,WAAW,CAC/B,YAAY,EAAE,YAAY,EAC1B,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,CAkBjB;AAED,wBAAsB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAkDjF;AAED,kEAAkE;AAClE,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAKzF;AAED,wBAAsB,YAAY,IAAI,OAAO,CAAC,KAAK,CAAC;IAClD,EAAE,EAAE,MAAM,CAAA;IACV,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAC,CAAC,CAuCF;AAED,sCAAsC;AACtC,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAMD,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAA6C;IAC1D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;gBAEvB,UAAU,SAAO;IAI7B;;;OAGG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAYvC,+BAA+B;IAC/B,MAAM,IAAI,IAAI;IAOd,yCAAyC;IACnC,KAAK,CAAC,EAAE,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;CAIpD"}
@@ -1,7 +1,14 @@
1
1
  /**
2
2
  * Session persistence — save/load conversation sessions to ~/.cmdr/sessions/.
3
+ *
4
+ * Uses append-only JSONL (one JSON object per line) for crash-safe writes.
5
+ * Each line is one of:
6
+ * {"type":"meta","sessionId":"...","model":"...","projectRoot":"...","createdAt":"..."}
7
+ * {"type":"message","role":"user","content":[...],"timestamp":"..."}
8
+ * {"type":"compact","boundaryIndex":42,"summary":"...","timestamp":"..."}
3
9
  */
4
- import { readFile, writeFile, mkdir, readdir } from 'fs/promises';
10
+ import { readFile, writeFile, mkdir, readdir, appendFile } from 'fs/promises';
11
+ import { existsSync } from 'fs';
5
12
  import { join } from 'path';
6
13
  import { homedir } from 'os';
7
14
  const CMDR_DIR = join(homedir(), '.cmdr');
@@ -37,6 +44,49 @@ function extractSummary(messages) {
37
44
  }
38
45
  return '';
39
46
  }
47
+ function journalPath(sessionId) {
48
+ return join(SESSIONS_DIR, `${sessionId}.jsonl`);
49
+ }
50
+ /** Append a single message to the JSONL session file. */
51
+ export async function appendSessionMessage(sessionId, msg) {
52
+ await ensureDir(SESSIONS_DIR);
53
+ const line = {
54
+ type: 'message',
55
+ role: msg.role,
56
+ content: msg.content,
57
+ timestamp: new Date().toISOString(),
58
+ ...(msg.isCompactSummary ? { isCompactSummary: true } : {}),
59
+ ...(msg.isCompactBoundary ? { isCompactBoundary: true } : {}),
60
+ ...(msg.isVisibleInTranscriptOnly ? { isVisibleInTranscriptOnly: true } : {}),
61
+ ...(msg.isMeta ? { isMeta: true } : {}),
62
+ };
63
+ await appendFile(journalPath(sessionId), JSON.stringify(line) + '\n', 'utf-8');
64
+ }
65
+ /** Write session meta header (called once at session start). */
66
+ export async function writeSessionMeta(sessionId, model, projectRoot) {
67
+ await ensureDir(SESSIONS_DIR);
68
+ const line = {
69
+ type: 'meta',
70
+ sessionId,
71
+ model,
72
+ projectRoot,
73
+ createdAt: new Date().toISOString(),
74
+ };
75
+ await appendFile(journalPath(sessionId), JSON.stringify(line) + '\n', 'utf-8');
76
+ }
77
+ /** Append a compaction marker to the journal. */
78
+ export async function appendCompactMarker(sessionId, boundaryIndex, summary) {
79
+ const line = {
80
+ type: 'compact',
81
+ boundaryIndex,
82
+ summary,
83
+ timestamp: new Date().toISOString(),
84
+ };
85
+ await appendFile(journalPath(sessionId), JSON.stringify(line) + '\n', 'utf-8');
86
+ }
87
+ // ---------------------------------------------------------------------------
88
+ // Save / Load
89
+ // ---------------------------------------------------------------------------
40
90
  export async function saveSession(sessionState, model) {
41
91
  await ensureDir(SESSIONS_DIR);
42
92
  const saved = {
@@ -49,15 +99,55 @@ export async function saveSession(sessionState, model) {
49
99
  toolsUsed: extractToolsUsed(sessionState.messages),
50
100
  summary: extractSummary(sessionState.messages),
51
101
  };
102
+ // Write atomic JSON snapshot (for listSessions/quick load)
52
103
  const filePath = join(SESSIONS_DIR, `${sessionState.id}.json`);
53
104
  await writeFile(filePath, JSON.stringify(saved, null, 2), 'utf-8');
54
105
  return sessionState.id;
55
106
  }
56
107
  export async function loadSession(sessionId) {
57
108
  try {
58
- const filePath = join(SESSIONS_DIR, `${sessionId}.json`);
59
- const data = await readFile(filePath, 'utf-8');
60
- return JSON.parse(data);
109
+ // Try JSON snapshot first (faster)
110
+ const jsonPath = join(SESSIONS_DIR, `${sessionId}.json`);
111
+ if (existsSync(jsonPath)) {
112
+ const data = await readFile(jsonPath, 'utf-8');
113
+ return JSON.parse(data);
114
+ }
115
+ // Fallback: reconstruct from JSONL journal
116
+ const jPath = journalPath(sessionId);
117
+ if (!existsSync(jPath))
118
+ return null;
119
+ const content = await readFile(jPath, 'utf-8');
120
+ const lines = content.trim().split('\n').filter(Boolean);
121
+ let meta = null;
122
+ const messages = [];
123
+ for (const line of lines) {
124
+ const entry = JSON.parse(line);
125
+ if (entry.type === 'meta') {
126
+ meta = entry;
127
+ }
128
+ else if (entry.type === 'message') {
129
+ messages.push({
130
+ role: entry.role,
131
+ content: entry.content,
132
+ ...(entry.isCompactSummary ? { isCompactSummary: true } : {}),
133
+ ...(entry.isCompactBoundary ? { isCompactBoundary: true } : {}),
134
+ ...(entry.isVisibleInTranscriptOnly ? { isVisibleInTranscriptOnly: true } : {}),
135
+ ...(entry.isMeta ? { isMeta: true } : {}),
136
+ });
137
+ }
138
+ }
139
+ if (!meta)
140
+ return null;
141
+ return {
142
+ id: meta.sessionId,
143
+ messages,
144
+ projectRoot: meta.projectRoot,
145
+ model: meta.model,
146
+ createdAt: meta.createdAt,
147
+ lastActivity: new Date().toISOString(),
148
+ toolsUsed: extractToolsUsed(messages),
149
+ summary: extractSummary(messages),
150
+ };
61
151
  }
62
152
  catch {
63
153
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"session-persistence.js","sourceRoot":"","sources":["../../../src/session/session-persistence.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-persistence.js","sourceRoot":"","sources":["../../../src/session/session-persistence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Bash command security checks.
3
+ *
4
+ * Derived from Claude Code's 23 security checks — blocks destructive ops,
5
+ * data exfiltration, and shell injection vectors.
6
+ */
7
+ export interface SecurityResult {
8
+ safe: boolean;
9
+ reason?: string;
10
+ sanitized: string;
11
+ }
12
+ export declare function sanitizeBashCommand(command: string): SecurityResult;
13
+ //# sourceMappingURL=bash-security.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bash-security.d.ts","sourceRoot":"","sources":["../../../../src/tools/built-in/bash-security.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA+BH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,OAAO,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CA0BnE"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Bash command security checks.
3
+ *
4
+ * Derived from Claude Code's 23 security checks — blocks destructive ops,
5
+ * data exfiltration, and shell injection vectors.
6
+ */
7
+ // Destructive or dangerous command patterns
8
+ const BLOCKED_PATTERNS = [
9
+ // Destructive commands
10
+ { pattern: /\brm\s+(-[a-zA-Z]*f[a-zA-Z]*\s+)?\/\s*$/, label: 'rm -rf /' },
11
+ { pattern: /\bchmod\s+(-R\s+)?777\s+\//, label: 'chmod 777 /' },
12
+ { pattern: /\bmkfs\b/, label: 'filesystem format' },
13
+ { pattern: /\bdd\s+.*of=\/dev\//, label: 'dd to device' },
14
+ // Data exfiltration
15
+ { pattern: /\bcurl\s+.*-d\s+.*@/, label: 'curl posting file contents' },
16
+ { pattern: /\bwget\s+.*--post-file/, label: 'wget posting files' },
17
+ // Sensitive file access via subshell
18
+ { pattern: /\$\(.*\bcat\b.*\/etc\/(passwd|shadow)/, label: 'reading sensitive files' },
19
+ ];
20
+ // Zsh builtins that should never come from an LLM
21
+ const BLOCKED_ZSH_BUILTINS = new Set([
22
+ 'bindkey', 'compdef', 'compadd', 'zmodload', 'autoload',
23
+ 'zle', 'zstyle', 'typeset', 'setopt', 'unsetopt',
24
+ 'functions', 'aliases', 'disable', 'enable', 'emulate',
25
+ ]);
26
+ // Zero-width characters (from Claude Code HackerOne finding)
27
+ const ZERO_WIDTH_REGEX = /[\u200B\u200C\u200D\u2060\uFEFF]/g;
28
+ // Zsh equals expansion: =curl → /usr/bin/curl
29
+ const ZSH_EQUALS_REGEX = /(?:^|\s)=[a-zA-Z]/;
30
+ export function sanitizeBashCommand(command) {
31
+ // Strip zero-width characters
32
+ const cleaned = command.replace(ZERO_WIDTH_REGEX, '');
33
+ // Check zsh equals expansion
34
+ if (ZSH_EQUALS_REGEX.test(cleaned)) {
35
+ return { safe: false, reason: 'Zsh equals expansion detected', sanitized: cleaned };
36
+ }
37
+ // Check blocked patterns
38
+ for (const { pattern, label } of BLOCKED_PATTERNS) {
39
+ if (pattern.test(cleaned)) {
40
+ return { safe: false, reason: `Blocked: ${label}`, sanitized: cleaned };
41
+ }
42
+ }
43
+ // Check blocked zsh builtins at start of each segment
44
+ const segments = cleaned.split(/[;|&]/);
45
+ for (const segment of segments) {
46
+ const firstWord = segment.trim().split(/\s/)[0];
47
+ if (BLOCKED_ZSH_BUILTINS.has(firstWord)) {
48
+ return { safe: false, reason: `Blocked shell builtin: ${firstWord}`, sanitized: cleaned };
49
+ }
50
+ }
51
+ return { safe: true, sanitized: cleaned };
52
+ }
53
+ //# sourceMappingURL=bash-security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bash-security.js","sourceRoot":"","sources":["../../../../src/tools/built-in/bash-security.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,4CAA4C;AAC5C,MAAM,gBAAgB,GAAyC;IAC7D,uBAAuB;IACvB,EAAE,OAAO,EAAE,yCAAyC,EAAE,KAAK,EAAE,UAAU,EAAE;IACzE,EAAE,OAAO,EAAE,4BAA4B,EAAE,KAAK,EAAE,aAAa,EAAE;IAC/D,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,mBAAmB,EAAE;IACnD,EAAE,OAAO,EAAE,qBAAqB,EAAE,KAAK,EAAE,cAAc,EAAE;IAEzD,oBAAoB;IACpB,EAAE,OAAO,EAAE,qBAAqB,EAAE,KAAK,EAAE,4BAA4B,EAAE;IACvE,EAAE,OAAO,EAAE,wBAAwB,EAAE,KAAK,EAAE,oBAAoB,EAAE;IAElE,qCAAqC;IACrC,EAAE,OAAO,EAAE,uCAAuC,EAAE,KAAK,EAAE,yBAAyB,EAAE;CACvF,CAAA;AAED,kDAAkD;AAClD,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU;IACvD,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU;IAChD,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS;CACvD,CAAC,CAAA;AAEF,6DAA6D;AAC7D,MAAM,gBAAgB,GAAG,mCAAmC,CAAA;AAE5D,8CAA8C;AAC9C,MAAM,gBAAgB,GAAG,mBAAmB,CAAA;AAQ5C,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,8BAA8B;IAC9B,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAA;IAErD,6BAA6B;IAC7B,IAAI,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACnC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,+BAA+B,EAAE,SAAS,EAAE,OAAO,EAAE,CAAA;IACrF,CAAC;IAED,yBAAyB;IACzB,KAAK,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,gBAAgB,EAAE,CAAC;QAClD,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC1B,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,KAAK,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,CAAA;QACzE,CAAC;IACH,CAAC;IAED,sDAAsD;IACtD,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IACvC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;QAC/C,IAAI,oBAAoB,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YACxC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,0BAA0B,SAAS,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,CAAA;QAC3F,CAAC;IACH,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAA;AAC3C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../../../src/tools/built-in/bash.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,eAAO,MAAM,QAAQ;;;;EA6BnB,CAAA"}
1
+ {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../../../src/tools/built-in/bash.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH,eAAO,MAAM,QAAQ;;;;EAmCnB,CAAA"}
@@ -4,6 +4,7 @@
4
4
  import { spawn } from 'child_process';
5
5
  import { z } from 'zod';
6
6
  import { defineTool } from '../registry.js';
7
+ import { sanitizeBashCommand } from './bash-security.js';
7
8
  const DEFAULT_TIMEOUT_MS = 30_000;
8
9
  export const bashTool = defineTool({
9
10
  name: 'bash',
@@ -16,9 +17,14 @@ export const bashTool = defineTool({
16
17
  cwd: z.string().optional().describe('Working directory for the command.'),
17
18
  }),
18
19
  execute: async (input, context) => {
20
+ // Security check
21
+ const check = sanitizeBashCommand(input.command);
22
+ if (!check.safe) {
23
+ return { data: `Command blocked: ${check.reason}`, isError: true };
24
+ }
19
25
  const timeoutMs = input.timeout ?? DEFAULT_TIMEOUT_MS;
20
26
  const cwd = input.cwd ?? context.cwd ?? process.cwd();
21
- const { stdout, stderr, exitCode } = await runCommand(input.command, cwd, timeoutMs, context.abortSignal);
27
+ const { stdout, stderr, exitCode } = await runCommand(check.sanitized, cwd, timeoutMs, context.abortSignal);
22
28
  const parts = [];
23
29
  if (stdout)
24
30
  parts.push(stdout);