gipity 1.0.379 → 1.0.380

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/progress.js CHANGED
@@ -19,11 +19,26 @@ class TerminalProgress {
19
19
  /** True while an in-place transfer line is on screen and not yet committed. */
20
20
  liveOpen = false;
21
21
  lastRenderAt = 0;
22
+ /** The label of the current transfer session; a change starts a fresh one. */
23
+ barLabel = null;
24
+ /** True once the current session hit 100% - late/overshoot ticks are dropped. */
25
+ barSettled = false;
22
26
  phase(message) {
23
27
  this.commitLive();
24
28
  process.stdout.write(` ${muted(message)}\n`);
25
29
  }
26
30
  transfer(label, doneBytes, totalBytes) {
31
+ // A new label begins a fresh transfer session (e.g. downloads → uploads on
32
+ // the same reporter). Within a session, once we've drawn the 100% frame we
33
+ // drop any further ticks - download byte totals are estimated, so the wire
34
+ // can deliver a hair more or fewer bytes than expected and we don't want a
35
+ // late chunk reopening a second "100%" line.
36
+ if (label !== this.barLabel) {
37
+ this.barLabel = label;
38
+ this.barSettled = false;
39
+ }
40
+ if (this.barSettled)
41
+ return;
27
42
  const finished = totalBytes > 0 && doneBytes >= totalBytes;
28
43
  // Throttle mid-flight redraws; always paint the first and final frames.
29
44
  const now = Date.now();
@@ -32,8 +47,10 @@ class TerminalProgress {
32
47
  this.lastRenderAt = now;
33
48
  this.liveOpen = true;
34
49
  process.stdout.write('\r' + this.frame(label, doneBytes, totalBytes) + CLEAR_TO_EOL);
35
- if (finished)
50
+ if (finished) {
36
51
  this.commitLive();
52
+ this.barSettled = true;
53
+ }
37
54
  }
38
55
  finish() {
39
56
  this.commitLive();
package/dist/sync.js CHANGED
@@ -195,14 +195,14 @@ async function fetchRemote(projectGuid) {
195
195
  }
196
196
  return out;
197
197
  }
198
- async function downloadAll(projectGuid) {
198
+ async function downloadAll(projectGuid, onBytes) {
199
199
  const stream = await downloadStream(`/projects/${projectGuid}/files/tree?content=tar`);
200
200
  const extract = tar.extract();
201
201
  const files = new Map();
202
202
  return new Promise((resolve, reject) => {
203
203
  extract.on('entry', (header, entryStream, next) => {
204
204
  const chunks = [];
205
- entryStream.on('data', (c) => chunks.push(c));
205
+ entryStream.on('data', (c) => { chunks.push(c); onBytes?.(c.length); });
206
206
  entryStream.on('end', () => { files.set(header.name, Buffer.concat(chunks)); next(); });
207
207
  entryStream.resume();
208
208
  });
@@ -519,9 +519,23 @@ async function syncInner(projectGuid, root, ignore, opts, interactive) {
519
519
  const downloadedBytes = new Map();
520
520
  const needsBulkDownload = plannedToApply.some(a => a.kind === 'download' || a.kind === 'conflict');
521
521
  if (needsBulkDownload) {
522
- p?.phase('Downloading updates from Gipity…');
522
+ // The tree endpoint streams the *whole* remote tree as one tar (the caller
523
+ // then picks out only the paths it planned to apply), so the bytes that
524
+ // actually move = the sum of every remote file's size. That's the honest
525
+ // denominator for the bar - it tracks real wire progress, not just the
526
+ // handful of changed files.
527
+ const downloadLabel = 'Downloading updates from Gipity';
528
+ const totalDownloadBytes = [...remote.values()].reduce((sum, r) => sum + r.size, 0);
529
+ let recvBytes = 0;
530
+ p?.transfer(downloadLabel, 0, totalDownloadBytes);
531
+ const onBytes = p
532
+ ? (delta) => {
533
+ recvBytes = Math.min(recvBytes + delta, totalDownloadBytes);
534
+ p.transfer(downloadLabel, recvBytes, totalDownloadBytes);
535
+ }
536
+ : undefined;
523
537
  try {
524
- const all = await downloadAll(config.projectGuid);
538
+ const all = await downloadAll(config.projectGuid, onBytes);
525
539
  for (const a of plannedToApply) {
526
540
  if (a.kind === 'download' || a.kind === 'conflict') {
527
541
  const buf = all.get(a.path);
@@ -533,6 +547,11 @@ async function syncInner(projectGuid, root, ignore, opts, interactive) {
533
547
  catch (err) {
534
548
  errors.push(`Download batch failed: ${err.message}`);
535
549
  }
550
+ finally {
551
+ // Settle the bar even if the extracted-byte tally fell short of the
552
+ // estimate (the live line stays open until something hits 100% or finish()).
553
+ p?.finish();
554
+ }
536
555
  }
537
556
  // ── Writes pass: uploads, downloads, conflicts (rename + download + upload copy) ──
538
557
  // We serialize conflicts; uploads run with bounded concurrency.
@@ -68,7 +68,10 @@ export function buildTemplateVars(v) {
68
68
  '{{DESCRIPTION_META}}': v.description ? `\n <meta name="description" content="${safeDesc}">` : '',
69
69
  '{{OG_DESCRIPTION}}': v.description ? `\n <meta property="og:description" content="${safeDesc}">` : '',
70
70
  '{{JSON_LD_BLOCK}}': `<script type="application/ld+json">\n${jsonLd}\n </script>`,
71
- '{{ANALYTICS_SCRIPT}}': `<script defer src="https://media.gipity.ai/client/v1/gipity.js" data-app="${v.projectGuid}"></script>`,
71
+ // `crossorigin="anonymous"` so SDK errors surface with a real message/stack
72
+ // (CORS mode) instead of a sanitized message-less "Script error". The CDN
73
+ // returns Access-Control-Allow-Origin:*, so it works on any app domain.
74
+ '{{ANALYTICS_SCRIPT}}': `<script defer crossorigin="anonymous" src="https://media.gipity.ai/client/v1/gipity.js" data-app="${v.projectGuid}"></script>`,
72
75
  };
73
76
  }
74
77
  /** Pure string substitution — exported so the test can exercise it without
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gipity",
3
- "version": "1.0.379",
3
+ "version": "1.0.380",
4
4
  "description": "The full-stack platform tuned for AI agents. Database, storage, auth, functions, deploy, and drop-in kits - all agent-tuned. Pair with Claude Code or use standalone.",
5
5
  "bin": {
6
6
  "gipity": "dist/updater/shim.js",