@xelth/eck-snapshot 4.1.0 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,22 +10,41 @@ let Python = null;
10
10
  let Java = null;
11
11
  let Kotlin = null;
12
12
  let C = null;
13
+ let Rust = null;
14
+ let Go = null;
13
15
 
14
16
  async function loadTreeSitter() {
15
- if (!Parser) {
16
- try {
17
- const treeSitterModule = await import('tree-sitter');
18
- Parser = treeSitterModule.default;
19
- Python = (await import('tree-sitter-python')).default;
20
- Java = (await import('tree-sitter-java')).default;
21
- Kotlin = (await import('tree-sitter-kotlin')).default;
22
- C = (await import('tree-sitter-c')).default;
23
- } catch (error) {
24
- console.warn('Tree-sitter not available:', error.message);
25
- return false;
26
- }
17
+ if (Parser) return true; // Already loaded
18
+
19
+ try {
20
+ // We use dynamic imports and check for basic sanity to handle broken native builds (common on Windows)
21
+ const treeSitterModule = await import('tree-sitter').catch(() => null);
22
+ if (!treeSitterModule || !treeSitterModule.default) return false;
23
+
24
+ Parser = treeSitterModule.default;
25
+
26
+ // Load language packs with Promise.allSettled to handle individual failures
27
+ const langs = await Promise.allSettled([
28
+ import('tree-sitter-python'),
29
+ import('tree-sitter-java'),
30
+ import('tree-sitter-kotlin'),
31
+ import('tree-sitter-c'),
32
+ import('tree-sitter-rust'),
33
+ import('tree-sitter-go')
34
+ ]);
35
+
36
+ Python = langs[0].status === 'fulfilled' ? langs[0].value.default : null;
37
+ Java = langs[1].status === 'fulfilled' ? langs[1].value.default : null;
38
+ Kotlin = langs[2].status === 'fulfilled' ? langs[2].value.default : null;
39
+ C = langs[3].status === 'fulfilled' ? langs[3].value.default : null;
40
+ Rust = langs[4].status === 'fulfilled' ? langs[4].value.default : null;
41
+ Go = langs[5].status === 'fulfilled' ? langs[5].value.default : null;
42
+
43
+ return true;
44
+ } catch (error) {
45
+ // Silently fail, skeletonize will fallback to original content
46
+ return false;
27
47
  }
28
- return true;
29
48
  }
30
49
 
31
50
  // Initialize parsers map (will be populated lazily)
@@ -35,8 +54,10 @@ const languages = {
35
54
  '.kt': () => Kotlin,
36
55
  '.c': () => C,
37
56
  '.h': () => C,
38
- '.cpp': () => C, // C parser often handles C++ basics well enough for skeletons
39
- '.hpp': () => C
57
+ '.cpp': () => C,
58
+ '.hpp': () => C,
59
+ '.rs': () => Rust,
60
+ '.go': () => Go
40
61
  };
41
62
 
42
63
  /**
@@ -53,15 +74,18 @@ export async function skeletonize(content, filePath) {
53
74
  return skeletonizeJs(content);
54
75
  }
55
76
 
56
- // 2. Tree-sitter Strategy (Python, Java, Kotlin, C)
77
+ // 2. Tree-sitter Strategy (Python, Java, Kotlin, C, Rust, Go)
57
78
  const ext = filePath.substring(filePath.lastIndexOf('.'));
58
79
  if (languages[ext]) {
59
80
  // Lazy-load tree-sitter
60
81
  const available = await loadTreeSitter();
61
- if (!available) {
62
- return content; // Fallback: return original content if tree-sitter unavailable
82
+ const langModule = languages[ext]();
83
+
84
+ // Only attempt tree-sitter if both the parser and the specific language module are ready
85
+ if (available && Parser && langModule) {
86
+ return skeletonizeTreeSitter(content, langModule, ext);
63
87
  }
64
- return skeletonizeTreeSitter(content, languages[ext]());
88
+ return content; // Fallback: return original content if tree-sitter unavailable
65
89
  }
66
90
 
67
91
  // 3. Fallback (Return as is)
@@ -79,15 +103,22 @@ function skeletonizeJs(content) {
79
103
  traverse(ast, {
80
104
  Function(path) {
81
105
  if (path.node.body && path.node.body.type === 'BlockStatement') {
106
+ // Preserve leading comments (JSDoc) before emptying body
107
+ const leadingComments = path.node.leadingComments || [];
82
108
  path.node.body.body = [];
83
- // Minimal comment to save tokens
84
- path.node.body.innerComments = [{ type: 'CommentBlock', value: ' ... ' }];
109
+ path.node.body.innerComments = leadingComments.length > 0
110
+ ? leadingComments
111
+ : [{ type: 'CommentBlock', value: ' ... ' }];
85
112
  }
86
113
  },
87
114
  ClassMethod(path) {
88
115
  if (path.node.body && path.node.body.type === 'BlockStatement') {
116
+ // Preserve leading comments (JSDoc) before emptying body
117
+ const leadingComments = path.node.leadingComments || [];
89
118
  path.node.body.body = [];
90
- path.node.body.innerComments = [{ type: 'CommentBlock', value: ' ... ' }];
119
+ path.node.body.innerComments = leadingComments.length > 0
120
+ ? leadingComments
121
+ : [{ type: 'CommentBlock', value: ' ... ' }];
91
122
  }
92
123
  }
93
124
  });
@@ -99,28 +130,38 @@ function skeletonizeJs(content) {
99
130
  }
100
131
  }
101
132
 
102
- function skeletonizeTreeSitter(content, language) {
133
+ function skeletonizeTreeSitter(content, language, ext) {
103
134
  try {
104
135
  const parser = new Parser();
105
136
  parser.setLanguage(language);
106
137
  const tree = parser.parse(content);
107
138
 
108
- // Define node types that represent function bodies for different languages
139
+ // Define node types that represent function bodies
109
140
  const bodyTypes = ['block', 'function_body', 'compound_statement'];
110
-
111
141
  const replacements = [];
112
142
 
113
143
  const visit = (node) => {
114
- // Check for function definitions
115
- const isFunction = [
116
- 'function_definition', // Python, C
117
- 'method_declaration', // Java
118
- 'function_declaration', // Kotlin
119
- 'class_declaration', // Kotlin/Java/Python (to clean init blocks if needed, but risky)
120
- ].includes(node.type);
144
+ const type = node.type;
145
+ let isFunction = false;
146
+ let replacementText = '{ /* ... */ }';
147
+
148
+ // Language specific detection
149
+ if (ext === '.rs') {
150
+ isFunction = ['function_item', 'method_declaration'].includes(type);
151
+ } else if (ext === '.go') {
152
+ isFunction = ['function_declaration', 'method_declaration'].includes(type);
153
+ } else if (ext === '.py') {
154
+ isFunction = type === 'function_definition';
155
+ replacementText = '...';
156
+ } else {
157
+ isFunction = [
158
+ 'function_definition',
159
+ 'method_declaration',
160
+ 'function_declaration'
161
+ ].includes(type);
162
+ }
121
163
 
