@cdoing/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/coordinator.d.ts +114 -0
- package/dist/agents/coordinator.d.ts.map +1 -0
- package/dist/agents/coordinator.js +158 -0
- package/dist/agents/coordinator.js.map +1 -0
- package/dist/context-providers/clipboard.d.ts +13 -0
- package/dist/context-providers/clipboard.d.ts.map +1 -0
- package/dist/context-providers/clipboard.js +53 -0
- package/dist/context-providers/clipboard.js.map +1 -0
- package/dist/context-providers/codebase.d.ts +46 -0
- package/dist/context-providers/codebase.d.ts.map +1 -0
- package/dist/context-providers/codebase.js +273 -0
- package/dist/context-providers/codebase.js.map +1 -0
- package/dist/context-providers/diff.d.ts +18 -0
- package/dist/context-providers/diff.d.ts.map +1 -0
- package/dist/context-providers/diff.js +63 -0
- package/dist/context-providers/diff.js.map +1 -0
- package/dist/context-providers/docs.d.ts +21 -0
- package/dist/context-providers/docs.d.ts.map +1 -0
- package/dist/context-providers/docs.js +180 -0
- package/dist/context-providers/docs.js.map +1 -0
- package/dist/context-providers/file-include.d.ts +13 -0
- package/dist/context-providers/file-include.d.ts.map +1 -0
- package/dist/context-providers/file-include.js +82 -0
- package/dist/context-providers/file-include.js.map +1 -0
- package/dist/context-providers/folder.d.ts +19 -0
- package/dist/context-providers/folder.d.ts.map +1 -0
- package/dist/context-providers/folder.js +130 -0
- package/dist/context-providers/folder.js.map +1 -0
- package/dist/context-providers/git.d.ts +19 -0
- package/dist/context-providers/git.d.ts.map +1 -0
- package/dist/context-providers/git.js +74 -0
- package/dist/context-providers/git.js.map +1 -0
- package/dist/context-providers/index.d.ts +26 -0
- package/dist/context-providers/index.d.ts.map +1 -0
- package/dist/context-providers/index.js +37 -0
- package/dist/context-providers/index.js.map +1 -0
- package/dist/context-providers/open-files.d.ts +25 -0
- package/dist/context-providers/open-files.d.ts.map +1 -0
- package/dist/context-providers/open-files.js +134 -0
- package/dist/context-providers/open-files.js.map +1 -0
- package/dist/context-providers/problems.d.ts +24 -0
- package/dist/context-providers/problems.d.ts.map +1 -0
- package/dist/context-providers/problems.js +97 -0
- package/dist/context-providers/problems.js.map +1 -0
- package/dist/context-providers/registry.d.ts +61 -0
- package/dist/context-providers/registry.d.ts.map +1 -0
- package/dist/context-providers/registry.js +92 -0
- package/dist/context-providers/registry.js.map +1 -0
- package/dist/context-providers/terminal.d.ts +25 -0
- package/dist/context-providers/terminal.d.ts.map +1 -0
- package/dist/context-providers/terminal.js +55 -0
- package/dist/context-providers/terminal.js.map +1 -0
- package/dist/context-providers/tree.d.ts +29 -0
- package/dist/context-providers/tree.d.ts.map +1 -0
- package/dist/context-providers/tree.js +172 -0
- package/dist/context-providers/tree.js.map +1 -0
- package/dist/context-providers/types.d.ts +72 -0
- package/dist/context-providers/types.d.ts.map +1 -0
- package/dist/context-providers/types.js +10 -0
- package/dist/context-providers/types.js.map +1 -0
- package/dist/context-providers/url.d.ts +27 -0
- package/dist/context-providers/url.d.ts.map +1 -0
- package/dist/context-providers/url.js +131 -0
- package/dist/context-providers/url.js.map +1 -0
- package/dist/effort/index.d.ts +78 -0
- package/dist/effort/index.d.ts.map +1 -0
- package/dist/effort/index.js +146 -0
- package/dist/effort/index.js.map +1 -0
- package/dist/hooks/index.d.ts +47 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +151 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +152 -0
- package/dist/index.js.map +1 -0
- package/dist/indexing/chunker.d.ts +25 -0
- package/dist/indexing/chunker.d.ts.map +1 -0
- package/dist/indexing/chunker.js +217 -0
- package/dist/indexing/chunker.js.map +1 -0
- package/dist/indexing/database.d.ts +49 -0
- package/dist/indexing/database.d.ts.map +1 -0
- package/dist/indexing/database.js +287 -0
- package/dist/indexing/database.js.map +1 -0
- package/dist/indexing/index.d.ts +9 -0
- package/dist/indexing/index.d.ts.map +1 -0
- package/dist/indexing/index.js +13 -0
- package/dist/indexing/index.js.map +1 -0
- package/dist/indexing/indexer.d.ts +63 -0
- package/dist/indexing/indexer.d.ts.map +1 -0
- package/dist/indexing/indexer.js +352 -0
- package/dist/indexing/indexer.js.map +1 -0
- package/dist/indexing/recent-edits-cache.d.ts +77 -0
- package/dist/indexing/recent-edits-cache.d.ts.map +1 -0
- package/dist/indexing/recent-edits-cache.js +123 -0
- package/dist/indexing/recent-edits-cache.js.map +1 -0
- package/dist/indexing/types.d.ts +39 -0
- package/dist/indexing/types.d.ts.map +1 -0
- package/dist/indexing/types.js +6 -0
- package/dist/indexing/types.js.map +1 -0
- package/dist/mcp/index.d.ts +33 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +37 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/manager.d.ts +123 -0
- package/dist/mcp/manager.d.ts.map +1 -0
- package/dist/mcp/manager.js +331 -0
- package/dist/mcp/manager.js.map +1 -0
- package/dist/oauth.d.ts +33 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +312 -0
- package/dist/oauth.js.map +1 -0
- package/dist/permissions/index.d.ts +216 -0
- package/dist/permissions/index.d.ts.map +1 -0
- package/dist/permissions/index.js +938 -0
- package/dist/permissions/index.js.map +1 -0
- package/dist/plan/index.d.ts +20 -0
- package/dist/plan/index.d.ts.map +1 -0
- package/dist/plan/index.js +24 -0
- package/dist/plan/index.js.map +1 -0
- package/dist/plan/manager.d.ts +101 -0
- package/dist/plan/manager.d.ts.map +1 -0
- package/dist/plan/manager.js +170 -0
- package/dist/plan/manager.js.map +1 -0
- package/dist/rules/index.d.ts +28 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +31 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/manager.d.ts +77 -0
- package/dist/rules/manager.d.ts.map +1 -0
- package/dist/rules/manager.js +279 -0
- package/dist/rules/manager.js.map +1 -0
- package/dist/rules/types.d.ts +34 -0
- package/dist/rules/types.d.ts.map +1 -0
- package/dist/rules/types.js +9 -0
- package/dist/rules/types.js.map +1 -0
- package/dist/sandbox/filesystem.d.ts +20 -0
- package/dist/sandbox/filesystem.d.ts.map +1 -0
- package/dist/sandbox/filesystem.js +141 -0
- package/dist/sandbox/filesystem.js.map +1 -0
- package/dist/sandbox/index.d.ts +4 -0
- package/dist/sandbox/index.d.ts.map +1 -0
- package/dist/sandbox/index.js +8 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/sandbox/manager.d.ts +47 -0
- package/dist/sandbox/manager.d.ts.map +1 -0
- package/dist/sandbox/manager.js +220 -0
- package/dist/sandbox/manager.js.map +1 -0
- package/dist/sandbox/network.d.ts +14 -0
- package/dist/sandbox/network.d.ts.map +1 -0
- package/dist/sandbox/network.js +87 -0
- package/dist/sandbox/network.js.map +1 -0
- package/dist/sandbox/types.d.ts +42 -0
- package/dist/sandbox/types.d.ts.map +1 -0
- package/dist/sandbox/types.js +25 -0
- package/dist/sandbox/types.js.map +1 -0
- package/dist/tools/ast-edit.d.ts +57 -0
- package/dist/tools/ast-edit.d.ts.map +1 -0
- package/dist/tools/ast-edit.js +443 -0
- package/dist/tools/ast-edit.js.map +1 -0
- package/dist/tools/code-verify.d.ts +8 -0
- package/dist/tools/code-verify.d.ts.map +1 -0
- package/dist/tools/code-verify.js +159 -0
- package/dist/tools/code-verify.js.map +1 -0
- package/dist/tools/codebase-search.d.ts +17 -0
- package/dist/tools/codebase-search.d.ts.map +1 -0
- package/dist/tools/codebase-search.js +104 -0
- package/dist/tools/codebase-search.js.map +1 -0
- package/dist/tools/file-delete.d.ts +26 -0
- package/dist/tools/file-delete.d.ts.map +1 -0
- package/dist/tools/file-delete.js +179 -0
- package/dist/tools/file-delete.js.map +1 -0
- package/dist/tools/file-edit.d.ts +10 -0
- package/dist/tools/file-edit.d.ts.map +1 -0
- package/dist/tools/file-edit.js +138 -0
- package/dist/tools/file-edit.js.map +1 -0
- package/dist/tools/file-read.d.ts +12 -0
- package/dist/tools/file-read.d.ts.map +1 -0
- package/dist/tools/file-read.js +211 -0
- package/dist/tools/file-read.js.map +1 -0
- package/dist/tools/file-run.d.ts +10 -0
- package/dist/tools/file-run.d.ts.map +1 -0
- package/dist/tools/file-run.js +179 -0
- package/dist/tools/file-run.js.map +1 -0
- package/dist/tools/file-write.d.ts +10 -0
- package/dist/tools/file-write.d.ts.map +1 -0
- package/dist/tools/file-write.js +134 -0
- package/dist/tools/file-write.js.map +1 -0
- package/dist/tools/glob-search.d.ts +8 -0
- package/dist/tools/glob-search.d.ts.map +1 -0
- package/dist/tools/glob-search.js +108 -0
- package/dist/tools/glob-search.js.map +1 -0
- package/dist/tools/grep-search.d.ts +8 -0
- package/dist/tools/grep-search.d.ts.map +1 -0
- package/dist/tools/grep-search.js +139 -0
- package/dist/tools/grep-search.js.map +1 -0
- package/dist/tools/list-dir.d.ts +16 -0
- package/dist/tools/list-dir.d.ts.map +1 -0
- package/dist/tools/list-dir.js +183 -0
- package/dist/tools/list-dir.js.map +1 -0
- package/dist/tools/multi-edit.d.ts +16 -0
- package/dist/tools/multi-edit.d.ts.map +1 -0
- package/dist/tools/multi-edit.js +163 -0
- package/dist/tools/multi-edit.js.map +1 -0
- package/dist/tools/notebook-edit.d.ts +31 -0
- package/dist/tools/notebook-edit.d.ts.map +1 -0
- package/dist/tools/notebook-edit.js +321 -0
- package/dist/tools/notebook-edit.js.map +1 -0
- package/dist/tools/registry.d.ts +16 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +41 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/shell-exec.d.ts +12 -0
- package/dist/tools/shell-exec.d.ts.map +1 -0
- package/dist/tools/shell-exec.js +261 -0
- package/dist/tools/shell-exec.js.map +1 -0
- package/dist/tools/sub-agent-manager.d.ts +57 -0
- package/dist/tools/sub-agent-manager.d.ts.map +1 -0
- package/dist/tools/sub-agent-manager.js +153 -0
- package/dist/tools/sub-agent-manager.js.map +1 -0
- package/dist/tools/sub-agent-status.d.ts +12 -0
- package/dist/tools/sub-agent-status.d.ts.map +1 -0
- package/dist/tools/sub-agent-status.js +59 -0
- package/dist/tools/sub-agent-status.js.map +1 -0
- package/dist/tools/sub-agent-terminate.d.ts +12 -0
- package/dist/tools/sub-agent-terminate.d.ts.map +1 -0
- package/dist/tools/sub-agent-terminate.js +55 -0
- package/dist/tools/sub-agent-terminate.js.map +1 -0
- package/dist/tools/sub-agent.d.ts +34 -0
- package/dist/tools/sub-agent.d.ts.map +1 -0
- package/dist/tools/sub-agent.js +140 -0
- package/dist/tools/sub-agent.js.map +1 -0
- package/dist/tools/system-info.d.ts +24 -0
- package/dist/tools/system-info.d.ts.map +1 -0
- package/dist/tools/system-info.js +220 -0
- package/dist/tools/system-info.js.map +1 -0
- package/dist/tools/todo.d.ts +16 -0
- package/dist/tools/todo.d.ts.map +1 -0
- package/dist/tools/todo.js +144 -0
- package/dist/tools/todo.js.map +1 -0
- package/dist/tools/types.d.ts +20 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +3 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/view-diff.d.ts +11 -0
- package/dist/tools/view-diff.d.ts.map +1 -0
- package/dist/tools/view-diff.js +88 -0
- package/dist/tools/view-diff.js.map +1 -0
- package/dist/tools/view-repo-map.d.ts +18 -0
- package/dist/tools/view-repo-map.d.ts.map +1 -0
- package/dist/tools/view-repo-map.js +245 -0
- package/dist/tools/view-repo-map.js.map +1 -0
- package/dist/tools/web-fetch.d.ts +13 -0
- package/dist/tools/web-fetch.d.ts.map +1 -0
- package/dist/tools/web-fetch.js +106 -0
- package/dist/tools/web-fetch.js.map +1 -0
- package/dist/tools/web-search.d.ts +10 -0
- package/dist/tools/web-search.d.ts.map +1 -0
- package/dist/tools/web-search.js +106 -0
- package/dist/tools/web-search.js.map +1 -0
- package/dist/utils/gitignore.d.ts +10 -0
- package/dist/utils/gitignore.d.ts.map +1 -0
- package/dist/utils/gitignore.js +104 -0
- package/dist/utils/gitignore.js.map +1 -0
- package/dist/utils/lazy-apply.d.ts +45 -0
- package/dist/utils/lazy-apply.d.ts.map +1 -0
- package/dist/utils/lazy-apply.js +164 -0
- package/dist/utils/lazy-apply.js.map +1 -0
- package/dist/utils/memory.d.ts +36 -0
- package/dist/utils/memory.d.ts.map +1 -0
- package/dist/utils/memory.js +136 -0
- package/dist/utils/memory.js.map +1 -0
- package/dist/utils/path-matching.d.ts +24 -0
- package/dist/utils/path-matching.d.ts.map +1 -0
- package/dist/utils/path-matching.js +116 -0
- package/dist/utils/path-matching.js.map +1 -0
- package/dist/utils/path-safety.d.ts +13 -0
- package/dist/utils/path-safety.d.ts.map +1 -0
- package/dist/utils/path-safety.js +54 -0
- package/dist/utils/path-safety.js.map +1 -0
- package/dist/utils/project-config.d.ts +18 -0
- package/dist/utils/project-config.d.ts.map +1 -0
- package/dist/utils/project-config.js +76 -0
- package/dist/utils/project-config.js.map +1 -0
- package/dist/utils/search-match.d.ts +63 -0
- package/dist/utils/search-match.d.ts.map +1 -0
- package/dist/utils/search-match.js +426 -0
- package/dist/utils/search-match.js.map +1 -0
- package/dist/utils/shell-paths.d.ts +17 -0
- package/dist/utils/shell-paths.d.ts.map +1 -0
- package/dist/utils/shell-paths.js +107 -0
- package/dist/utils/shell-paths.js.map +1 -0
- package/dist/utils/streaming-diff.d.ts +45 -0
- package/dist/utils/streaming-diff.d.ts.map +1 -0
- package/dist/utils/streaming-diff.js +230 -0
- package/dist/utils/streaming-diff.js.map +1 -0
- package/dist/utils/todo.d.ts +47 -0
- package/dist/utils/todo.d.ts.map +1 -0
- package/dist/utils/todo.js +102 -0
- package/dist/utils/todo.js.map +1 -0
- package/package.json +23 -0
- package/src/agents/coordinator.ts +240 -0
- package/src/context-providers/clipboard.ts +48 -0
- package/src/context-providers/codebase.ts +274 -0
- package/src/context-providers/diff.ts +66 -0
- package/src/context-providers/docs.ts +160 -0
- package/src/context-providers/file-include.ts +54 -0
- package/src/context-providers/folder.ts +106 -0
- package/src/context-providers/git.ts +72 -0
- package/src/context-providers/index.ts +26 -0
- package/src/context-providers/open-files.ts +113 -0
- package/src/context-providers/problems.ts +100 -0
- package/src/context-providers/registry.ts +99 -0
- package/src/context-providers/terminal.ts +58 -0
- package/src/context-providers/tree.ts +161 -0
- package/src/context-providers/types.ts +84 -0
- package/src/context-providers/url.ts +138 -0
- package/src/effort/index.ts +177 -0
- package/src/hooks/index.ts +148 -0
- package/src/index.ts +114 -0
- package/src/indexing/README.md +267 -0
- package/src/indexing/chunker.ts +206 -0
- package/src/indexing/database.ts +299 -0
- package/src/indexing/index.ts +15 -0
- package/src/indexing/indexer.ts +383 -0
- package/src/indexing/recent-edits-cache.ts +150 -0
- package/src/indexing/types.ts +44 -0
- package/src/mcp/index.ts +33 -0
- package/src/mcp/manager.ts +385 -0
- package/src/oauth.ts +330 -0
- package/src/permissions/index.ts +1011 -0
- package/src/plan/index.ts +20 -0
- package/src/plan/manager.ts +233 -0
- package/src/rules/index.ts +28 -0
- package/src/rules/manager.ts +276 -0
- package/src/rules/types.ts +40 -0
- package/src/sandbox/filesystem.ts +135 -0
- package/src/sandbox/index.ts +9 -0
- package/src/sandbox/manager.ts +213 -0
- package/src/sandbox/network.ts +101 -0
- package/src/sandbox/types.ts +63 -0
- package/src/tools/ast-edit.ts +493 -0
- package/src/tools/code-verify.ts +143 -0
- package/src/tools/codebase-search.ts +117 -0
- package/src/tools/file-delete.ts +155 -0
- package/src/tools/file-edit.ts +115 -0
- package/src/tools/file-read.ts +195 -0
- package/src/tools/file-run.ts +158 -0
- package/src/tools/file-write.ts +104 -0
- package/src/tools/glob-search.ts +80 -0
- package/src/tools/grep-search.ts +120 -0
- package/src/tools/list-dir.ts +172 -0
- package/src/tools/multi-edit.ts +138 -0
- package/src/tools/notebook-edit.ts +342 -0
- package/src/tools/registry.ts +43 -0
- package/src/tools/shell-exec.ts +251 -0
- package/src/tools/sub-agent-manager.ts +183 -0
- package/src/tools/sub-agent-status.ts +67 -0
- package/src/tools/sub-agent-terminate.ts +62 -0
- package/src/tools/sub-agent.ts +162 -0
- package/src/tools/system-info.ts +248 -0
- package/src/tools/todo.ts +149 -0
- package/src/tools/types.ts +21 -0
- package/src/tools/view-diff.ts +99 -0
- package/src/tools/view-repo-map.ts +249 -0
- package/src/tools/web-fetch.ts +118 -0
- package/src/tools/web-search.ts +129 -0
- package/src/utils/gitignore.ts +73 -0
- package/src/utils/lazy-apply.ts +189 -0
- package/src/utils/memory.ts +124 -0
- package/src/utils/path-matching.ts +84 -0
- package/src/utils/path-safety.ts +19 -0
- package/src/utils/project-config.ts +41 -0
- package/src/utils/search-match.ts +495 -0
- package/src/utils/shell-paths.ts +79 -0
- package/src/utils/streaming-diff.ts +260 -0
- package/src/utils/todo.ts +115 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lazy Apply — LLM-assisted placeholder expansion for file edits.
|
|
3
|
+
*
|
|
4
|
+
* When an LLM generates code with placeholder markers like:
|
|
5
|
+
* // ... existing code ...
|
|
6
|
+
* // ... rest of the function ...
|
|
7
|
+
* # ... remaining imports ...
|
|
8
|
+
*
|
|
9
|
+
* This module detects those placeholders and expands them by preserving
|
|
10
|
+
* the corresponding original code sections. This allows LLMs to make
|
|
11
|
+
* targeted edits without reproducing entire files.
|
|
12
|
+
*
|
|
13
|
+
* Three strategies:
|
|
14
|
+
* 1. Deterministic — match anchors (lines before/after placeholder) against
|
|
15
|
+
* original content and splice in the preserved region
|
|
16
|
+
* 2. Unified diff — if the new content is a diff, apply it directly
|
|
17
|
+
* 3. Streaming — process token-by-token as LLM generates, expanding in real-time
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Common placeholder patterns used by LLMs to indicate "keep existing code here".
|
|
22
|
+
* Matches patterns like:
|
|
23
|
+
* // ... existing code ...
|
|
24
|
+
* // ... rest of the function ...
|
|
25
|
+
* # ... remaining imports ...
|
|
26
|
+
* /* ... keep existing ... * /
|
|
27
|
+
* // [existing code]
|
|
28
|
+
* // (rest remains the same)
|
|
29
|
+
*/
|
|
30
|
+
const PLACEHOLDER_PATTERNS = [
|
|
31
|
+
// Comment-style with ellipsis: // ... existing code ...
|
|
32
|
+
/^(\s*)(?:\/\/|#|--|\/\*|\*|<!--)\s*\.{2,}\s*(existing|remaining|rest|keep|same|unchanged|other|previous).*$/i,
|
|
33
|
+
// Comment-style with brackets: // [existing code]
|
|
34
|
+
/^(\s*)(?:\/\/|#|--|\/\*|\*|<!--)\s*\[(?:existing|remaining|rest|keep|same|unchanged|other|previous).*\].*$/i,
|
|
35
|
+
// Comment-style with parens: // (rest remains the same)
|
|
36
|
+
/^(\s*)(?:\/\/|#|--|\/\*|\*|<!--)\s*\((?:existing|remaining|rest|keep|same|unchanged|other|previous).*\).*$/i,
|
|
37
|
+
// Bare ellipsis comment: // ...
|
|
38
|
+
/^(\s*)(?:\/\/|#|--|\/\*|\*|<!--)\s*\.{3,}\s*(?:\*\/|-->)?\s*$/,
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
export interface LazyApplyResult {
|
|
42
|
+
content: string;
|
|
43
|
+
placeholdersExpanded: number;
|
|
44
|
+
strategy: "deterministic" | "none";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Check if a line is a placeholder marker.
|
|
49
|
+
*/
|
|
50
|
+
export function isPlaceholderLine(line: string): boolean {
|
|
51
|
+
return PLACEHOLDER_PATTERNS.some((p) => p.test(line));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Detect if content contains any placeholder markers.
|
|
56
|
+
*/
|
|
57
|
+
export function hasPlaceholders(content: string): boolean {
|
|
58
|
+
return content.split("\n").some(isPlaceholderLine);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Expand placeholders in newContent by referencing originalContent.
|
|
63
|
+
*
|
|
64
|
+
* Algorithm:
|
|
65
|
+
* 1. Split both contents into lines
|
|
66
|
+
* 2. Walk through newContent lines
|
|
67
|
+
* 3. When a placeholder line is found:
|
|
68
|
+
* a. Use anchor lines (the non-placeholder lines before and after) to locate
|
|
69
|
+
* the corresponding region in the original file
|
|
70
|
+
* b. Splice in the original lines between the anchors
|
|
71
|
+
* 4. Return the expanded content
|
|
72
|
+
*/
|
|
73
|
+
export function expandPlaceholders(
|
|
74
|
+
originalContent: string,
|
|
75
|
+
newContent: string,
|
|
76
|
+
): LazyApplyResult {
|
|
77
|
+
const newLines = newContent.split("\n");
|
|
78
|
+
|
|
79
|
+
if (!newLines.some(isPlaceholderLine)) {
|
|
80
|
+
return { content: newContent, placeholdersExpanded: 0, strategy: "none" };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const originalLines = originalContent.split("\n");
|
|
84
|
+
const result: string[] = [];
|
|
85
|
+
let placeholdersExpanded = 0;
|
|
86
|
+
let i = 0;
|
|
87
|
+
|
|
88
|
+
while (i < newLines.length) {
|
|
89
|
+
if (!isPlaceholderLine(newLines[i])) {
|
|
90
|
+
result.push(newLines[i]);
|
|
91
|
+
i++;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Found a placeholder — find anchor lines before and after
|
|
96
|
+
const anchorBefore = findAnchorBefore(result);
|
|
97
|
+
const anchorAfter = findAnchorAfter(newLines, i);
|
|
98
|
+
|
|
99
|
+
// Locate the region in original content between these anchors
|
|
100
|
+
const region = findOriginalRegion(originalLines, anchorBefore, anchorAfter);
|
|
101
|
+
|
|
102
|
+
if (region) {
|
|
103
|
+
// Splice in the original lines
|
|
104
|
+
for (let r = region.start; r < region.end; r++) {
|
|
105
|
+
result.push(originalLines[r]);
|
|
106
|
+
}
|
|
107
|
+
placeholdersExpanded++;
|
|
108
|
+
} else {
|
|
109
|
+
// Couldn't find region — keep placeholder as a comment so it's visible
|
|
110
|
+
result.push(newLines[i]);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
i++;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
content: result.join("\n"),
|
|
118
|
+
placeholdersExpanded,
|
|
119
|
+
strategy: placeholdersExpanded > 0 ? "deterministic" : "none",
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Find the last non-empty, non-placeholder line from the result so far.
|
|
125
|
+
*/
|
|
126
|
+
function findAnchorBefore(resultSoFar: string[]): string | null {
|
|
127
|
+
for (let i = resultSoFar.length - 1; i >= 0; i--) {
|
|
128
|
+
const line = resultSoFar[i].trim();
|
|
129
|
+
if (line && !isPlaceholderLine(resultSoFar[i])) {
|
|
130
|
+
return resultSoFar[i];
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Find the next non-empty, non-placeholder line after position i.
|
|
138
|
+
*/
|
|
139
|
+
function findAnchorAfter(lines: string[], fromIndex: number): string | null {
|
|
140
|
+
for (let i = fromIndex + 1; i < lines.length; i++) {
|
|
141
|
+
const line = lines[i].trim();
|
|
142
|
+
if (line && !isPlaceholderLine(lines[i])) {
|
|
143
|
+
return lines[i];
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Find the region in originalLines between anchorBefore and anchorAfter.
|
|
151
|
+
* Returns the line range (exclusive end) of original lines to preserve.
|
|
152
|
+
*/
|
|
153
|
+
function findOriginalRegion(
|
|
154
|
+
originalLines: string[],
|
|
155
|
+
anchorBefore: string | null,
|
|
156
|
+
anchorAfter: string | null,
|
|
157
|
+
): { start: number; end: number } | null {
|
|
158
|
+
let startIdx = 0;
|
|
159
|
+
let endIdx = originalLines.length;
|
|
160
|
+
|
|
161
|
+
// Find where anchorBefore occurs in original
|
|
162
|
+
if (anchorBefore !== null) {
|
|
163
|
+
const beforeTrimmed = anchorBefore.trim();
|
|
164
|
+
for (let i = 0; i < originalLines.length; i++) {
|
|
165
|
+
if (originalLines[i].trim() === beforeTrimmed) {
|
|
166
|
+
startIdx = i + 1; // Start after the anchor
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Find where anchorAfter occurs in original (searching from startIdx)
|
|
173
|
+
if (anchorAfter !== null) {
|
|
174
|
+
const afterTrimmed = anchorAfter.trim();
|
|
175
|
+
for (let i = startIdx; i < originalLines.length; i++) {
|
|
176
|
+
if (originalLines[i].trim() === afterTrimmed) {
|
|
177
|
+
endIdx = i; // End before the anchor
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Validate we found a sensible region
|
|
184
|
+
if (startIdx >= endIdx) {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return { start: startIdx, end: endIdx };
|
|
189
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory System — persistent memory across sessions.
|
|
3
|
+
*
|
|
4
|
+
* Stores key-value memories in ~/.cdoing/memory.json
|
|
5
|
+
* The agent can save, recall, and forget memories.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import * as fs from "fs";
|
|
9
|
+
import * as path from "path";
|
|
10
|
+
import * as os from "os";
|
|
11
|
+
|
|
12
|
+
const MEMORY_DIR = path.join(os.homedir(), ".cdoing");
|
|
13
|
+
const MEMORY_FILE = path.join(MEMORY_DIR, "memory.json");
|
|
14
|
+
|
|
15
|
+
export interface MemoryEntry {
|
|
16
|
+
key: string;
|
|
17
|
+
value: string;
|
|
18
|
+
category: "user" | "project" | "preference" | "context";
|
|
19
|
+
createdAt: string;
|
|
20
|
+
updatedAt: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class MemoryStore {
|
|
24
|
+
private memories: MemoryEntry[] = [];
|
|
25
|
+
|
|
26
|
+
constructor() {
|
|
27
|
+
this.load();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
private load(): void {
|
|
31
|
+
try {
|
|
32
|
+
if (fs.existsSync(MEMORY_FILE)) {
|
|
33
|
+
const data = JSON.parse(fs.readFileSync(MEMORY_FILE, "utf-8"));
|
|
34
|
+
this.memories = Array.isArray(data.memories) ? data.memories : [];
|
|
35
|
+
}
|
|
36
|
+
} catch {
|
|
37
|
+
this.memories = [];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private save(): void {
|
|
42
|
+
if (!fs.existsSync(MEMORY_DIR)) fs.mkdirSync(MEMORY_DIR, { recursive: true });
|
|
43
|
+
fs.writeFileSync(
|
|
44
|
+
MEMORY_FILE,
|
|
45
|
+
JSON.stringify({ memories: this.memories }, null, 2),
|
|
46
|
+
"utf-8"
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Save or update a memory */
|
|
51
|
+
set(key: string, value: string, category: MemoryEntry["category"] = "context"): void {
|
|
52
|
+
const now = new Date().toISOString();
|
|
53
|
+
const existing = this.memories.find((m) => m.key === key);
|
|
54
|
+
if (existing) {
|
|
55
|
+
existing.value = value;
|
|
56
|
+
existing.updatedAt = now;
|
|
57
|
+
existing.category = category;
|
|
58
|
+
} else {
|
|
59
|
+
this.memories.push({ key, value, category, createdAt: now, updatedAt: now });
|
|
60
|
+
}
|
|
61
|
+
this.save();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Get a specific memory */
|
|
65
|
+
get(key: string): string | null {
|
|
66
|
+
const entry = this.memories.find((m) => m.key === key);
|
|
67
|
+
return entry?.value || null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Search memories by keyword */
|
|
71
|
+
search(query: string): MemoryEntry[] {
|
|
72
|
+
const q = query.toLowerCase();
|
|
73
|
+
return this.memories.filter(
|
|
74
|
+
(m) => m.key.toLowerCase().includes(q) || m.value.toLowerCase().includes(q)
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Get all memories */
|
|
79
|
+
getAll(): ReadonlyArray<MemoryEntry> {
|
|
80
|
+
return this.memories;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Get memories by category */
|
|
84
|
+
getByCategory(category: MemoryEntry["category"]): MemoryEntry[] {
|
|
85
|
+
return this.memories.filter((m) => m.category === category);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Delete a memory */
|
|
89
|
+
forget(key: string): boolean {
|
|
90
|
+
const index = this.memories.findIndex((m) => m.key === key);
|
|
91
|
+
if (index === -1) return false;
|
|
92
|
+
this.memories.splice(index, 1);
|
|
93
|
+
this.save();
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Clear all memories */
|
|
98
|
+
clear(): void {
|
|
99
|
+
this.memories = [];
|
|
100
|
+
this.save();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Format memories for inclusion in system prompt */
|
|
104
|
+
formatForPrompt(): string {
|
|
105
|
+
if (this.memories.length === 0) return "";
|
|
106
|
+
|
|
107
|
+
const byCategory = new Map<string, MemoryEntry[]>();
|
|
108
|
+
for (const m of this.memories) {
|
|
109
|
+
const list = byCategory.get(m.category) || [];
|
|
110
|
+
list.push(m);
|
|
111
|
+
byCategory.set(m.category, list);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const parts: string[] = [];
|
|
115
|
+
for (const [category, entries] of byCategory) {
|
|
116
|
+
parts.push(`## ${category}`);
|
|
117
|
+
for (const e of entries) {
|
|
118
|
+
parts.push(`- **${e.key}**: ${e.value}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return parts.join("\n");
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path Matching Utilities — shared by permissions and sandbox systems.
|
|
3
|
+
*
|
|
4
|
+
* Supports path specifier prefixes:
|
|
5
|
+
* //abs/path → absolute from filesystem root
|
|
6
|
+
* ~/rel/path → relative to home directory
|
|
7
|
+
* /proj/path → relative to project root
|
|
8
|
+
* ./rel/path → relative to current working directory
|
|
9
|
+
* rel/path → relative to current working directory
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import * as path from "path";
|
|
13
|
+
import * as os from "os";
|
|
14
|
+
|
|
15
|
+
const HOME_DIR = os.homedir();
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Resolve a specifier to an absolute base path for matching.
|
|
19
|
+
*/
|
|
20
|
+
export function resolveSpecifierBase(specifier: string, projectDir: string, cwd: string): string {
|
|
21
|
+
if (specifier.startsWith("//")) {
|
|
22
|
+
return path.normalize("/" + specifier.substring(2));
|
|
23
|
+
}
|
|
24
|
+
if (specifier.startsWith("~/")) {
|
|
25
|
+
return path.join(HOME_DIR, specifier.substring(2));
|
|
26
|
+
}
|
|
27
|
+
if (specifier.startsWith("/")) {
|
|
28
|
+
return path.join(projectDir, specifier.substring(1));
|
|
29
|
+
}
|
|
30
|
+
if (specifier.startsWith("./")) {
|
|
31
|
+
return path.join(cwd, specifier.substring(2));
|
|
32
|
+
}
|
|
33
|
+
return path.join(cwd, specifier);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Glob match: * matches single directory segment, ** matches recursively. */
|
|
37
|
+
export function pathGlob(filePath: string, pattern: string): boolean {
|
|
38
|
+
if (!pattern.includes("*")) {
|
|
39
|
+
return filePath === pattern || filePath.startsWith(pattern + path.sep);
|
|
40
|
+
}
|
|
41
|
+
const patParts = pattern.split(path.sep);
|
|
42
|
+
const fileParts = filePath.split(path.sep);
|
|
43
|
+
return matchPathParts(fileParts, patParts, 0, 0);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function matchPathParts(fp: string[], pp: string[], fi: number, pi: number): boolean {
|
|
47
|
+
while (pi < pp.length) {
|
|
48
|
+
if (pp[pi] === "**") {
|
|
49
|
+
for (let k = fi; k <= fp.length; k++) {
|
|
50
|
+
if (matchPathParts(fp, pp, k, pi + 1)) return true;
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
if (fi >= fp.length) return false;
|
|
55
|
+
if (!matchSegment(fp[fi], pp[pi])) return false;
|
|
56
|
+
fi++;
|
|
57
|
+
pi++;
|
|
58
|
+
}
|
|
59
|
+
return fi === fp.length;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function matchSegment(name: string, pat: string): boolean {
|
|
63
|
+
if (!pat.includes("*")) return name === pat;
|
|
64
|
+
const rx = "^" + pat.split("*").map(escapeRegex).join("[^/]*") + "$";
|
|
65
|
+
return new RegExp(rx).test(name);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function escapeRegex(s: string): string {
|
|
69
|
+
return s.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Match a file path against a specifier, resolving the specifier relative
|
|
74
|
+
* to the project directory and current working directory.
|
|
75
|
+
*/
|
|
76
|
+
export function matchPath(
|
|
77
|
+
filePath: string,
|
|
78
|
+
specifier: string,
|
|
79
|
+
projectDir: string,
|
|
80
|
+
cwd: string,
|
|
81
|
+
): boolean {
|
|
82
|
+
const base = resolveSpecifierBase(specifier, projectDir, cwd);
|
|
83
|
+
return pathGlob(filePath, base);
|
|
84
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path Safety — resolves user-provided paths to absolute paths.
|
|
3
|
+
*
|
|
4
|
+
* Access control is handled by the permission system (allow/deny rules)
|
|
5
|
+
* and the sandbox system (filesystem restrictions when enabled).
|
|
6
|
+
* This utility only normalizes paths — it does NOT restrict access.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import * as path from "path";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Resolve a user-provided path to an absolute, normalized path.
|
|
13
|
+
* Relative paths are resolved against the working directory.
|
|
14
|
+
*/
|
|
15
|
+
export function safePath(userPath: string, workingDir: string): string {
|
|
16
|
+
return path.isAbsolute(userPath)
|
|
17
|
+
? path.resolve(userPath)
|
|
18
|
+
: path.resolve(workingDir, userPath);
|
|
19
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Config — reads .cdoing/config.md for project-specific instructions.
|
|
3
|
+
* Similar to Claude Code's CLAUDE.md system.
|
|
4
|
+
*
|
|
5
|
+
* Looks for config in these locations (in order):
|
|
6
|
+
* 1. .cdoing/config.md (project-specific)
|
|
7
|
+
* 2. CDOING.md (project root alternative)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import * as fs from "fs";
|
|
11
|
+
import * as path from "path";
|
|
12
|
+
|
|
13
|
+
const CONFIG_FILES = [
|
|
14
|
+
".cdoing/config.md",
|
|
15
|
+
"CDOING.md",
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Load project configuration from the working directory.
|
|
20
|
+
* Returns the content of the first config file found, or null.
|
|
21
|
+
*/
|
|
22
|
+
export function loadProjectConfig(workingDir: string): string | null {
|
|
23
|
+
for (const file of CONFIG_FILES) {
|
|
24
|
+
const filePath = path.join(workingDir, file);
|
|
25
|
+
try {
|
|
26
|
+
if (fs.existsSync(filePath)) {
|
|
27
|
+
return fs.readFileSync(filePath, "utf-8").trim();
|
|
28
|
+
}
|
|
29
|
+
} catch {
|
|
30
|
+
// skip unreadable files
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Get the path where project config would be stored.
|
|
38
|
+
*/
|
|
39
|
+
export function getProjectConfigPath(workingDir: string): string {
|
|
40
|
+
return path.join(workingDir, ".cdoing", "config.md");
|
|
41
|
+
}
|