shraga 0.1.127 → 0.1.129

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.
@@ -13,8 +13,8 @@
13
13
  <link rel="preconnect" href="https://fonts.googleapis.com" />
14
14
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
15
15
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet" />
16
- <script type="module" crossorigin src="/assets/index-DRTvNKXl.js"></script>
17
- <link rel="stylesheet" crossorigin href="/assets/index-_XEpjgJO.css">
16
+ <script type="module" crossorigin src="/assets/index-kSoIKs9H.js"></script>
17
+ <link rel="stylesheet" crossorigin href="/assets/index-BLAQpfJ9.css">
18
18
  </head>
19
19
  <body>
20
20
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shraga",
3
- "version": "0.1.127",
3
+ "version": "0.1.129",
4
4
  "description": "The teammate you delegate coding to — a self-hostable, multi-user AI coding agent web UI (Claude Code, with a pluggable engine seam).",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -54,35 +54,41 @@ export function ClaudeAccountSection({ getToken }: { getToken: () => Promise<str
54
54
  ? !accounts?.me?.connected || !!accounts.me.useShared
55
55
  : !!accounts?.me?.connected && !accounts.me.useShared;
56
56
 
57
- const row = (target: Target, title: string, s: AccountStatus | null, canManage = true) => (
58
- <div className="flex items-center justify-between gap-2 flex-wrap">
59
- <div className="text-sm min-w-0">
60
- <div className="font-medium flex items-center gap-2">
61
- {title}
62
- {active(target) && <span className="text-[10px] uppercase tracking-wide text-emerald-500">active</span>}
63
- <UsageMetric usage={accounts?.usage?.[target] ?? null} />
64
- </div>
65
- <div className="text-xs text-muted-foreground truncate">
66
- {s?.connected ? `${s.account ?? 'Connected'}${s.subscriptionType ? ` · ${s.subscriptionType}` : ''}` : target === 'me' ? 'Not connected — using the shared subscription' : canManage ? 'Not connected' : ''}
57
+ const row = (target: Target, title: string, s: AccountStatus | null, canManage = true) => {
58
+ const usage = accounts?.usage?.[target] ?? null;
59
+ const identity = s?.connected ? [s.account ?? 'Connected', s.subscriptionType].filter(Boolean).join(' · ')
60
+ : target === 'me' ? 'Not connected' : canManage ? 'Not connected' : null;
61
+ return (
62
+ <div className="flex items-center justify-between gap-3">
63
+ <div className="min-w-0 space-y-0.5">
64
+ <div className="flex items-center gap-2 text-sm font-medium">
65
+ {title}
66
+ {active(target) && <span className="rounded-full bg-emerald-500/15 px-1.5 py-px text-[10px] font-medium text-emerald-500">Active</span>}
67
+ </div>
68
+ <div className="flex items-center gap-1.5 text-xs text-muted-foreground min-w-0">
69
+ {identity && <span className="truncate">{identity}</span>}
70
+ {identity && usage && <span aria-hidden>·</span>}
71
+ <UsageMetric usage={usage} compact />
72
+ </div>
67
73
  </div>
74
+ {canManage && (
75
+ <div className="flex shrink-0 gap-2">
76
+ {target === 'me' && s?.connected && (
77
+ <>
78
+ <Button size="sm" variant="outline" disabled={busy} onClick={() => useShared(!s.useShared)}>{s.useShared ? 'Use mine' : 'Use shared'}</Button>
79
+ <Button size="sm" variant="outline" disabled={busy} onClick={() => disconnect(target)}>Sign out</Button>
80
+ </>
81
+ )}
82
+ <Button size="sm" variant="outline" disabled={busy} onClick={() => connect(target)}>{s?.connected ? 'Replace' : 'Connect'}</Button>
83
+ </div>
84
+ )}
68
85
  </div>
69
- {canManage && (
70
- <div className="flex gap-2">
71
- <Button size="sm" variant="outline" disabled={busy} onClick={() => connect(target)}>{s?.connected ? 'Replace' : 'Connect'}</Button>
72
- {target === 'me' && s?.connected && (
73
- <>
74
- <Button size="sm" variant="ghost" disabled={busy} onClick={() => useShared(!s.useShared)}>{s.useShared ? 'Use mine' : 'Use shared'}</Button>
75
- <Button size="sm" variant="ghost" disabled={busy} onClick={() => disconnect(target)}>Sign out</Button>
76
- </>
77
- )}
78
- </div>
79
- )}
80
- </div>
81
- );
86
+ );
87
+ };
82
88
 
83
89
  if (!accounts) return error ? <p className="text-xs text-destructive">{error}</p> : null;
84
90
  return (
85
- <div className="space-y-3">
91
+ <div className="space-y-4">
86
92
  <label className="text-sm font-medium block">Claude subscription</label>
87
93
  {accounts.me ? row('me', 'Your subscription', accounts.me) : (
88
94
  <p className="text-xs text-muted-foreground">Personal subscription unavailable: you are not a contact on this agent.</p>
@@ -136,7 +136,7 @@ function ClaudeUsageMetric({ getToken }: { getToken: () => Promise<string | null
136
136
 
137
137
  /** Pure render — null usage (204, or any failure) renders NOTHING. Split from the fetching shell so
138
138
  * the gate and the labelling are testable without a network or a DOM. */
139
- export function UsageMetric({ usage }: { usage: Usage | null }) {
139
+ export function UsageMetric({ usage, compact }: { usage: Usage | null; /** Inline text trigger (settings rows) instead of the strip gauge. */ compact?: boolean }) {
140
140
  const top = usage && binding(usage.limits);
141
141
  const [state, setState] = useState<CardState>(CLOSED);
142
142
  const timer = useRef<ReturnType<typeof setTimeout> | null>(null);
@@ -169,7 +169,9 @@ export function UsageMetric({ usage }: { usage: Usage | null }) {
169
169
  onPointerEnter={e => send({ type: 'pointerenter', pointerType: e.pointerType }, HOVER_OPEN_MS)}
170
170
  onPointerLeave={e => send({ type: 'pointerleave', pointerType: e.pointerType }, HOVER_CLOSE_MS)}
171
171
  >
172
- <Metric label="usage" value={top.percent} severity={top.severity} />
172
+ {compact
173
+ ? <span className={cn('tabular-nums', level(top.percent, top.severity))}>{top.percent}% used</span>
174
+ : <Metric label="usage" value={top.percent} severity={top.severity} />}
173
175
  </button>
174
176
  </PopoverTrigger>
175
177
  <PopoverContent
@@ -85,6 +85,13 @@ export function isChurnPath(file: string): boolean {
85
85
  || /\.bak(-|\.|$)/.test(file);
86
86
  }
87
87
 
88
+ /** Authored documents (HTML reports, dashboards, styles, scripts) are REWRITTEN wholesale by design —
89
+ * a redesign that drops 87 lines is an edit, not data loss (2026-09-17: two trial-journey report
90
+ * copies blocked every flush). The shrink guard protects records like contacts.json, not these. */
91
+ export function isAuthoredDocPath(file: string): boolean {
92
+ return /\.(html?|css|m?[jt]sx?|svg)$/i.test(file);
93
+ }
94
+
88
95
  export class DataSyncOptions {
89
96
  repoUrl = process.env.DATA_SYNC_REPO || '';
90
97
  branch = process.env.DATA_SYNC_BRANCH || 'main';
@@ -294,7 +301,7 @@ export class DataSync {
294
301
  const [addRaw, delRaw, file] = line.split('\t');
295
302
  if (addRaw === '-' || delRaw === '-' || !file) continue; // binary
296
303
  const net = (parseInt(delRaw, 10) || 0) - (parseInt(addRaw, 10) || 0);
297
- if (net > shrinkThreshold && !isChurnPath(file)) shrunk.push(`• ${file} (−${net} net lines)`);
304
+ if (net > shrinkThreshold && !isChurnPath(file) && !isAuthoredDocPath(file)) shrunk.push(`• ${file} (−${net} net lines)`);
298
305
  }
299
306
  if (shrunk.length) {
300
307
  console.error(`${TAG} 🚫 BLOCKED large content shrink (${context}): ${shrunk.length} file(s) — net-removal threshold is ${shrinkThreshold}`);