@codewithdan/zingit 0.16.1 → 0.17.1

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@codewithdan/zingit",
3
- "version": "0.16.1",
4
- "description": "AI-powered UI annotation tool - point, annotate, and let AI fix it",
3
+ "version": "0.17.1",
4
+ "description": "AI-powered UI marker tool - point, mark, and let AI fix it",
5
5
  "type": "module",
6
6
  "engines": {
7
7
  "node": ">=22.0.0"
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "keywords": [
36
36
  "ui",
37
- "annotation",
37
+ "marker",
38
38
  "ai",
39
39
  "agent",
40
40
  "claude",
@@ -11,8 +11,8 @@ export declare abstract class BaseAgent implements Agent {
11
11
  */
12
12
  protected formatPromptWithImageMetadata(prompt: string, images?: ImageContent[]): string;
13
13
  /**
14
- * Extract images from batch data annotations
15
- * Returns an array of ImageContent objects for annotations that have screenshots
14
+ * Extract images from batch data markers
15
+ * Returns an array of ImageContent objects for markers that have screenshots
16
16
  */
17
17
  extractImages(data: BatchData): ImageContent[];
18
18
  formatPrompt(data: BatchData, projectDir: string): string;
@@ -18,12 +18,12 @@ export class BaseAgent {
18
18
  return `${header}---\n\n${prompt}`;
19
19
  }
20
20
  /**
21
- * Extract images from batch data annotations
22
- * Returns an array of ImageContent objects for annotations that have screenshots
21
+ * Extract images from batch data markers
22
+ * Returns an array of ImageContent objects for markers that have screenshots
23
23
  */
24
24
  extractImages(data) {
25
25
  const images = [];
26
- data.annotations.forEach((ann, i) => {
26
+ data.markers.forEach((ann, i) => {
27
27
  if (ann.screenshot) {
28
28
  let base64Data = ann.screenshot;
29
29
  let mediaType = 'image/png'; // Default
@@ -48,13 +48,13 @@ export class BaseAgent {
48
48
  // 3. Check padding is correct
49
49
  const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;
50
50
  if (!base64Data || !base64Regex.test(base64Data) || base64Data.length % 4 !== 0) {
51
- console.warn(`ZingIt: Invalid base64 data in annotation ${i + 1}, skipping screenshot`);
52
- return; // Skip this annotation's screenshot
51
+ console.warn(`ZingIt: Invalid base64 data in marker ${i + 1}, skipping screenshot`);
52
+ return; // Skip this marker's screenshot
53
53
  }
54
54
  // Check image size limit (base64 is ~33% larger than binary)
55
55
  const estimatedBinarySize = Math.ceil(base64Data.length * 0.75);
56
56
  if (estimatedBinarySize > MAX_IMAGE_SIZE_BYTES) {
57
- console.warn(`ZingIt: Image in annotation ${i + 1} exceeds ${MAX_IMAGE_SIZE_BYTES / 1024 / 1024}MB limit, skipping`);
57
+ console.warn(`ZingIt: Image in marker ${i + 1} exceeds ${MAX_IMAGE_SIZE_BYTES / 1024 / 1024}MB limit, skipping`);
58
58
  return; // Skip oversized image
59
59
  }
60
60
  // Validate that base64 can be decoded (catches corrupted data)
@@ -62,13 +62,13 @@ export class BaseAgent {
62
62
  Buffer.from(base64Data, 'base64');
63
63
  }
64
64
  catch (err) {
65
- console.warn(`ZingIt: Failed to decode base64 in annotation ${i + 1}, skipping screenshot:`, err);
66
- return; // Skip this annotation's screenshot
65
+ console.warn(`ZingIt: Failed to decode base64 in marker ${i + 1}, skipping screenshot:`, err);
66
+ return; // Skip this marker's screenshot
67
67
  }
68
68
  images.push({
69
69
  base64: base64Data,
70
70
  mediaType,
71
- label: `Screenshot of Annotation ${i + 1}: ${ann.identifier}`
71
+ label: `Screenshot of Marker ${i + 1}: ${ann.identifier}`
72
72
  });
73
73
  }
74
74
  });
@@ -81,10 +81,10 @@ Page: ${data.pageTitle}
81
81
  URL: ${data.pageUrl}
82
82
 
83
83
  `;
84
- data.annotations.forEach((ann, i) => {
84
+ data.markers.forEach((ann, i) => {
85
85
  prompt += `---
86
86
 
87
- ## Annotation ${i + 1}: ${ann.identifier}
87
+ ## Marker ${i + 1}: ${ann.identifier}
88
88
 
89
89
  **Requested Change:** ${ann.notes}
90
90
 
@@ -108,8 +108,8 @@ ${ann.parentContext ? `**Parent Path:** \`${ann.parentContext}\`` : ''}
108
108
 
109
109
  `;
110
110
  });
111
- // Check if any annotations have screenshots
112
- const hasScreenshots = data.annotations.some(ann => ann.screenshot);
111
+ // Check if any markers have screenshots
112
+ const hasScreenshots = data.markers.some(ann => ann.screenshot);
113
113
  prompt += `
114
114
  CRITICAL INSTRUCTIONS:
115
115
  1. CAREFULLY identify the CORRECT element to modify:
@@ -84,7 +84,7 @@ CRITICAL EFFICIENCY RULES:
84
84
  2. Make the requested change immediately - don't explore or explain unless there's ambiguity
85
85
  3. For simple changes (text, styles, attributes), be concise - just do it and confirm
86
86
  4. Only search/explore if the selector doesn't match or you need to understand complex context
87
- 5. Avoid explaining what annotations are or describing the codebase unnecessarily
87
+ 5. Avoid explaining what markers are or describing the codebase unnecessarily
88
88
 
89
89
  WHEN TO BE BRIEF (90% of cases):
90
90
  - Text changes: Find, change, confirm (1-2 sentences)
@@ -79,7 +79,7 @@ export class CodexAgent extends BaseAgent {
79
79
  }
80
80
  }
81
81
  // Add system instructions and main prompt
82
- const systemInstructions = `You are a UI debugging assistant. When given annotations about UI elements, search for the corresponding code using the selectors and HTML context provided, then make the requested changes.
82
+ const systemInstructions = `You are a UI debugging assistant. When given markers about UI elements, search for the corresponding code using the selectors and HTML context provided, then make the requested changes.
83
83
 
84
84
  When screenshots are provided, use them to:
85
85
  - Better understand the visual context and styling of the elements
@@ -49,7 +49,7 @@ export class CopilotAgent extends BaseAgent {
49
49
  <context>
50
50
  You are a UI debugging assistant working in the project directory: ${projectDir}
51
51
 
52
- When given annotations about UI elements:
52
+ When given markers about UI elements:
53
53
  1. Search for the corresponding code using the selectors and HTML context provided
54
54
  2. Make the requested changes in the project at ${projectDir}
55
55
  3. Be thorough in finding the right files and making precise edits
@@ -116,7 +116,7 @@ export async function handleBatch(ws, state, msg, deps) {
116
116
  try {
117
117
  console.log('[Batch] Creating checkpoint...');
118
118
  const checkpoint = await state.gitManager.createCheckpoint({
119
- annotations: batchData.annotations,
119
+ markers: batchData.markers,
120
120
  pageUrl: batchData.pageUrl,
121
121
  pageTitle: batchData.pageTitle,
122
122
  agentName: state.agentName,
@@ -128,7 +128,7 @@ export async function handleBatch(ws, state, msg, deps) {
128
128
  checkpoint: {
129
129
  id: checkpoint.id,
130
130
  timestamp: checkpoint.timestamp,
131
- annotations: checkpoint.annotations,
131
+ markers: checkpoint.markers,
132
132
  filesModified: 0,
133
133
  linesChanged: 0,
134
134
  agentName: checkpoint.agentName,
@@ -169,12 +169,12 @@ export async function handleBatch(ws, state, msg, deps) {
169
169
  else {
170
170
  console.log('[Batch] Reusing existing session');
171
171
  }
172
- // Log user's annotations before formatting
173
- console.log('[Batch] Annotation count:', batchData.annotations?.length || 0);
174
- if (batchData.annotations && batchData.annotations.length > 0) {
175
- batchData.annotations.forEach((ann, idx) => {
176
- const notePreview = ann.notes?.substring(0, 200) || '(no notes)';
177
- console.log(`[Batch] Annotation ${idx + 1}: ${notePreview}`);
172
+ // Log user's markers before formatting
173
+ console.log('[Batch] Marker count:', batchData.markers?.length || 0);
174
+ if (batchData.markers && batchData.markers.length > 0) {
175
+ batchData.markers.forEach((m, idx) => {
176
+ const notePreview = m.notes?.substring(0, 200) || '(no notes)';
177
+ console.log(`[Batch] Marker ${idx + 1}: ${notePreview}`);
178
178
  });
179
179
  }
180
180
  if (batchData.pageUrl) {
@@ -229,7 +229,7 @@ export async function handleMessage(ws, state, msg, deps) {
229
229
  return;
230
230
  }
231
231
  console.log('[Message] ===== Request started =====');
232
- // Create session if it doesn't exist (allows direct messaging without annotations)
232
+ // Create session if it doesn't exist (allows direct messaging without markers)
233
233
  if (!state.session) {
234
234
  if (!state.agent) {
235
235
  console.warn('[ZingIt] No agent selected for message');
@@ -1,10 +1,10 @@
1
- import type { Annotation } from '../types.js';
1
+ import type { Marker } from '../types.js';
2
2
  export interface Checkpoint {
3
3
  id: string;
4
4
  timestamp: string;
5
5
  commitHash: string;
6
6
  branchName: string;
7
- annotations: AnnotationSummary[];
7
+ markers: MarkerSummary[];
8
8
  pageUrl: string;
9
9
  pageTitle: string;
10
10
  agentName: string;
@@ -12,7 +12,7 @@ export interface Checkpoint {
12
12
  filesModified: number;
13
13
  linesChanged: number;
14
14
  }
15
- export interface AnnotationSummary {
15
+ export interface MarkerSummary {
16
16
  id: string;
17
17
  identifier: string;
18
18
  notes: string;
@@ -32,7 +32,7 @@ export interface ChangeHistory {
32
32
  export interface CheckpointInfo {
33
33
  id: string;
34
34
  timestamp: string;
35
- annotations: AnnotationSummary[];
35
+ markers: MarkerSummary[];
36
36
  filesModified: number;
37
37
  linesChanged: number;
38
38
  agentName: string;
@@ -62,7 +62,7 @@ export declare class GitManager {
62
62
  * Create a checkpoint before AI modifications
63
63
  */
64
64
  createCheckpoint(metadata: {
65
- annotations: Annotation[];
65
+ markers: Marker[];
66
66
  pageUrl: string;
67
67
  pageTitle: string;
68
68
  agentName: string;
@@ -114,10 +114,10 @@ export class GitManager {
114
114
  timestamp: new Date().toISOString(),
115
115
  commitHash: commitHash.trim(),
116
116
  branchName: status.branch,
117
- annotations: metadata.annotations.map((a) => ({
118
- id: a.id,
119
- identifier: a.identifier,
120
- notes: a.notes,
117
+ markers: metadata.markers.map((m) => ({
118
+ id: m.id,
119
+ identifier: m.identifier,
120
+ notes: m.notes,
121
121
  })),
122
122
  pageUrl: metadata.pageUrl,
123
123
  pageTitle: metadata.pageTitle,
@@ -188,7 +188,7 @@ export class GitManager {
188
188
  if (fileChanges.length > 0) {
189
189
  try {
190
190
  await execFileAsync('git', ['add', '-A'], { cwd: this.projectDir });
191
- const identifiers = checkpoint.annotations.map((a) => sanitizeForGit(a.identifier)).join(', ');
191
+ const identifiers = checkpoint.markers.map((a) => sanitizeForGit(a.identifier)).join(', ');
192
192
  const commitMsg = `[ZingIt] ${identifiers}`;
193
193
  // Use execFile with array args to avoid shell injection
194
194
  await execFileAsync('git', ['commit', '-m', commitMsg], { cwd: this.projectDir });
@@ -266,7 +266,7 @@ export class GitManager {
266
266
  return history.checkpoints.map((cp, index) => ({
267
267
  id: cp.id,
268
268
  timestamp: cp.timestamp,
269
- annotations: cp.annotations,
269
+ markers: cp.markers,
270
270
  filesModified: cp.filesModified,
271
271
  linesChanged: cp.linesChanged,
272
272
  agentName: cp.agentName,
@@ -1,2 +1,2 @@
1
1
  export { GitManager, GitManagerError } from './git-manager.js';
2
- export type { Checkpoint, CheckpointInfo, ChangeHistory, FileChange, AnnotationSummary } from './git-manager.js';
2
+ export type { Checkpoint, CheckpointInfo, ChangeHistory, FileChange, MarkerSummary } from './git-manager.js';
@@ -29,7 +29,7 @@ export interface AgentSession {
29
29
  destroy(): Promise<void>;
30
30
  getSessionId?(): string | null;
31
31
  }
32
- export interface Annotation {
32
+ export interface Marker {
33
33
  id: string;
34
34
  selector: string;
35
35
  identifier: string;
@@ -46,7 +46,7 @@ export interface Annotation {
46
46
  export interface BatchData {
47
47
  pageUrl: string;
48
48
  pageTitle: string;
49
- annotations: Annotation[];
49
+ markers: Marker[];
50
50
  projectDir?: string;
51
51
  }
52
52
  export type WSIncomingType = 'batch' | 'message' | 'reset' | 'stop' | 'get_agents' | 'select_agent' | 'get_history' | 'undo' | 'revert_to' | 'clear_history';
@@ -1,5 +1,5 @@
1
1
  import type { BatchData } from '../types.js';
2
- export declare const MAX_ANNOTATIONS = 50;
2
+ export declare const MAX_MARKERS = 50;
3
3
  export declare const MAX_HTML_LENGTH = 50000;
4
4
  export declare const MAX_NOTES_LENGTH = 5000;
5
5
  export declare const MAX_SELECTOR_LENGTH = 1000;
@@ -2,33 +2,33 @@
2
2
  // ============================================
3
3
  // Payload Validation
4
4
  // ============================================
5
- export const MAX_ANNOTATIONS = 50;
5
+ export const MAX_MARKERS = 50;
6
6
  export const MAX_HTML_LENGTH = 50000;
7
7
  export const MAX_NOTES_LENGTH = 5000;
8
8
  export const MAX_SELECTOR_LENGTH = 1000;
9
9
  export const MAX_SCREENSHOT_SIZE = 5000000; // ~5MB base64 (matches Claude API limit)
10
10
  const VALID_STATUSES = ['pending', 'processing', 'completed'];
11
- function validateAnnotation(annotation, index) {
12
- if (!annotation.id || typeof annotation.id !== 'string') {
13
- return { valid: false, error: `Annotation ${index}: missing or invalid id` };
11
+ function validateMarker(marker, index) {
12
+ if (!marker.id || typeof marker.id !== 'string') {
13
+ return { valid: false, error: `Marker ${index}: missing or invalid id` };
14
14
  }
15
- if (!annotation.identifier || typeof annotation.identifier !== 'string') {
16
- return { valid: false, error: `Annotation ${index}: missing or invalid identifier` };
15
+ if (!marker.identifier || typeof marker.identifier !== 'string') {
16
+ return { valid: false, error: `Marker ${index}: missing or invalid identifier` };
17
17
  }
18
- if (annotation.status && !VALID_STATUSES.includes(annotation.status)) {
19
- return { valid: false, error: `Annotation ${index}: invalid status '${annotation.status}'` };
18
+ if (marker.status && !VALID_STATUSES.includes(marker.status)) {
19
+ return { valid: false, error: `Marker ${index}: invalid status '${marker.status}'` };
20
20
  }
21
- if (annotation.selector && annotation.selector.length > MAX_SELECTOR_LENGTH) {
22
- return { valid: false, error: `Annotation ${index}: selector too long (max ${MAX_SELECTOR_LENGTH})` };
21
+ if (marker.selector && marker.selector.length > MAX_SELECTOR_LENGTH) {
22
+ return { valid: false, error: `Marker ${index}: selector too long (max ${MAX_SELECTOR_LENGTH})` };
23
23
  }
24
- if (annotation.html && annotation.html.length > MAX_HTML_LENGTH) {
25
- return { valid: false, error: `Annotation ${index}: html too long (max ${MAX_HTML_LENGTH})` };
24
+ if (marker.html && marker.html.length > MAX_HTML_LENGTH) {
25
+ return { valid: false, error: `Marker ${index}: html too long (max ${MAX_HTML_LENGTH})` };
26
26
  }
27
- if (annotation.notes && annotation.notes.length > MAX_NOTES_LENGTH) {
28
- return { valid: false, error: `Annotation ${index}: notes too long (max ${MAX_NOTES_LENGTH})` };
27
+ if (marker.notes && marker.notes.length > MAX_NOTES_LENGTH) {
28
+ return { valid: false, error: `Marker ${index}: notes too long (max ${MAX_NOTES_LENGTH})` };
29
29
  }
30
- if (annotation.screenshot && annotation.screenshot.length > MAX_SCREENSHOT_SIZE) {
31
- return { valid: false, error: `Annotation ${index}: screenshot too large (max ${MAX_SCREENSHOT_SIZE / 1000}KB)` };
30
+ if (marker.screenshot && marker.screenshot.length > MAX_SCREENSHOT_SIZE) {
31
+ return { valid: false, error: `Marker ${index}: screenshot too large (max ${MAX_SCREENSHOT_SIZE / 1000}KB)` };
32
32
  }
33
33
  return { valid: true };
34
34
  }
@@ -36,18 +36,18 @@ export function validateBatchData(data) {
36
36
  if (!data) {
37
37
  return { valid: false, error: 'Missing batch data' };
38
38
  }
39
- if (!data.annotations || !Array.isArray(data.annotations)) {
40
- return { valid: false, error: 'Missing or invalid annotations array' };
39
+ if (!data.markers || !Array.isArray(data.markers)) {
40
+ return { valid: false, error: 'Missing or invalid markers array' };
41
41
  }
42
- if (data.annotations.length === 0) {
43
- return { valid: false, error: 'No annotations provided' };
42
+ if (data.markers.length === 0) {
43
+ return { valid: false, error: 'No markers provided' };
44
44
  }
45
- if (data.annotations.length > MAX_ANNOTATIONS) {
46
- return { valid: false, error: `Too many annotations (max ${MAX_ANNOTATIONS})` };
45
+ if (data.markers.length > MAX_MARKERS) {
46
+ return { valid: false, error: `Too many markers (max ${MAX_MARKERS})` };
47
47
  }
48
- // Validate each annotation
49
- for (let i = 0; i < data.annotations.length; i++) {
50
- const result = validateAnnotation(data.annotations[i], i);
48
+ // Validate each marker
49
+ for (let i = 0; i < data.markers.length; i++) {
50
+ const result = validateMarker(data.markers[i], i);
51
51
  if (!result.valid) {
52
52
  return { valid: false, error: result.error };
53
53
  }