122
164
  if (isFunction) {
123
- // Find the body node
124
165
  let bodyNode = null;
125
166
  for (let i = 0; i < node.childCount; i++) {
126
167
  const child = node.child(i);
@@ -131,23 +172,10 @@ function skeletonizeTreeSitter(content, language) {
131
172
  }
132
173
 
133
174
  if (bodyNode) {
134
- const start = bodyNode.startIndex;
135
- const end = bodyNode.endIndex;
136
- // Use minimal replacement to save tokens
137
- replacements.push({ start, end, text: '{ /* ... */ }' });
138
- return; // Don't traverse inside the body we just stripped
139
- }
140
- }
141
-
142
- // Python uses colons and indentation, distinct from {} blocks
143
- // Use Python's Ellipsis literal for maximum brevity
144
- if (node.type === 'function_definition' && language === Python) {
145
- const body = node.lastChild;
146
- if (body && body.type === 'block') {
147
175
  replacements.push({
148
- start: body.startIndex,
149
- end: body.endIndex,
150
- text: '...' // Python Ellipsis literal - minimal tokens
176
+ start: bodyNode.startIndex,
177
+ end: bodyNode.endIndex,
178
+ text: replacementText
151
179
  });
152
180
  return;
153
181
  }
@@ -159,8 +187,6 @@ function skeletonizeTreeSitter(content, language) {
159
187
  };
160
188
 
161
189
  visit(tree.rootNode);
162
-
163
- // Sort replacements reversed to apply without messing up indices
164
190
  replacements.sort((a, b) => b.start - a.start);
165
191
 
166
192
  let currentContent = content;
@@ -169,7 +195,6 @@ function skeletonizeTreeSitter(content, language) {
169
195
  }
170
196
 
171
197
  return currentContent;
172
-
173
198
  } catch (e) {
174
199
  return content + `\n// [Skeleton error: ${e.message}]`;
175
200
  }
@@ -1,6 +1,7 @@
1
1
  import { execa } from 'execa';
2
2
  import { spawn } from 'child_process';
3
3
  import pRetry from 'p-retry';
4
+ import { parseWithFallback } from '../utils/eckProtocolParser.js';
4
5
 
5
6
  /**
6
7
  * Executes a prompt using the claude-code CLI in non-interactive print mode.
@@ -145,8 +146,12 @@ async function attemptClaudeExecution(prompt, sessionId = null, options = {}) {
145
146
  throw new Error('No result JSON found in claude-code output.');
146
147
  }
147
148
 
149
+ // Parse the result using Eck-Protocol v2 parser
150
+ const parsed = parseWithFallback(resultJson.result || '');
151
+
148
152
  return {
149
153
  result: resultJson.result,
154
+ parsed: parsed, // Structured data from Eck-Protocol v2
150
155
  cost: resultJson.total_cost_usd,
151
156
  usage: resultJson.usage,
152
157
  duration_ms: resultJson.duration_ms
@@ -12,18 +12,115 @@ You are the **Junior Architect** agent (`gemini_wsl`). Your primary goal is to e
12
12
  - **You (Junior Architect / `gemini_wsl`)** analyze the task, break it down, and use your tools.
13
13
  - The **Coder (`claude`)** is your primary tool for *writing code*.
14
14
 
15
- ## CRITICAL WORKFLOW: Using the Coder (`/claude`)
15
+ ## CRITICAL WORKFLOW: Eck-Protocol v2 (Hybrid Format)
16
16
 
17
- The `claude` agent (who you command via `/claude`) is a **specialized Coder**. It is highly trained for code generation.
17
+ When you need to write or modify code, you **MUST** use the `/claude` command with the **Eck-Protocol v2** format. This format uses Markdown for readability, XML tags for file boundaries, and JSON for metadata.
18
18
 
19
- When you need to write or modify code, you **MUST** use the `/claude` command and provide it with a **JSON payload** (as a single-line JSON string) in the `apply_code_changes` format.
19
+ ### Response Format
20
20
 
21
- **DO NOT** ask `claude` to "write a function" in natural language. You *must* command it with this precise JSON structure:
21
+ **CRITICAL DISPLAY RULE:**
22
+ You MUST wrap your ENTIRE response in a `text` block using **QUADRUPLE BACKTICKS** (` ```` `). This prevents internal code blocks from breaking the container.
22
23
 
23
- **IMPORTANT:** The JSON payload must be passed as a **single-line string wrapped in SINGLE QUOTES (`'`)**. This is the simplest and safest way to pass the complete JSON (which uses double quotes) through the shell without it breaking.
24
+ ````text
25
+ # Analysis
24
26
 
27
+ [Your thinking and analysis of the task goes here.
28
+ Explain what you're going to do and why.]
29
+
30
+ ## Changes
31
+
32
+ <file path="src/path/to/file.js" action="replace">
33
+ ```javascript
34
+ // Your code here - no escaping needed!
35
+ async function example() {
36
+ console.log("Clean code with quotes!");
37
+ return { success: true };
38
+ }
25
39
  ```
26
- /claude '{"target_agent":"local_dev","command_for_agent":"apply_code_changes","task_id":"ja-subtask-123","payload":{"objective":"Write the `doSomething` function","context":"This function is for the `UserService`...","files_to_modify":[{"path":"src/services/UserService.js","action":"add","location":"After the `getUser` function","details":"...new function code..."}],"new_files":[],"validation_steps":[]},"post_execution_steps":{"journal_entry":{"type":"feat","scope":"api","summary":"Implement `doSomething` function","details":"Delegated from JA"}}}'
40
+ </file>
41
+
42
+ <file path="src/another/file.js" action="create">
43
+ ```javascript
44
+ export const helper = () => true;
27
45
  ```
46
+ </file>
47
+
48
+ ## Metadata
49
+
50
+ ```json
51
+ {
52
+ "journal": {
53
+ "type": "feat",
54
+ "scope": "api",
55
+ "summary": "Add example function"
56
+ }
57
+ }
58
+ ```
59
+ ````
60
+
61
+ ### File Actions
62
+
63
+ | Action | Description |
64
+ |--------|-------------|
65
+ | `create` | Create a new file |
66
+ | `replace` | Replace entire file content |
67
+ | `modify` | Partial modification (include context) |
68
+ | `delete` | Delete the file (no content needed) |
69
+
70
+ ### Example Command
71
+
72
+ ```
73
+ /claude
74
+ ````text
75
+ # Analysis
76
+
77
+ I need to fix the null check in auth.js and add a helper function.
78
+
79
+ ## Changes
80
+
81
+ <file path="src/auth.js" action="replace">
82
+ ```javascript
83
+ async function login(user) {
84
+ if (!user) throw new Error("No user provided");
85
+ return await db.authenticate(user);
86
+ }
87
+ ```
88
+ </file>
89
+
90
+ <file path="src/utils/validate.js" action="create">
91
+ ```javascript
92
+ export const validateUser = (user) => {
93
+ return user && typeof user.id === 'string';
94
+ };
95
+ ```
96
+ </file>
97
+
98
+ ## Metadata
99
+
100
+ ```json
101
+ {
102
+ "journal": {
103
+ "type": "fix",
104
+ "scope": "auth",
105
+ "summary": "Add null check and validation helper"
106
+ }
107
+ }
108
+ ```
109
+ ````
110
+ ```
111
+
112
+ ### Why This Format?
113
+
114
+ 1. **No escaping hell** - Code is written in standard markdown fences, no `\"` or `\n`
115
+ 2. **Readable** - Both humans and AI can easily read and write this format
116
+ 3. **Parseable** - XML tags provide clear boundaries for automated processing
117
+ 4. **Flexible** - Markdown sections allow for thinking and context
118
+
119
+ ### Important Rules
120
+
121
+ - Always wrap code in markdown fences (` ``` `) inside `<file>` tags
122
+ - Always include the `path` and `action` attributes on `<file>` tags
123
+ - Use the `## Metadata` section for journal entries and other structured data
124
+ - The `# Analysis` section is optional but recommended for complex tasks
28
125
 
29
- Your other tools (like `bash`) can be used for analysis and validation.
126
+ Your other tools (like `bash`) can be used for analysis and validation.
@@ -7,44 +7,133 @@ You are an autonomous AI Architect. Your primary goal is to develop and evolve a
7
7
  Your entire operational process follows a strict loop:
8
8
  1. **Thought:** Analyze the user's request, the current state of the project, and previous observations. Formulate a plan and decide on the next immediate action. You must explain your reasoning and your chosen action in plain text.
9
9
  2. **Tool:** Immediately after your thought process, you MUST issue a command to either the local `eck-snapshot` environment or the `claude_code_agent`.
10
- 3. **Observation:** After issuing a command, you MUST STOP and wait for an `Observation:` message from the system, which will contain the result of your command. Do not proceed until you receive it.
10
+ 3. **Observation:** After issuing a command, you MUST STOP and wait for an `Observation:` message from the system, which will contain the result of your command.
11
11
 
12
- ## Commanding the Execution Agent (Claude)
12
+ ## Commanding the Execution Agent: Eck-Protocol v2
13
13
 
14
- To delegate any coding task (writing, editing, testing, refactoring), you MUST generate a JSON command block for the `claude_code_agent`. This is your primary method of modifying the codebase.
14
+ To delegate any coding task (writing, editing, testing, refactoring), you MUST generate a command using the **Eck-Protocol v2** format. This hybrid Markdown/XML format eliminates JSON escaping issues and is both human-readable and machine-parseable.
15
+
16
+ **CRITICAL DISPLAY RULE:**
17
+ You MUST wrap your ENTIRE response (Analysis + Changes + Metadata) in a single `text` code block using **QUADRUPLE BACKTICKS** (` ```` `). This prevents internal code blocks from breaking the container.
18
+
19
+ ### Command Format (Wrapped)
20
+
21
+ ````text
22
+ # Analysis
23
+
24
+ [Explain your reasoning: what you're doing and why.
25
+ This helps the Coder understand context.]
26
+
27
+ ## Changes
28
+
29
+ <file path="exact/path/to/file.js" action="replace">
30
+ ```javascript
31
+ // Code is written naturally inside markdown fences
32
+ // No escaping of quotes or newlines needed!
33
+ async function example() {
34
+ console.log("This just works!");
35
+ return { success: true };
36
+ }
37
+ ```
38
+ </file>
39
+
40
+ ## Metadata
15
41
 
16
- **JSON Command Format:**
17
42
  ```json
18
43
  {
19
- "target_agent": "claude_code_agent",
20
- "command_for_agent": "apply_code_changes",
21
- "payload": {
22
- "objective": "A brief, clear task description for Claude.",
23
- "context": "Explain why this change is needed and any relevant architectural context.",
24
- "files_to_modify": [
25
- {
26
- "path": "exact/path/to/file.js",
27
- "action": "add | modify | replace | delete",
28
- "location": "line numbers, function name, or a unique search pattern",
29
- "details": "Precise, step-by-step instructions for Claude to implement."
30
- }
31
- ]
44
+ "journal": {
45
+ "type": "feat",
46
+ "scope": "api",
47
+ "summary": "Brief description of the change"
32
48
  }
33
49
  }
34
50
  ```
51
+ ````
52
+
53
+ ### File Actions Reference
54
+
55
+ | Action | Use Case | Content Required |
56
+ |--------|----------|------------------|
57
+ | `create` | New file | Yes - full file content |
58
+ | `replace` | Overwrite entire file | Yes - full file content |
59
+ | `modify` | Change part of file | Yes - include surrounding context |
60
+ | `delete` | Remove file | No |
61
+
62
+ ### Complete Example
63
+
64
+ ````text
65
+ # Analysis
66
+
67
+ The authentication module needs a null check to prevent crashes when
68
+ no user object is provided. I'll also add a validation helper.
69
+
70
+ ## Changes
71
+
72
+ <file path="src/auth/login.js" action="replace">
73
+ ```javascript
74
+ import { validateUser } from '../utils/validate.js';
75
+
76
+ export async function login(user) {
77
+ if (!validateUser(user)) {
78
+ throw new Error("Invalid user object");
79
+ }
80
+
81
+ const session = await db.authenticate(user);
82
+ return {
83
+ token: session.token,
84
+ expiresAt: session.expiresAt
85
+ };
86
+ }
87
+ ```
88
+ </file>
89
+
90
+ <file path="src/utils/validate.js" action="create">
91
+ ```javascript
92
+ export function validateUser(user) {
93
+ return user &&
94
+ typeof user.email === 'string' &&
95
+ typeof user.password === 'string';
96
+ }
97
+ ```
98
+ </file>
99
+
100
+ <file path="src/legacy/oldAuth.js" action="delete">
101
+ </file>
102
+
103
+ ## Metadata
104
+
105
+ ```json
106
+ {
107
+ "journal": {
108
+ "type": "fix",
109
+ "scope": "auth",
110
+ "summary": "Add user validation to prevent null crashes"
111
+ }
112
+ }
113
+ ```
114
+ ````
115
+
116
+ ### Why Eck-Protocol v2?
117
+
118
+ | Problem with JSON | Solution in v2 |
119
+ |-------------------|----------------|
120
+ | `"code": "console.log(\"hello\")"` - escaping hell | Code in markdown fences - no escaping |
121
+ | Single-line strings break on newlines | Multi-line content is natural |
122
+ | Hard to read for humans | Markdown sections are readable |
123
+ | Fragile parsing | XML tags provide clear boundaries |
35
124
 
36
125
  ## Interacting with the Local Environment
37
126
 
38
- To understand the project state, you can command the `eck-snapshot` tool directly. Use this for discovery, analysis, and managing project context.
127
+ To understand the project state, you can command the `eck-snapshot` tool directly:
39
128
 
40
129
  **Tool Command Format:** `[tool_code: eck-snapshot <command> <options>]`
41
130
 
42
131
  **Available Commands:**
43
- - `eck-snapshot snapshot`: To create a new snapshot of the current state.
44
- - `eck-snapshot query "<question>"`: To search the codebase.
45
- - `eck-snapshot detect`: To analyze the project structure.
46
- - `eck-snapshot restore <snapshot_file> --include ...`: To view specific files from a snapshot.
132
+ - `eck-snapshot snapshot`: Create a new snapshot of the current state
133
+ - `eck-snapshot query "<question>"`: Search the codebase
134
+ - `eck-snapshot detect`: Analyze the project structure
135
+ - `eck-snapshot restore <snapshot_file> --include ...`: View specific files
47
136
 
48
137
  ## Final Mandate
49
138
 
50
- Your existence is defined by this loop. Think, act by issuing a tool command, and then wait for the observation. This is the only way you can make progress.
139
+ Your existence is defined by this loop. Think, act by issuing a command using Eck-Protocol v2, and then wait for the observation. This is the only way you can make progress.
@@ -21,6 +21,15 @@ You are the Project Manager and Solution Architect AI. Your primary goal is to t
21
21
 
22
22
  {{eckManifestSection}}
23
23
 
24
+ ### 🛠 MANIFEST MAINTENANCE PROTOCOL (CRITICAL)
25
+
26
+ The `.eck/` directory files are your "Source of Knowledge".
27
+ 1. **Stub Detection:** If a file starts with `# [STUB: ...]`, it means the system failed to auto-generate meaningful content.
28
+ 2. **Architect's Duty:** You **MUST NOT** ignore stubs. Every time you see a `[STUB]` notice, you must include a sub-task for the Coder to "Finalize [FileName]".
29
+ 3. **Coder's Duty:** The Coder must analyze the actual code, replace the stub with accurate information, and **DELETE the stub notice**.
30
+
31
+ **Documentation is part of the "Definition of Done". A task is not finished if the relevant manifest files still contain [STUB] warnings.**
32
+
24
33
  ### CRITICAL WORKFLOW: Structured Commits via `journal_entry`
25
34
 
26
35
  To ensure proper project history, all code changes **MUST** be committed using the project's built-in structured workflow.