checkpoint-cli 0.4.0 → 0.5.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/index.js CHANGED
@@ -446,12 +446,12 @@ function loginWithBrowser() {
446
446
  const program = new commander_1.Command();
447
447
  program
448
448
  .name('checkpoint')
449
- .description('Share your localhost with reviewers — get visual feedback directly on the page')
450
- .version('0.4.0');
449
+ .description('Share your localhost with reviewers — get visual feedback directly on the page.\n\nQuick start:\n 1. checkpoint login Sign in to your Checkpoint account\n 2. checkpoint start -p 3000 Start tunneling and get a share link\n\nReuse a tunnel name to keep the same share URL and preserve all comments.')
450
+ .version('0.5.0');
451
451
  // ── checkpoint login ──
452
452
  program
453
453
  .command('login')
454
- .description('Authenticate with Checkpoint via the browser')
454
+ .description('Sign in to your Checkpoint account. Opens the browser for authentication.')
455
455
  .action(async () => {
456
456
  console.log('');
457
457
  console.log(chalk_1.default.blue.bold(' ⟐ Checkpoint'));
@@ -497,7 +497,7 @@ program
497
497
  // ── checkpoint logout ──
498
498
  program
499
499
  .command('logout')
500
- .description('Sign out and remove stored credentials')
500
+ .description('Sign out and clear saved credentials from this machine.')
501
501
  .action(() => {
502
502
  console.log('');
503
503
  console.log(chalk_1.default.blue.bold(' ⟐ Checkpoint'));
@@ -509,9 +509,9 @@ program
509
509
  // ── checkpoint start ──
510
510
  program
511
511
  .command('start')
512
- .description('Tunnel a local port and create a Checkpoint share link')
513
- .requiredOption('-p, --port <port>', 'Local port to tunnel', '3000')
514
- .option('-n, --name <name>', 'Name for this tunnel')
512
+ .description('Start tunneling a local port and get a shareable link for reviewers.\nIf a tunnel with the same name already exists, it reconnects to it —\nkeeping the same share URL and all previous comments intact.')
513
+ .requiredOption('-p, --port <port>', 'Local port your dev server is running on (e.g. 3000, 5173)', '3000')
514
+ .option('-n, --name <name>', 'Tunnel name. Reuse a name to resume the same share URL.')
515
515
  .option('--provider <provider>', 'Tunnel provider: cloudflared (default) or ngrok')
516
516
  .action(async (opts) => {
517
517
  requireAuth();
@@ -611,10 +611,10 @@ program
611
611
  // ── checkpoint share ──
612
612
  program
613
613
  .command('share')
614
- .description('Register an existing tunnel URL with Checkpoint')
615
- .requiredOption('-u, --url <url>', 'Your tunnel URL')
614
+ .description('Register an existing tunnel URL (e.g. from ngrok) with Checkpoint.\nUse this if you already have a tunnel running and just need a share link.')
615
+ .requiredOption('-u, --url <url>', 'The public tunnel URL to register (https://...)')
616
616
  .option('-n, --name <name>', 'Name for this tunnel', 'My Tunnel')
617
- .option('-p, --port <port>', 'Local port (for reference)', '3000')
617
+ .option('-p, --port <port>', 'Local port for reference', '3000')
618
618
  .action(async (opts) => {
619
619
  requireAuth();
620
620
  console.log('');
@@ -673,7 +673,7 @@ program
673
673
  // ── checkpoint status ──
674
674
  program
675
675
  .command('status')
676
- .description('Check setup status')
676
+ .description('Show login status and which tunnel providers are installed.')
677
677
  .action(async () => {
678
678
  console.log('');
679
679
  console.log(chalk_1.default.blue.bold(' ⟐ Checkpoint — Status'));
@@ -711,7 +711,7 @@ program
711
711
  // ── checkpoint whoami ──
712
712
  program
713
713
  .command('whoami')
714
- .description('Show the currently logged in user')
714
+ .description('Print the email of the currently logged-in user.')
715
715
  .action(async () => {
716
716
  const config = (0, config_js_1.loadConfig)();
717
717
  if (!config) {
@@ -14,7 +14,6 @@ function buildMinimalTrackingScript() {
14
14
  var lastMouseX=0;
15
15
  var lastMouseY=0;
16
16
  var inspectBox=null;
17
- var inspectLabel=null;
18
17
  var pickShield=null;
19
18
  var lastPath='';
20
19
  var mutationTick=false;
@@ -147,6 +146,214 @@ function buildMinimalTrackingScript() {
147
146
  return path.slice(-12);
148
147
  }
149
148
 
149
+ function withFrameworkSuffix(path,framework){
150
+ var safePath=Array.isArray(path)?path.slice(0):[];
151
+ if(framework) safePath.push('@fw:'+framework);
152
+ return safePath.slice(-16);
153
+ }
154
+
155
+ function getVueComponentFromElement(el){
156
+ if(!el||el.nodeType!==1) return null;
157
+ var current=el;
158
+ var depth=0;
159
+ while(current&&depth<8){
160
+ try{
161
+ if(current.__vueParentComponent) return current.__vueParentComponent;
162
+ if(current.__vue__) return current.__vue__;
163
+ if(current.__vnode&&current.__vnode.component) return current.__vnode.component;
164
+ }catch(e){}
165
+ current=current.parentElement;
166
+ depth++;
167
+ }
168
+ return null;
169
+ }
170
+
171
+ function getVueComponentName(instance){
172
+ try{
173
+ if(!instance) return '';
174
+ if(instance.type){
175
+ var t=instance.type;
176
+ if(typeof t.name==='string'&&t.name) return t.name;
177
+ if(typeof t.__name==='string'&&t.__name) return t.__name;
178
+ if(typeof t.displayName==='string'&&t.displayName) return t.displayName;
179
+ }
180
+ if(instance.$options&&typeof instance.$options.name==='string'&&instance.$options.name){
181
+ return instance.$options.name;
182
+ }
183
+ }catch(e){}
184
+ return '';
185
+ }
186
+
187
+ function getVueSourceFile(instance){
188
+ try{
189
+ if(!instance) return '';
190
+ if(instance.type&&typeof instance.type.__file==='string'&&instance.type.__file) return instance.type.__file;
191
+ if(instance.$options&&typeof instance.$options.__file==='string'&&instance.$options.__file) return instance.$options.__file;
192
+ }catch(e){}
193
+ return '';
194
+ }
195
+
196
+ function getVueOwnerPath(instance){
197
+ var path=[];
198
+ var current=instance;
199
+ var steps=0;
200
+ while(current&&steps<24){
201
+ var name=getVueComponentName(current);
202
+ var keyVal='';
203
+ try{
204
+ if(current.vnode&&current.vnode.key!=null) keyVal=String(current.vnode.key);
205
+ else if(current.$vnode&&current.$vnode.key!=null) keyVal=String(current.$vnode.key);
206
+ }catch(e){}
207
+ if(name) path.push(keyVal?name+'#'+keyVal:name);
208
+ current=current.parent||current.$parent||null;
209
+ steps++;
210
+ }
211
+ path.reverse();
212
+ return path.slice(-12);
213
+ }
214
+
215
+ function getVueInstanceKey(instance){
216
+ try{
217
+ if(!instance) return '';
218
+ if(instance.vnode&&instance.vnode.key!=null) return String(instance.vnode.key);
219
+ if(instance.$vnode&&instance.$vnode.key!=null) return String(instance.$vnode.key);
220
+ }catch(e){}
221
+ return '';
222
+ }
223
+
224
+ function getSvelteMetaFromElement(el){
225
+ if(!el||el.nodeType!==1) return null;
226
+ var current=el;
227
+ var depth=0;
228
+ while(current&&depth<8){
229
+ try{
230
+ if(current.__svelte_meta) return current.__svelte_meta;
231
+ }catch(e){}
232
+ current=current.parentElement;
233
+ depth++;
234
+ }
235
+ return null;
236
+ }
237
+
238
+ function basename(path){
239
+ if(!path) return '';
240
+ try{
241
+ var clean=String(path).split(/[\\/]/).pop()||'';
242
+ return clean;
243
+ }catch(e){}
244
+ return '';
245
+ }
246
+
247
+ function withoutExt(name){
248
+ if(!name) return '';
249
+ return String(name).replace(/\.[^.]+$/,'');
250
+ }
251
+
252
+ function getAngularComponentFromElement(el){
253
+ var ngApi=null;
254
+ try{ ngApi=window.ng||null; }catch(e){ ngApi=null; }
255
+ if(!ngApi||typeof ngApi.getComponent!=='function') return null;
256
+ var current=el;
257
+ var depth=0;
258
+ while(current&&depth<8){
259
+ try{
260
+ var comp=ngApi.getComponent(current);
261
+ if(comp) return { component:comp, host:current };
262
+ }catch(e){}
263
+ current=current.parentElement;
264
+ depth++;
265
+ }
266
+ return null;
267
+ }
268
+
269
+ function getAngularOwnerPath(el){
270
+ var ngApi=null;
271
+ try{ ngApi=window.ng||null; }catch(e){ ngApi=null; }
272
+ if(!ngApi||typeof ngApi.getComponent!=='function') return [];
273
+ var path=[];
274
+ var current=el;
275
+ var depth=0;
276
+ while(current&&depth<12){
277
+ try{
278
+ var comp=ngApi.getComponent(current);
279
+ if(comp&&comp.constructor&&comp.constructor.name){
280
+ path.push(String(comp.constructor.name));
281
+ }
282
+ }catch(e){}
283
+ current=current.parentElement;
284
+ depth++;
285
+ }
286
+ path.reverse();
287
+ return path.slice(-12);
288
+ }
289
+
290
+ function getFrameworkContextFromElement(el){
291
+ if(!el||el.nodeType!==1) return null;
292
+
293
+ var fiber=getReactFiberNode(el);
294
+ if(fiber){
295
+ var reactPath=getReactOwnerPathFromFiber(fiber);
296
+ var reactSource=getSourceDebugInfo(fiber);
297
+ return {
298
+ framework:'react',
299
+ component_name:getReactFiberName(fiber)||'',
300
+ owner_path:withFrameworkSuffix(reactPath,'react'),
301
+ source_file:reactSource&&reactSource.fileName?String(reactSource.fileName):'',
302
+ source_line:reactSource&&typeof reactSource.lineNumber==='number'?reactSource.lineNumber:undefined,
303
+ source_column:reactSource&&typeof reactSource.columnNumber==='number'?reactSource.columnNumber:undefined,
304
+ instance_key:fiber&&fiber.key!=null?String(fiber.key):''
305
+ };
306
+ }
307
+
308
+ var vueInstance=getVueComponentFromElement(el);
309
+ if(vueInstance){
310
+ var vueFile=getVueSourceFile(vueInstance);
311
+ return {
312
+ framework:'vue',
313
+ component_name:getVueComponentName(vueInstance)||withoutExt(basename(vueFile))||'',
314
+ owner_path:withFrameworkSuffix(getVueOwnerPath(vueInstance),'vue'),
315
+ source_file:vueFile||'',
316
+ source_line:undefined,
317
+ source_column:undefined,
318
+ instance_key:getVueInstanceKey(vueInstance)||''
319
+ };
320
+ }
321
+
322
+ var svelteMeta=getSvelteMetaFromElement(el);
323
+ if(svelteMeta){
324
+ var sLoc=svelteMeta.loc||null;
325
+ var sFile=sLoc&&sLoc.file?String(sLoc.file):'';
326
+ var sName=withoutExt(basename(sFile));
327
+ return {
328
+ framework:'svelte',
329
+ component_name:sName||'SvelteComponent',
330
+ owner_path:withFrameworkSuffix(sName?[sName]:[],'svelte'),
331
+ source_file:sFile||'',
332
+ source_line:sLoc&&typeof sLoc.line==='number'?sLoc.line:undefined,
333
+ source_column:sLoc&&typeof sLoc.column==='number'?sLoc.column:undefined,
334
+ instance_key:''
335
+ };
336
+ }
337
+
338
+ var ngMatch=getAngularComponentFromElement(el);
339
+ if(ngMatch&&ngMatch.component){
340
+ var ngName=(ngMatch.component.constructor&&ngMatch.component.constructor.name)
341
+ ? String(ngMatch.component.constructor.name)
342
+ : 'AngularComponent';
343
+ return {
344
+ framework:'angular',
345
+ component_name:ngName,
346
+ owner_path:withFrameworkSuffix(getAngularOwnerPath(el),'angular'),
347
+ source_file:'',
348
+ source_line:undefined,
349
+ source_column:undefined,
350
+ instance_key:''
351
+ };
352
+ }
353
+
354
+ return null;
355
+ }
356
+
150
357
  function getExplicitAnchorId(el){
151
358
  if(!el||typeof el.closest!=='function') return '';
152
359
  var holder=el.closest('[data-checkpoint-anchor]');
@@ -156,22 +363,26 @@ function buildMinimalTrackingScript() {
156
363
 
157
364
  function getSourceAnchorFromElement(el){
158
365
  if(!el||el.nodeType!==1) return null;
159
- var fiber=getReactFiberNode(el);
160
- var ownerPath=getReactOwnerPathFromFiber(fiber);
161
- var source=getSourceDebugInfo(fiber);
162
- var component=getReactFiberName(fiber);
163
366
  var explicitId=getExplicitAnchorId(el);
164
- var reactKey=fiber&&fiber.key!=null?String(fiber.key):'';
165
- var hasData=!!(explicitId||component||ownerPath.length>0||source||reactKey);
367
+ var context=getFrameworkContextFromElement(el);
368
+ var hasData=!!(
369
+ explicitId||
370
+ (context&&(
371
+ context.component_name||
372
+ (Array.isArray(context.owner_path)&&context.owner_path.length>0)||
373
+ context.source_file||
374
+ context.instance_key
375
+ ))
376
+ );
166
377
  if(!hasData) return null;
167
378
  return {
168
379
  explicit_id:explicitId||undefined,
169
- component_name:component||undefined,
170
- owner_path:ownerPath,
171
- source_file:source&&source.fileName?String(source.fileName):undefined,
172
- source_line:source&&typeof source.lineNumber==='number'?source.lineNumber:undefined,
173
- source_column:source&&typeof source.columnNumber==='number'?source.columnNumber:undefined,
174
- react_key:reactKey||undefined,
380
+ component_name:context&&context.component_name?context.component_name:undefined,
381
+ owner_path:context&&Array.isArray(context.owner_path)?context.owner_path:[],
382
+ source_file:context&&context.source_file?context.source_file:undefined,
383
+ source_line:context&&typeof context.source_line==='number'?context.source_line:undefined,
384
+ source_column:context&&typeof context.source_column==='number'?context.source_column:undefined,
385
+ react_key:context&&context.instance_key?context.instance_key:undefined,
175
386
  host_tag:el&&el.tagName?String(el.tagName).toLowerCase():undefined
176
387
  };
177
388
  }
@@ -249,17 +460,16 @@ function buildMinimalTrackingScript() {
249
460
  if(explicit===sourceAnchor.explicit_id) score+=2400;
250
461
  else if(explicit) score-=200;
251
462
  }
252
- var fiber=getReactFiberNode(el);
253
- var component=getReactFiberName(fiber);
254
- var source=getSourceDebugInfo(fiber);
255
- var ownerPath=getReactOwnerPathFromFiber(fiber);
463
+ var context=getFrameworkContextFromElement(el);
464
+ var component=context&&context.component_name?context.component_name:'';
465
+ var ownerPath=context&&Array.isArray(context.owner_path)?context.owner_path:[];
256
466
  if(sourceAnchor.component_name&&component===sourceAnchor.component_name) score+=240;
257
- if(sourceAnchor.react_key&&fiber&&fiber.key!=null&&String(fiber.key)===sourceAnchor.react_key) score+=360;
467
+ if(sourceAnchor.react_key&&context&&context.instance_key&&String(context.instance_key)===sourceAnchor.react_key) score+=360;
258
468
  score+=ownerSuffixScore(ownerPath,sourceAnchor.owner_path||[]);
259
- if(sourceAnchor.source_file&&source&&String(source.fileName||'')===String(sourceAnchor.source_file)){
469
+ if(sourceAnchor.source_file&&context&&context.source_file&&String(context.source_file||'')===String(sourceAnchor.source_file)){
260
470
  score+=420;
261
- if(typeof sourceAnchor.source_line==='number'&&source.lineNumber===sourceAnchor.source_line) score+=420;
262
- if(typeof sourceAnchor.source_column==='number'&&source.columnNumber===sourceAnchor.source_column) score+=80;
471
+ if(typeof sourceAnchor.source_line==='number'&&context.source_line===sourceAnchor.source_line) score+=420;
472
+ if(typeof sourceAnchor.source_column==='number'&&context.source_column===sourceAnchor.source_column) score+=80;
263
473
  }
264
474
  if(sourceAnchor.host_tag&&el.tagName&&String(el.tagName).toLowerCase()===sourceAnchor.host_tag) score+=40;
265
475
  return score;
@@ -451,29 +661,6 @@ function buildMinimalTrackingScript() {
451
661
  return { coordFallback:null, strategy:'none', matchedSelector:null, status:'none' };
452
662
  }
453
663
 
454
- function getInspectLabelText(target){
455
- if(!target||!target.tagName) return '';
456
- var tag=String(target.tagName).toLowerCase();
457
- var id=target.id?('#'+target.id):'';
458
- var cls='';
459
- try{
460
- var classes=(target.className&&typeof target.className==='string')
461
- ? target.className.trim().split(/\s+/).filter(Boolean).slice(0,3)
462
- : [];
463
- if(classes.length>0) cls='.'+classes.join('.');
464
- }catch(e){}
465
- var selector=shortText(tag+id+cls);
466
- var anchor=findBestAnchorableElement(target).sourceAnchor;
467
- var source='(no source)';
468
- if(anchor){
469
- var file=anchor.source_file?String(anchor.source_file).split(/[\\/]/).pop():'';
470
- if(file&&typeof anchor.source_line==='number') source=file+':'+anchor.source_line;
471
- else if(file) source=file;
472
- else if(anchor.component_name) source=anchor.component_name;
473
- if(anchor.explicit_id) source=source+' · #'+anchor.explicit_id;
474
- }
475
- return selector+'\n'+source;
476
- }
477
664
 
478
665
  function ensureInspectUi(){
479
666
  if(!document.body) return;
@@ -493,31 +680,10 @@ inspectBox.style.border='2px solid #F26522';
493
680
  inspectBox.style.display='none';
494
681
  document.body.appendChild(inspectBox);
495
682
  }
496
- if(!inspectLabel){
497
- inspectLabel=document.createElement('div');
498
- inspectLabel.style.position='fixed';
499
- inspectLabel.style.left='0';
500
- inspectLabel.style.top='0';
501
- inspectLabel.style.padding='6px 8px';
502
- inspectLabel.style.maxWidth='420px';
503
- inspectLabel.style.borderRadius='8px';
504
- inspectLabel.style.border='1px solid rgba(148,163,184,0.45)';
505
- inspectLabel.style.background='rgba(15,23,42,0.96)';
506
- inspectLabel.style.color='#e2e8f0';
507
- inspectLabel.style.font='12px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace';
508
- inspectLabel.style.whiteSpace='pre-line';
509
- inspectLabel.style.wordBreak='break-word';
510
- inspectLabel.style.pointerEvents='none';
511
- inspectLabel.style.zIndex='2147483647';
512
- inspectLabel.style.display='none';
513
- inspectLabel.style.boxShadow='0 6px 20px rgba(0,0,0,0.35)';
514
- document.body.appendChild(inspectLabel);
515
- }
516
683
  }
517
684
 
518
685
  function hideInspectUi(){
519
- if(inspectBox) inspectBox.style.display='none';
520
- if(inspectLabel) inspectLabel.style.display='none';
686
+ if(inspectBox) inspectBox.style.display='none';
521
687
  }
522
688
 
523
689
  function ensurePickShield(){
@@ -544,7 +710,7 @@ inspectBox.style.border='2px solid #F26522';
544
710
 
545
711
  function renderInspectAt(x,y){
546
712
  ensureInspectUi();
547
- if(!inspectBox||!inspectLabel){
713
+ if(!inspectBox){
548
714
  return;
549
715
  }
550
716
  var target=getElementAtPoint(x,y);
@@ -562,18 +728,6 @@ inspectBox.style.border='2px solid #F26522';
562
728
  inspectBox.style.top=Math.max(0,rect.top)+'px';
563
729
  inspectBox.style.width=Math.max(1,rect.width)+'px';
564
730
  inspectBox.style.height=Math.max(1,rect.height)+'px';
565
- inspectLabel.textContent=getInspectLabelText(target);
566
- inspectLabel.style.display='block';
567
-
568
- var vw=window.innerWidth||document.documentElement.clientWidth||0;
569
- var vh=window.innerHeight||document.documentElement.clientHeight||0;
570
- var lr=inspectLabel.getBoundingClientRect();
571
- var left=x+12;
572
- var top=y+12;
573
- if(left+lr.width>vw-8) left=Math.max(8,x-lr.width-12);
574
- if(top+lr.height>vh-8) top=Math.max(8,y-lr.height-12);
575
- inspectLabel.style.left=left+'px';
576
- inspectLabel.style.top=top+'px';
577
731
  }
578
732
 
579
733
  function postPickResult(target,clientX,clientY){
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "checkpoint-cli",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Share your localhost with reviewers — get visual feedback directly on the page",
5
5
  "keywords": [
6
6
  "checkpoint",