@phuetz/code-buddy 0.1.25 → 0.1.26

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 (253) hide show
  1. package/README.md +1049 -741
  2. package/dist/agent/codebuddy-agent.d.ts +5 -0
  3. package/dist/agent/codebuddy-agent.js +46 -1
  4. package/dist/agent/codebuddy-agent.js.map +1 -1
  5. package/dist/agent/execution/agent-executor.d.ts +12 -0
  6. package/dist/agent/execution/agent-executor.js +147 -6
  7. package/dist/agent/execution/agent-executor.js.map +1 -1
  8. package/dist/agent/lessons-tracker.d.ts +50 -0
  9. package/dist/agent/lessons-tracker.js +234 -0
  10. package/dist/agent/lessons-tracker.js.map +1 -0
  11. package/dist/agent/message-queue.d.ts +39 -2
  12. package/dist/agent/message-queue.js +67 -2
  13. package/dist/agent/message-queue.js.map +1 -1
  14. package/dist/agent/middleware/index.d.ts +1 -0
  15. package/dist/agent/middleware/index.js +1 -0
  16. package/dist/agent/middleware/index.js.map +1 -1
  17. package/dist/agent/middleware/workflow-guard.d.ts +21 -0
  18. package/dist/agent/middleware/workflow-guard.js +94 -0
  19. package/dist/agent/middleware/workflow-guard.js.map +1 -0
  20. package/dist/agent/repo-profiler.d.ts +61 -0
  21. package/dist/agent/repo-profiler.js +295 -0
  22. package/dist/agent/repo-profiler.js.map +1 -0
  23. package/dist/agent/response-constraint.d.ts +61 -0
  24. package/dist/agent/response-constraint.js +91 -0
  25. package/dist/agent/response-constraint.js.map +1 -0
  26. package/dist/agent/todo-tracker.d.ts +67 -0
  27. package/dist/agent/todo-tracker.js +245 -0
  28. package/dist/agent/todo-tracker.js.map +1 -0
  29. package/dist/agent/tool-handler.d.ts +11 -0
  30. package/dist/agent/tool-handler.js +79 -1
  31. package/dist/agent/tool-handler.js.map +1 -1
  32. package/dist/agent/types.d.ts +20 -2
  33. package/dist/agent/wide-research.d.ts +93 -0
  34. package/dist/agent/wide-research.js +232 -0
  35. package/dist/agent/wide-research.js.map +1 -0
  36. package/dist/channels/index.d.ts +2 -0
  37. package/dist/channels/index.js +2 -0
  38. package/dist/channels/index.js.map +1 -1
  39. package/dist/channels/pro/callback-router.d.ts +54 -0
  40. package/dist/channels/pro/callback-router.js +178 -0
  41. package/dist/channels/pro/callback-router.js.map +1 -0
  42. package/dist/channels/pro/ci-watcher.d.ts +86 -0
  43. package/dist/channels/pro/ci-watcher.js +343 -0
  44. package/dist/channels/pro/ci-watcher.js.map +1 -0
  45. package/dist/channels/pro/diff-first.d.ts +63 -0
  46. package/dist/channels/pro/diff-first.js +187 -0
  47. package/dist/channels/pro/diff-first.js.map +1 -0
  48. package/dist/channels/pro/enhanced-commands.d.ts +83 -0
  49. package/dist/channels/pro/enhanced-commands.js +218 -0
  50. package/dist/channels/pro/enhanced-commands.js.map +1 -0
  51. package/dist/channels/pro/index.d.ts +19 -0
  52. package/dist/channels/pro/index.js +21 -0
  53. package/dist/channels/pro/index.js.map +1 -0
  54. package/dist/channels/pro/pro-features.d.ts +79 -0
  55. package/dist/channels/pro/pro-features.js +203 -0
  56. package/dist/channels/pro/pro-features.js.map +1 -0
  57. package/dist/channels/pro/run-commands.d.ts +59 -0
  58. package/dist/channels/pro/run-commands.js +122 -0
  59. package/dist/channels/pro/run-commands.js.map +1 -0
  60. package/dist/channels/pro/run-tracker.d.ts +74 -0
  61. package/dist/channels/pro/run-tracker.js +252 -0
  62. package/dist/channels/pro/run-tracker.js.map +1 -0
  63. package/dist/channels/pro/scoped-auth.d.ts +97 -0
  64. package/dist/channels/pro/scoped-auth.js +340 -0
  65. package/dist/channels/pro/scoped-auth.js.map +1 -0
  66. package/dist/channels/pro/text-formatter.d.ts +27 -0
  67. package/dist/channels/pro/text-formatter.js +269 -0
  68. package/dist/channels/pro/text-formatter.js.map +1 -0
  69. package/dist/channels/pro/types.d.ts +242 -0
  70. package/dist/channels/pro/types.js +14 -0
  71. package/dist/channels/pro/types.js.map +1 -0
  72. package/dist/channels/streaming-policy.d.ts +66 -0
  73. package/dist/channels/streaming-policy.js +266 -0
  74. package/dist/channels/streaming-policy.js.map +1 -0
  75. package/dist/channels/telegram/ci-watcher.d.ts +5 -0
  76. package/dist/channels/telegram/ci-watcher.js +5 -0
  77. package/dist/channels/telegram/ci-watcher.js.map +1 -0
  78. package/dist/channels/telegram/client.d.ts +28 -0
  79. package/dist/channels/telegram/client.js +147 -1
  80. package/dist/channels/telegram/client.js.map +1 -1
  81. package/dist/channels/telegram/diff-first.d.ts +5 -0
  82. package/dist/channels/telegram/diff-first.js +5 -0
  83. package/dist/channels/telegram/diff-first.js.map +1 -0
  84. package/dist/channels/telegram/enhanced-commands.d.ts +6 -0
  85. package/dist/channels/telegram/enhanced-commands.js +6 -0
  86. package/dist/channels/telegram/enhanced-commands.js.map +1 -0
  87. package/dist/channels/telegram/index.d.ts +6 -0
  88. package/dist/channels/telegram/index.js +6 -0
  89. package/dist/channels/telegram/index.js.map +1 -1
  90. package/dist/channels/telegram/pro-formatter.d.ts +30 -0
  91. package/dist/channels/telegram/pro-formatter.js +276 -0
  92. package/dist/channels/telegram/pro-formatter.js.map +1 -0
  93. package/dist/channels/telegram/run-commands.d.ts +5 -0
  94. package/dist/channels/telegram/run-commands.js +6 -0
  95. package/dist/channels/telegram/run-commands.js.map +1 -0
  96. package/dist/channels/telegram/run-tracker.d.ts +5 -0
  97. package/dist/channels/telegram/run-tracker.js +5 -0
  98. package/dist/channels/telegram/run-tracker.js.map +1 -0
  99. package/dist/channels/telegram/scoped-auth.d.ts +6 -0
  100. package/dist/channels/telegram/scoped-auth.js +5 -0
  101. package/dist/channels/telegram/scoped-auth.js.map +1 -0
  102. package/dist/channels/telegram/types.d.ts +34 -0
  103. package/dist/codebuddy/client.js +14 -1
  104. package/dist/codebuddy/client.js.map +1 -1
  105. package/dist/commands/dev/index.d.ts +12 -0
  106. package/dist/commands/dev/index.js +231 -0
  107. package/dist/commands/dev/index.js.map +1 -0
  108. package/dist/commands/dev/workflows.d.ts +31 -0
  109. package/dist/commands/dev/workflows.js +214 -0
  110. package/dist/commands/dev/workflows.js.map +1 -0
  111. package/dist/commands/execpolicy.d.ts +17 -0
  112. package/dist/commands/execpolicy.js +155 -0
  113. package/dist/commands/execpolicy.js.map +1 -0
  114. package/dist/commands/knowledge.d.ts +13 -0
  115. package/dist/commands/knowledge.js +142 -0
  116. package/dist/commands/knowledge.js.map +1 -0
  117. package/dist/commands/lessons.d.ts +11 -0
  118. package/dist/commands/lessons.js +129 -0
  119. package/dist/commands/lessons.js.map +1 -0
  120. package/dist/commands/pairing.d.ts +14 -0
  121. package/dist/commands/pairing.js +132 -0
  122. package/dist/commands/pairing.js.map +1 -0
  123. package/dist/commands/research/index.d.ts +13 -0
  124. package/dist/commands/research/index.js +91 -0
  125. package/dist/commands/research/index.js.map +1 -0
  126. package/dist/commands/run-cli/index.d.ts +11 -0
  127. package/dist/commands/run-cli/index.js +49 -0
  128. package/dist/commands/run-cli/index.js.map +1 -0
  129. package/dist/commands/todos.d.ts +9 -0
  130. package/dist/commands/todos.js +119 -0
  131. package/dist/commands/todos.js.map +1 -0
  132. package/dist/config/toml-config.d.ts +21 -0
  133. package/dist/config/toml-config.js +15 -0
  134. package/dist/config/toml-config.js.map +1 -1
  135. package/dist/context/enhanced-compression.js +12 -1
  136. package/dist/context/enhanced-compression.js.map +1 -1
  137. package/dist/context/observation-variator.d.ts +44 -0
  138. package/dist/context/observation-variator.js +83 -0
  139. package/dist/context/observation-variator.js.map +1 -0
  140. package/dist/context/precompaction-flush.d.ts +40 -0
  141. package/dist/context/precompaction-flush.js +134 -0
  142. package/dist/context/precompaction-flush.js.map +1 -0
  143. package/dist/context/restorable-compression.d.ts +80 -0
  144. package/dist/context/restorable-compression.js +228 -0
  145. package/dist/context/restorable-compression.js.map +1 -0
  146. package/dist/daemon/daily-reset.d.ts +77 -0
  147. package/dist/daemon/daily-reset.js +175 -0
  148. package/dist/daemon/daily-reset.js.map +1 -0
  149. package/dist/daemon/index.d.ts +1 -0
  150. package/dist/daemon/index.js +1 -0
  151. package/dist/daemon/index.js.map +1 -1
  152. package/dist/index.js +53 -0
  153. package/dist/index.js.map +1 -1
  154. package/dist/knowledge/knowledge-manager.d.ts +77 -0
  155. package/dist/knowledge/knowledge-manager.js +244 -0
  156. package/dist/knowledge/knowledge-manager.js.map +1 -0
  157. package/dist/observability/run-store.d.ts +133 -0
  158. package/dist/observability/run-store.js +419 -0
  159. package/dist/observability/run-store.js.map +1 -0
  160. package/dist/observability/run-viewer.d.ts +33 -0
  161. package/dist/observability/run-viewer.js +254 -0
  162. package/dist/observability/run-viewer.js.map +1 -0
  163. package/dist/optimization/cache-breakpoints.d.ts +52 -0
  164. package/dist/optimization/cache-breakpoints.js +97 -0
  165. package/dist/optimization/cache-breakpoints.js.map +1 -0
  166. package/dist/persistence/session-store.d.ts +3 -1
  167. package/dist/persistence/session-store.js +1 -1
  168. package/dist/persistence/session-store.js.map +1 -1
  169. package/dist/prompts/system-base.js +51 -7
  170. package/dist/prompts/system-base.js.map +1 -1
  171. package/dist/prompts/variation-injector.d.ts +55 -0
  172. package/dist/prompts/variation-injector.js +171 -0
  173. package/dist/prompts/variation-injector.js.map +1 -0
  174. package/dist/prompts/workflow-rules.d.ts +10 -0
  175. package/dist/prompts/workflow-rules.js +79 -0
  176. package/dist/prompts/workflow-rules.js.map +1 -0
  177. package/dist/sandbox/execpolicy.d.ts +45 -0
  178. package/dist/sandbox/execpolicy.js +80 -0
  179. package/dist/sandbox/execpolicy.js.map +1 -1
  180. package/dist/sandbox/os-sandbox.d.ts +25 -0
  181. package/dist/sandbox/os-sandbox.js +73 -0
  182. package/dist/sandbox/os-sandbox.js.map +1 -1
  183. package/dist/security/security-audit.d.ts +10 -0
  184. package/dist/security/security-audit.js +116 -0
  185. package/dist/security/security-audit.js.map +1 -1
  186. package/dist/security/shell-env-policy.d.ts +45 -0
  187. package/dist/security/shell-env-policy.js +141 -0
  188. package/dist/security/shell-env-policy.js.map +1 -0
  189. package/dist/security/ssrf-guard.d.ts +61 -0
  190. package/dist/security/ssrf-guard.js +382 -0
  191. package/dist/security/ssrf-guard.js.map +1 -0
  192. package/dist/security/write-policy.d.ts +57 -0
  193. package/dist/security/write-policy.js +117 -0
  194. package/dist/security/write-policy.js.map +1 -0
  195. package/dist/services/prompt-builder.js +37 -0
  196. package/dist/services/prompt-builder.js.map +1 -1
  197. package/dist/themes/theme-schema.d.ts +10 -10
  198. package/dist/tools/ask-human-tool.d.ts +62 -0
  199. package/dist/tools/ask-human-tool.js +112 -0
  200. package/dist/tools/ask-human-tool.js.map +1 -0
  201. package/dist/tools/bash/bash-tool.d.ts +15 -0
  202. package/dist/tools/bash/bash-tool.js +62 -0
  203. package/dist/tools/bash/bash-tool.js.map +1 -1
  204. package/dist/tools/bash/command-validator.d.ts +1 -0
  205. package/dist/tools/bash/command-validator.js +5 -0
  206. package/dist/tools/bash/command-validator.js.map +1 -1
  207. package/dist/tools/create-skill-tool.d.ts +87 -0
  208. package/dist/tools/create-skill-tool.js +142 -0
  209. package/dist/tools/create-skill-tool.js.map +1 -0
  210. package/dist/tools/fetch-tool.js +5 -3
  211. package/dist/tools/fetch-tool.js.map +1 -1
  212. package/dist/tools/index.d.ts +1 -0
  213. package/dist/tools/index.js +1 -0
  214. package/dist/tools/index.js.map +1 -1
  215. package/dist/tools/plan-tool.d.ts +22 -0
  216. package/dist/tools/plan-tool.js +128 -0
  217. package/dist/tools/plan-tool.js.map +1 -0
  218. package/dist/tools/registry/attention-tools.d.ts +32 -0
  219. package/dist/tools/registry/attention-tools.js +225 -0
  220. package/dist/tools/registry/attention-tools.js.map +1 -0
  221. package/dist/tools/registry/index.d.ts +9 -1
  222. package/dist/tools/registry/index.js +30 -2
  223. package/dist/tools/registry/index.js.map +1 -1
  224. package/dist/tools/registry/knowledge-tools.d.ts +46 -0
  225. package/dist/tools/registry/knowledge-tools.js +293 -0
  226. package/dist/tools/registry/knowledge-tools.js.map +1 -0
  227. package/dist/tools/registry/lessons-tools.d.ts +48 -0
  228. package/dist/tools/registry/lessons-tools.js +359 -0
  229. package/dist/tools/registry/lessons-tools.js.map +1 -0
  230. package/dist/tools/registry/plan-tools.d.ts +2 -0
  231. package/dist/tools/registry/plan-tools.js +7 -0
  232. package/dist/tools/registry/plan-tools.js.map +1 -0
  233. package/dist/tools/registry/script-tools.d.ts +2 -0
  234. package/dist/tools/registry/script-tools.js +7 -0
  235. package/dist/tools/registry/script-tools.js.map +1 -0
  236. package/dist/tools/registry/tool-aliases.d.ts +44 -0
  237. package/dist/tools/registry/tool-aliases.js +130 -0
  238. package/dist/tools/registry/tool-aliases.js.map +1 -0
  239. package/dist/tools/run-script-tool.d.ts +13 -0
  240. package/dist/tools/run-script-tool.js +146 -0
  241. package/dist/tools/run-script-tool.js.map +1 -0
  242. package/dist/tools/web-search.d.ts +25 -0
  243. package/dist/tools/web-search.js +68 -6
  244. package/dist/tools/web-search.js.map +1 -1
  245. package/dist/utils/config-validation/schema.d.ts +2 -2
  246. package/dist/utils/debug-logger.d.ts +1 -1
  247. package/dist/utils/stable-json.d.ts +27 -0
  248. package/dist/utils/stable-json.js +50 -0
  249. package/dist/utils/stable-json.js.map +1 -0
  250. package/dist/webhooks/webhook-manager.d.ts +7 -0
  251. package/dist/webhooks/webhook-manager.js +29 -0
  252. package/dist/webhooks/webhook-manager.js.map +1 -1
  253. package/package.json +1 -1
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Restorable Compression — Manus AI context engineering pattern
3
+ *
4
+ * Instead of lossy summarisation (which discards content permanently),
5
+ * this module extracts structural identifiers (file paths, URLs, tool
6
+ * call IDs, line ranges) from messages that are about to be dropped,
7
+ * then stores the original content indexed by those identifiers.
8
+ *
9
+ * The agent can later call `restore_context(identifier)` to re-fetch
10
+ * the full content on demand, making context compression reversible.
11
+ *
12
+ * This is complementary to summarisation: a short summary of a long
13
+ * file-read result is kept in the context, while the full content is
14
+ * recoverable via its file path identifier.
15
+ *
16
+ * Ref: "Context Engineering for AI Agents: Lessons from Building Manus"
17
+ * https://manus.im/blog/Context-Engineering-for-AI-Agents-Lessons-from-Building-Manus
18
+ */
19
+ export interface CompressibleMessage {
20
+ role: string;
21
+ content: string | null;
22
+ tool_call_id?: string;
23
+ name?: string;
24
+ }
25
+ export interface CompressionResult {
26
+ /** Compressed messages (identifiers preserved, full content dropped) */
27
+ messages: CompressibleMessage[];
28
+ /** Identifiers that were extracted and stored */
29
+ identifiers: string[];
30
+ /** Number of tokens saved (estimated) */
31
+ tokensSaved: number;
32
+ }
33
+ export interface RestoreResult {
34
+ found: boolean;
35
+ content: string;
36
+ identifier: string;
37
+ }
38
+ export declare class RestorableCompressor {
39
+ /** identifier → original content */
40
+ private store;
41
+ /**
42
+ * Compress a slice of messages that are about to be dropped.
43
+ *
44
+ * For each message, identifiers are extracted and the full content is
45
+ * stored. The message content is replaced with a compact stub listing
46
+ * the available identifiers.
47
+ */
48
+ compress(messages: CompressibleMessage[]): CompressionResult;
49
+ /**
50
+ * Restore the original content for an identifier.
51
+ *
52
+ * For file path identifiers, attempts to read from disk as a fallback.
53
+ * For URLs, returns a hint to use web_fetch.
54
+ */
55
+ restore(identifier: string): RestoreResult;
56
+ /**
57
+ * Persist a tool result to disk under `.codebuddy/tool-results/<callId>.txt`.
58
+ * This gives the restore_context tool a reliable disk-backed source and enables
59
+ * the compact/full dual-representation pattern (Manus AI #19).
60
+ *
61
+ * @param callId - Tool call ID (e.g. call_abc123 or toolu_xyz)
62
+ * @param content - Full tool output
63
+ * @param workDir - Working directory (defaults to process.cwd())
64
+ */
65
+ writeToolResult(callId: string, content: string, workDir?: string): void;
66
+ /**
67
+ * Read a tool result from disk (`.codebuddy/tool-results/<callId>.txt`).
68
+ * Used by restore_context when the in-memory store has been evicted.
69
+ */
70
+ private readToolResultFromDisk;
71
+ /** List all stored identifiers */
72
+ listIdentifiers(): string[];
73
+ /** Total number of bytes stored */
74
+ storeSize(): number;
75
+ /** Evict oldest entries if store exceeds maxBytes (default 10 MB) */
76
+ evict(maxBytes?: number): void;
77
+ }
78
+ export declare function getRestorableCompressor(): RestorableCompressor;
79
+ /** Reset singleton (for tests) */
80
+ export declare function resetRestorableCompressor(): void;
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Restorable Compression — Manus AI context engineering pattern
3
+ *
4
+ * Instead of lossy summarisation (which discards content permanently),
5
+ * this module extracts structural identifiers (file paths, URLs, tool
6
+ * call IDs, line ranges) from messages that are about to be dropped,
7
+ * then stores the original content indexed by those identifiers.
8
+ *
9
+ * The agent can later call `restore_context(identifier)` to re-fetch
10
+ * the full content on demand, making context compression reversible.
11
+ *
12
+ * This is complementary to summarisation: a short summary of a long
13
+ * file-read result is kept in the context, while the full content is
14
+ * recoverable via its file path identifier.
15
+ *
16
+ * Ref: "Context Engineering for AI Agents: Lessons from Building Manus"
17
+ * https://manus.im/blog/Context-Engineering-for-AI-Agents-Lessons-from-Building-Manus
18
+ */
19
+ import * as fs from 'fs';
20
+ import * as path from 'path';
21
+ import { logger } from '../utils/logger.js';
22
+ // ============================================================================
23
+ // Identifier extractors
24
+ // ============================================================================
25
+ // File paths: absolute or relative, with extensions
26
+ const FILE_PATH_RE = /(?:^|\s|["'`(])(\/?(?:[\w.-]+\/)*[\w.-]+\.(?:ts|js|py|json|md|txt|yaml|yml|sh|go|rs|java|cpp|c|h|rb|php|swift|kt|cs|html|css|sql|env|toml|cfg|conf|xml)(?::\d+(?:-\d+)?)?)/g;
27
+ // URLs
28
+ const URL_RE = /https?:\/\/[^\s"'<>)]+/g;
29
+ // Tool call IDs (Anthropic/OpenAI style)
30
+ const TOOL_CALL_ID_RE = /\b(call_[a-zA-Z0-9]+|toolu_[a-zA-Z0-9]+)\b/g;
31
+ function extractIdentifiers(text) {
32
+ const ids = new Set();
33
+ for (const m of text.matchAll(FILE_PATH_RE)) {
34
+ const raw = m[1].trim().replace(/['"`:]/g, '');
35
+ if (raw.length > 3)
36
+ ids.add(raw);
37
+ }
38
+ for (const m of text.matchAll(URL_RE)) {
39
+ const url = m[0].replace(/[.,;)]+$/, ''); // strip trailing punctuation
40
+ ids.add(url);
41
+ }
42
+ for (const m of text.matchAll(TOOL_CALL_ID_RE)) {
43
+ ids.add(m[1]);
44
+ }
45
+ return [...ids];
46
+ }
47
+ // ============================================================================
48
+ // RestorableCompressor
49
+ // ============================================================================
50
+ export class RestorableCompressor {
51
+ /** identifier → original content */
52
+ store = new Map();
53
+ /**
54
+ * Compress a slice of messages that are about to be dropped.
55
+ *
56
+ * For each message, identifiers are extracted and the full content is
57
+ * stored. The message content is replaced with a compact stub listing
58
+ * the available identifiers.
59
+ */
60
+ compress(messages) {
61
+ const compressed = [];
62
+ const allIdentifiers = [];
63
+ let tokensSaved = 0;
64
+ for (const msg of messages) {
65
+ const content = msg.content ?? '';
66
+ if (!content || content.length < 200) {
67
+ // Short messages: keep as-is
68
+ compressed.push(msg);
69
+ continue;
70
+ }
71
+ const ids = extractIdentifiers(content);
72
+ if (ids.length === 0) {
73
+ // No identifiers to preserve — keep original
74
+ compressed.push(msg);
75
+ continue;
76
+ }
77
+ // Store original content indexed by each identifier
78
+ for (const id of ids) {
79
+ if (!this.store.has(id)) {
80
+ this.store.set(id, content);
81
+ }
82
+ }
83
+ allIdentifiers.push(...ids);
84
+ tokensSaved += Math.floor(content.length / 4); // rough token estimate
85
+ // Replace with a compact stub
86
+ const stub = `[Content compressed — identifiers: ${ids.slice(0, 5).join(', ')}${ids.length > 5 ? ` +${ids.length - 5} more` : ''}. Use restore_context(identifier) to retrieve.]`;
87
+ compressed.push({ ...msg, content: stub });
88
+ logger.debug('RestorableCompressor: compressed message', {
89
+ identifiers: ids.length,
90
+ originalLen: content.length,
91
+ stubLen: stub.length,
92
+ });
93
+ }
94
+ return {
95
+ messages: compressed,
96
+ identifiers: [...new Set(allIdentifiers)],
97
+ tokensSaved,
98
+ };
99
+ }
100
+ /**
101
+ * Restore the original content for an identifier.
102
+ *
103
+ * For file path identifiers, attempts to read from disk as a fallback.
104
+ * For URLs, returns a hint to use web_fetch.
105
+ */
106
+ restore(identifier) {
107
+ // 1. Check in-memory store
108
+ const stored = this.store.get(identifier);
109
+ if (stored) {
110
+ return { found: true, content: stored, identifier };
111
+ }
112
+ // 2. Tool call ID — check disk-backed store
113
+ if (identifier.startsWith('call_') || identifier.startsWith('toulu_') || identifier.startsWith('toolu_')) {
114
+ const diskContent = this.readToolResultFromDisk(identifier);
115
+ if (diskContent) {
116
+ return { found: true, content: diskContent, identifier };
117
+ }
118
+ }
119
+ // 3. File path fallback — try reading from disk
120
+ if (!identifier.startsWith('http') && !identifier.startsWith('call_') && !identifier.startsWith('toolu_')) {
121
+ try {
122
+ // Strip line range if present (file.ts:10-50 → file.ts)
123
+ const filePath = identifier.split(':')[0];
124
+ if (fs.existsSync(filePath)) {
125
+ const content = fs.readFileSync(filePath, 'utf-8');
126
+ this.store.set(identifier, content); // cache for future
127
+ return { found: true, content, identifier };
128
+ }
129
+ }
130
+ catch {
131
+ // ignore
132
+ }
133
+ }
134
+ // 3. URL hint
135
+ if (identifier.startsWith('http')) {
136
+ return {
137
+ found: false,
138
+ content: `URL content not cached. Use web_fetch("${identifier}") to retrieve it.`,
139
+ identifier,
140
+ };
141
+ }
142
+ return {
143
+ found: false,
144
+ content: `Identifier "${identifier}" not found in restoration store.`,
145
+ identifier,
146
+ };
147
+ }
148
+ /**
149
+ * Persist a tool result to disk under `.codebuddy/tool-results/<callId>.txt`.
150
+ * This gives the restore_context tool a reliable disk-backed source and enables
151
+ * the compact/full dual-representation pattern (Manus AI #19).
152
+ *
153
+ * @param callId - Tool call ID (e.g. call_abc123 or toolu_xyz)
154
+ * @param content - Full tool output
155
+ * @param workDir - Working directory (defaults to process.cwd())
156
+ */
157
+ writeToolResult(callId, content, workDir = process.cwd()) {
158
+ try {
159
+ const dir = path.join(workDir, '.codebuddy', 'tool-results');
160
+ if (!fs.existsSync(dir)) {
161
+ fs.mkdirSync(dir, { recursive: true });
162
+ }
163
+ const filePath = path.join(dir, `${callId}.txt`);
164
+ fs.writeFileSync(filePath, content, 'utf-8');
165
+ // Also store in memory for fast access
166
+ this.store.set(callId, content);
167
+ }
168
+ catch (err) {
169
+ // Non-critical: disk write failure should not break tool execution
170
+ logger.debug('RestorableCompressor: failed to write tool result to disk', { callId, err });
171
+ }
172
+ }
173
+ /**
174
+ * Read a tool result from disk (`.codebuddy/tool-results/<callId>.txt`).
175
+ * Used by restore_context when the in-memory store has been evicted.
176
+ */
177
+ readToolResultFromDisk(callId, workDir = process.cwd()) {
178
+ try {
179
+ const filePath = path.join(workDir, '.codebuddy', 'tool-results', `${callId}.txt`);
180
+ if (fs.existsSync(filePath)) {
181
+ const content = fs.readFileSync(filePath, 'utf-8');
182
+ this.store.set(callId, content); // cache back into memory
183
+ return content;
184
+ }
185
+ }
186
+ catch {
187
+ // ignore
188
+ }
189
+ return null;
190
+ }
191
+ /** List all stored identifiers */
192
+ listIdentifiers() {
193
+ return [...this.store.keys()];
194
+ }
195
+ /** Total number of bytes stored */
196
+ storeSize() {
197
+ let total = 0;
198
+ for (const v of this.store.values())
199
+ total += v.length;
200
+ return total;
201
+ }
202
+ /** Evict oldest entries if store exceeds maxBytes (default 10 MB) */
203
+ evict(maxBytes = 10 * 1024 * 1024) {
204
+ while (this.storeSize() > maxBytes && this.store.size > 0) {
205
+ const firstKey = this.store.keys().next().value;
206
+ if (firstKey !== undefined) {
207
+ this.store.delete(firstKey);
208
+ }
209
+ else {
210
+ break;
211
+ }
212
+ }
213
+ }
214
+ }
215
+ // ============================================================================
216
+ // Singleton
217
+ // ============================================================================
218
+ let _instance = null;
219
+ export function getRestorableCompressor() {
220
+ if (!_instance)
221
+ _instance = new RestorableCompressor();
222
+ return _instance;
223
+ }
224
+ /** Reset singleton (for tests) */
225
+ export function resetRestorableCompressor() {
226
+ _instance = null;
227
+ }
228
+ //# sourceMappingURL=restorable-compression.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restorable-compression.js","sourceRoot":"","sources":["../../src/context/restorable-compression.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Daily Session Reset — OpenClaw-inspired context boundary
3
+ *
4
+ * Automatically resets the conversation context at a configurable time
5
+ * each day (default: 04:00 local time). This prevents unbounded context
6
+ * growth in long-running daemon sessions and mirrors the daily boundary
7
+ * reset pattern in OpenClaw.
8
+ *
9
+ * What is reset:
10
+ * - In-memory conversation history (messages array)
11
+ * - Cached tool selection results
12
+ *
13
+ * What is PRESERVED:
14
+ * - MEMORY.md (durable facts)
15
+ * - HEARTBEAT.md (task checklist)
16
+ * - Session metadata (model, cost counters)
17
+ * - All files on disk (todo.md, PLAN.md, etc.)
18
+ *
19
+ * After reset the agent posts a summary message noting the daily boundary
20
+ * so the conversation log remains intelligible.
21
+ *
22
+ * Ref: OpenClaw session management compaction docs
23
+ * https://docs.openclaw.ai/reference/session-management-compaction
24
+ */
25
+ import { EventEmitter } from 'events';
26
+ export interface DailyResetConfig {
27
+ /** Hour of the day for the reset (0-23). Default: 4 */
28
+ resetHour: number;
29
+ /** Minute of the reset (0-59). Default: 0 */
30
+ resetMinute: number;
31
+ /** IANA timezone identifier. Default: system local */
32
+ timezone?: string;
33
+ /** Whether the daily reset is enabled. Default: true */
34
+ enabled: boolean;
35
+ /** Post a summary message after reset. Default: true */
36
+ postSummary: boolean;
37
+ }
38
+ export interface ResetResult {
39
+ triggeredAt: Date;
40
+ /** Number of messages cleared */
41
+ messagesCleared: number;
42
+ /** Summary message posted to conversation (or null if postSummary is false) */
43
+ summaryMessage: string | null;
44
+ }
45
+ export declare class DailyResetManager extends EventEmitter {
46
+ private config;
47
+ private timer;
48
+ private lastResetDate;
49
+ constructor(config?: Partial<DailyResetConfig>);
50
+ /**
51
+ * Start the daily reset scheduler.
52
+ * Call this once when the daemon starts.
53
+ */
54
+ start(): void;
55
+ stop(): void;
56
+ /** Returns milliseconds until the next reset window. */
57
+ msUntilNextReset(): number;
58
+ private scheduleNext;
59
+ /**
60
+ * Perform the daily reset on the provided messages array (modified in-place).
61
+ *
62
+ * @param messages - The agent's LLM messages array to clear
63
+ * @param systemMessage - Optional system message to keep at position [0]
64
+ */
65
+ runReset(messages: Array<{
66
+ role: string;
67
+ content: string | null;
68
+ }>, systemMessage?: {
69
+ role: string;
70
+ content: string;
71
+ }): Promise<ResetResult>;
72
+ private buildSummaryMessage;
73
+ getConfig(): Readonly<DailyResetConfig>;
74
+ isEnabled(): boolean;
75
+ }
76
+ export declare function getDailyResetManager(config?: Partial<DailyResetConfig>): DailyResetManager;
77
+ export declare function resetDailyResetManager(): void;
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Daily Session Reset — OpenClaw-inspired context boundary
3
+ *
4
+ * Automatically resets the conversation context at a configurable time
5
+ * each day (default: 04:00 local time). This prevents unbounded context
6
+ * growth in long-running daemon sessions and mirrors the daily boundary
7
+ * reset pattern in OpenClaw.
8
+ *
9
+ * What is reset:
10
+ * - In-memory conversation history (messages array)
11
+ * - Cached tool selection results
12
+ *
13
+ * What is PRESERVED:
14
+ * - MEMORY.md (durable facts)
15
+ * - HEARTBEAT.md (task checklist)
16
+ * - Session metadata (model, cost counters)
17
+ * - All files on disk (todo.md, PLAN.md, etc.)
18
+ *
19
+ * After reset the agent posts a summary message noting the daily boundary
20
+ * so the conversation log remains intelligible.
21
+ *
22
+ * Ref: OpenClaw session management compaction docs
23
+ * https://docs.openclaw.ai/reference/session-management-compaction
24
+ */
25
+ import { EventEmitter } from 'events';
26
+ import { logger } from '../utils/logger.js';
27
+ // ============================================================================
28
+ // DailyResetManager
29
+ // ============================================================================
30
+ export class DailyResetManager extends EventEmitter {
31
+ config;
32
+ timer = null;
33
+ lastResetDate = null; // 'YYYY-MM-DD'
34
+ constructor(config = {}) {
35
+ super();
36
+ this.config = {
37
+ resetHour: config.resetHour ?? 4,
38
+ resetMinute: config.resetMinute ?? 0,
39
+ timezone: config.timezone,
40
+ enabled: config.enabled ?? true,
41
+ postSummary: config.postSummary ?? true,
42
+ };
43
+ }
44
+ // --------------------------------------------------------------------------
45
+ // Lifecycle
46
+ // --------------------------------------------------------------------------
47
+ /**
48
+ * Start the daily reset scheduler.
49
+ * Call this once when the daemon starts.
50
+ */
51
+ start() {
52
+ if (!this.config.enabled)
53
+ return;
54
+ this.scheduleNext();
55
+ logger.debug('DailyResetManager started', {
56
+ resetHour: this.config.resetHour,
57
+ resetMinute: this.config.resetMinute,
58
+ });
59
+ }
60
+ stop() {
61
+ if (this.timer) {
62
+ clearTimeout(this.timer);
63
+ this.timer = null;
64
+ }
65
+ }
66
+ // --------------------------------------------------------------------------
67
+ // Scheduling
68
+ // --------------------------------------------------------------------------
69
+ /** Returns milliseconds until the next reset window. */
70
+ msUntilNextReset() {
71
+ const now = new Date();
72
+ const next = new Date(now);
73
+ next.setHours(this.config.resetHour, this.config.resetMinute, 0, 0);
74
+ if (next <= now) {
75
+ // Already past today's reset time — schedule for tomorrow
76
+ next.setDate(next.getDate() + 1);
77
+ }
78
+ return next.getTime() - now.getTime();
79
+ }
80
+ scheduleNext() {
81
+ const ms = this.msUntilNextReset();
82
+ logger.debug('DailyResetManager: next reset in', {
83
+ minutes: Math.round(ms / 60_000),
84
+ });
85
+ this.timer = setTimeout(() => {
86
+ this.runReset([]).catch(err => {
87
+ logger.error('DailyResetManager: reset failed', { err });
88
+ });
89
+ this.scheduleNext(); // reschedule for tomorrow
90
+ }, ms);
91
+ // Allow Node to exit if this is the only pending timer
92
+ if (this.timer.unref)
93
+ this.timer.unref();
94
+ }
95
+ // --------------------------------------------------------------------------
96
+ // Reset logic
97
+ // --------------------------------------------------------------------------
98
+ /**
99
+ * Perform the daily reset on the provided messages array (modified in-place).
100
+ *
101
+ * @param messages - The agent's LLM messages array to clear
102
+ * @param systemMessage - Optional system message to keep at position [0]
103
+ */
104
+ async runReset(messages, systemMessage) {
105
+ const today = new Date().toISOString().split('T')[0];
106
+ // Avoid duplicate resets on the same day
107
+ if (this.lastResetDate === today) {
108
+ return {
109
+ triggeredAt: new Date(),
110
+ messagesCleared: 0,
111
+ summaryMessage: null,
112
+ };
113
+ }
114
+ this.lastResetDate = today;
115
+ const messagesCleared = messages.length;
116
+ // Clear messages (in-place)
117
+ messages.splice(0, messages.length);
118
+ // Re-inject system message if provided
119
+ if (systemMessage) {
120
+ messages.push(systemMessage);
121
+ }
122
+ const summaryMessage = this.config.postSummary
123
+ ? this.buildSummaryMessage(today, messagesCleared)
124
+ : null;
125
+ if (summaryMessage && messages.length > 0) {
126
+ // Append the summary as an assistant message so it appears in the log
127
+ messages.push({ role: 'assistant', content: summaryMessage });
128
+ }
129
+ const result = {
130
+ triggeredAt: new Date(),
131
+ messagesCleared,
132
+ summaryMessage,
133
+ };
134
+ this.emit('reset', result);
135
+ logger.info('DailyResetManager: daily reset completed', {
136
+ date: today,
137
+ messagesCleared,
138
+ });
139
+ return result;
140
+ }
141
+ // --------------------------------------------------------------------------
142
+ // Helpers
143
+ // --------------------------------------------------------------------------
144
+ buildSummaryMessage(date, cleared) {
145
+ return [
146
+ `---`,
147
+ `**[Daily context boundary — ${date}]**`,
148
+ `Conversation history was automatically cleared at ${String(this.config.resetHour).padStart(2, '0')}:${String(this.config.resetMinute).padStart(2, '0')} to maintain a fresh context window.`,
149
+ `${cleared} messages from the previous session were cleared.`,
150
+ `MEMORY.md, HEARTBEAT.md, todo.md, and all project files are preserved.`,
151
+ `---`,
152
+ ].join('\n');
153
+ }
154
+ getConfig() {
155
+ return { ...this.config };
156
+ }
157
+ isEnabled() {
158
+ return this.config.enabled;
159
+ }
160
+ }
161
+ // ============================================================================
162
+ // Singleton
163
+ // ============================================================================
164
+ let _instance = null;
165
+ export function getDailyResetManager(config) {
166
+ if (!_instance) {
167
+ _instance = new DailyResetManager(config);
168
+ }
169
+ return _instance;
170
+ }
171
+ export function resetDailyResetManager() {
172
+ _instance?.stop();
173
+ _instance = null;
174
+ }
175
+ //# sourceMappingURL=daily-reset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daily-reset.js","sourceRoot":"","sources":["../../src/daemon/daily-reset.ts"],"names":[],"mappings":"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"}
@@ -5,3 +5,4 @@ export { DaemonManager, getDaemonManager, resetDaemonManager, type DaemonConfig,
5
5
  export { DaemonLifecycle, getDaemonLifecycle, resetDaemonLifecycle, type DaemonService, type LifecycleConfig, } from './daemon-lifecycle.js';
6
6
  export { CronAgentBridge, getCronAgentBridge, resetCronAgentBridge, type BridgeConfig, type JobExecutionResult, } from './cron-agent-bridge.js';
7
7
  export { HealthMonitor, getHealthMonitor, resetHealthMonitor, type HealthMetrics, type HealthMonitorConfig, } from './health-monitor.js';
8
+ export { DailyResetManager, getDailyResetManager, resetDailyResetManager, type DailyResetConfig, type ResetResult, } from './daily-reset.js';
@@ -5,4 +5,5 @@ export { DaemonManager, getDaemonManager, resetDaemonManager, } from './daemon-m
5
5
  export { DaemonLifecycle, getDaemonLifecycle, resetDaemonLifecycle, } from './daemon-lifecycle.js';
6
6
  export { CronAgentBridge, getCronAgentBridge, resetCronAgentBridge, } from './cron-agent-bridge.js';
7
7
  export { HealthMonitor, getHealthMonitor, resetHealthMonitor, } from './health-monitor.js';
8
+ export { DailyResetManager, getDailyResetManager, resetDailyResetManager, } from './daily-reset.js';
8
9
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/daemon/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,kBAAkB,GAInB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,oBAAoB,GAGrB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,oBAAoB,GAGrB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,kBAAkB,GAGnB,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/daemon/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,kBAAkB,GAInB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,oBAAoB,GAGrB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,oBAAoB,GAGrB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,kBAAkB,GAGnB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,GAGvB,MAAM,kBAAkB,CAAC"}
package/dist/index.js CHANGED
@@ -581,8 +581,21 @@ program
581
581
  .option("--append-system-prompt <text>", "append text to the default system prompt")
582
582
  .option("--append-system-prompt-file <path>", "append file contents to the default system prompt")
583
583
  .option("--fallback-model <model>", "auto-fallback model when default is overloaded")
584
+ .option("--profile <name>", "apply a named configuration profile from .codebuddy/config.toml [profiles.<name>]")
584
585
  .option("--from-pr <pr>", "link session to a GitHub pull request (number or URL)")
585
586
  .action(async (message, options) => {
587
+ // Apply named configuration profile (--profile <name>) before anything else
588
+ if (options.profile) {
589
+ try {
590
+ const { getConfigManager } = await import('./config/toml-config.js');
591
+ getConfigManager().load();
592
+ getConfigManager().applyProfile(options.profile);
593
+ }
594
+ catch (err) {
595
+ startupLogger.error(`Profile error: ${err instanceof Error ? err.message : err}`);
596
+ process.exit(1);
597
+ }
598
+ }
586
599
  // Handle --setup flag (interactive setup wizard)
587
600
  if (options.setup) {
588
601
  const { runSetup } = await import("./utils/interactive-setup.js");
@@ -1257,5 +1270,45 @@ addLazyCommandGroup(program, 'config', 'Show environment variable configuration
1257
1270
  const { registerConfigCommand } = await import('./commands/cli/config-command.js');
1258
1271
  registerConfigCommand(program);
1259
1272
  });
1273
+ // Dev workflows — plan, run, pr, fix-ci, explain
1274
+ addLazyCommandGroup(program, 'dev', 'Golden-path developer workflows (plan, run, pr, fix-ci, explain)', async () => {
1275
+ const { registerDevCommands } = await import('./commands/dev/index.js');
1276
+ registerDevCommands(program);
1277
+ });
1278
+ // Run observability — list, show, tail, replay
1279
+ addLazyCommandGroup(program, 'runs', 'Inspect and replay agent runs (observability)', async () => {
1280
+ const { registerRunCommands } = await import('./commands/run-cli/index.js');
1281
+ registerRunCommands(program);
1282
+ });
1283
+ // DM pairing — approve, revoke, list, pending
1284
+ addLazyCommand(program, 'pairing', 'Manage DM pairing security (allowlist for messaging channel senders)', async () => {
1285
+ const { createPairingCommand } = await import('./commands/pairing.js');
1286
+ return createPairingCommand();
1287
+ });
1288
+ // Knowledge base management — add, list, show, search, remove, context
1289
+ addLazyCommand(program, 'knowledge', 'Manage agent knowledge bases (Knowledge.md files injected as context)', async () => {
1290
+ const { createKnowledgeCommand } = await import('./commands/knowledge.js');
1291
+ return createKnowledgeCommand();
1292
+ });
1293
+ // Wide Research — parallel agent workers for comprehensive research
1294
+ addLazyCommand(program, 'research', 'Wide Research: spawn parallel agent workers to research a topic (Manus AI-inspired)', async () => {
1295
+ const { createResearchCommand } = await import('./commands/research/index.js');
1296
+ return createResearchCommand();
1297
+ });
1298
+ // Todo attention bias — Manus AI-inspired persistent task list
1299
+ addLazyCommand(program, 'todo', 'Manage persistent task list (todo.md) — injected at end of every agent turn for focus', async () => {
1300
+ const { createTodosCommand } = await import('./commands/todos.js');
1301
+ return createTodosCommand();
1302
+ });
1303
+ // Exec Policy — Codex-inspired command authorization (allow/deny/ask/sandbox + prefix rules)
1304
+ addLazyCommand(program, 'execpolicy', 'Manage execution policy rules (allow/deny/ask/sandbox) for shell commands', async () => {
1305
+ const { createExecPolicyCommand } = await import('./commands/execpolicy.js');
1306
+ return createExecPolicyCommand();
1307
+ });
1308
+ // Lessons — self-improvement loop (lessons learned injected per agent turn)
1309
+ addLazyCommand(program, 'lessons', 'Manage lessons learned — self-improvement loop for recurring patterns (injected every turn)', async () => {
1310
+ const { createLessonsCommand } = await import('./commands/lessons.js');
1311
+ return createLessonsCommand();
1312
+ });
1260
1313
  program.parse();
1261
1314
  //# sourceMappingURL=index.js.map