@grifhinz/logics-manager 2.5.1 → 2.5.2

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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![CI](https://github.com/AlexAgo83/logics-manager/actions/workflows/ci.yml/badge.svg)](https://github.com/AlexAgo83/logics-manager/actions/workflows/ci.yml)
4
4
  [![License](https://img.shields.io/github/license/AlexAgo83/logics-manager)](LICENSE)
5
- ![Version](https://img.shields.io/badge/version-v2.5.1-4C8BF5)
5
+ ![Version](https://img.shields.io/badge/version-v2.5.2-4C8BF5)
6
6
  ![VS Code](https://img.shields.io/badge/VS%20Code-1.86.0-007ACC?logo=visualstudiocode&logoColor=white)
7
7
  ![TypeScript](https://img.shields.io/badge/TypeScript-5.3.3-3178C6?logo=typescript&logoColor=white)
8
8
  ![Vitest](https://img.shields.io/badge/Vitest-2.1.8-6E9F18?logo=vitest&logoColor=white)
package/VERSION CHANGED
@@ -1 +1 @@
1
- 2.5.1
1
+ 2.5.2
@@ -107,6 +107,7 @@
107
107
  }
108
108
 
109
109
  .layout--stacked .details {
110
+ width: 100%;
110
111
  min-height: 220px;
111
112
  border-top: none;
112
113
  position: absolute;
@@ -1751,6 +1751,14 @@
1751
1751
  <span class="viewer-git__domain-label">${escapeHtml(label)}${key === "changes" ? gitBadgeHtml("changes") : ""}${key === "history" ? gitBadgeHtml("history") : ""}</span><strong>${escapeHtml(count)}</strong>
1752
1752
  </button>
1753
1753
  `).join("");
1754
+ const renderChangeStats = (entry) => {
1755
+ const additions = Number(entry?.additions);
1756
+ const deletions = Number(entry?.deletions);
1757
+ if (!Number.isFinite(additions) || !Number.isFinite(deletions)) {
1758
+ return "";
1759
+ }
1760
+ return `<span class="viewer-git__file-changes" title="Line changes"><span class="viewer-git__file-additions">+${escapeHtml(additions)}</span><span class="viewer-git__file-deletions">-${escapeHtml(deletions)}</span></span>`;
1761
+ };
1754
1762
  const renderFileSections = (allowedKeys) => groupDefs.filter(([key]) => allowedKeys.includes(key)).map(([key, label]) => {
1755
1763
  const entries = Array.isArray(payload.groups?.[key]) ? payload.groups[key] : [];
1756
1764
  if (!entries.length) {
@@ -1763,6 +1771,7 @@
1763
1771
  <li>
1764
1772
  <button class="viewer-git__file" type="button" data-viewer-git-file="${escapeHtml(entry.path)}" data-viewer-git-cached="${key === "staged" ? "1" : "0"}">
1765
1773
  <span class="viewer-git__file-path">${escapeHtml(entry.from ? `${entry.from} -> ${entry.path}` : entry.path)}</span>
1774
+ ${renderChangeStats(entry)}
1766
1775
  ${entry.logicsType ? `<span class="viewer-git__file-kind">${escapeHtml(entry.logicsType)}</span>` : ""}
1767
1776
  </button>
1768
1777
  </li>
@@ -1852,6 +1861,29 @@
1852
1861
  });
1853
1862
  }
1854
1863
 
1864
+ function gitDiffLineKind(line) {
1865
+ if (line.startsWith("+") && !line.startsWith("+++")) {
1866
+ return "add";
1867
+ }
1868
+ if (line.startsWith("-") && !line.startsWith("---")) {
1869
+ return "delete";
1870
+ }
1871
+ if (line.startsWith("@@")) {
1872
+ return "hunk";
1873
+ }
1874
+ if (line.startsWith("diff --git") || line.startsWith("index ") || line.startsWith("+++") || line.startsWith("---")) {
1875
+ return "meta";
1876
+ }
1877
+ return "context";
1878
+ }
1879
+
1880
+ function renderGitDiffPreview(content) {
1881
+ return String(content)
1882
+ .split("\n")
1883
+ .map((line) => `<span class="viewer-git__diff-line viewer-git__diff-line--${gitDiffLineKind(line)}">${escapeHtml(line || " ")}</span>`)
1884
+ .join("");
1885
+ }
1886
+
1855
1887
  async function loadGitDiff(path, cached, button = null) {
1856
1888
  const diffPanel = document.querySelector("[data-viewer-git-diff]");
1857
1889
  if (!(diffPanel instanceof HTMLElement) || !path) {
@@ -1873,7 +1905,7 @@
1873
1905
  return;
1874
1906
  }
1875
1907
  const content = payload.diff || payload.message || "No diff is available for this file.";
1876
- diffPanel.innerHTML = `<div class="viewer-git__diff-meta">${escapeHtml(payload.path || path)} · ${escapeHtml(payload.mode || "worktree")}${payload.truncated ? " · truncated" : ""}</div><pre><code>${escapeHtml(content)}</code></pre>`;
1908
+ diffPanel.innerHTML = `<div class="viewer-git__diff-meta">${escapeHtml(payload.path || path)} · ${escapeHtml(payload.mode || "worktree")}${payload.truncated ? " · truncated" : ""}</div><pre><code>${renderGitDiffPreview(content)}</code></pre>`;
1877
1909
  }
1878
1910
 
1879
1911
  function applyGitDomain(domain) {
@@ -829,6 +829,23 @@
829
829
  overflow-wrap: anywhere;
830
830
  }
831
831
 
832
+ .viewer-git__file-changes {
833
+ display: inline-flex;
834
+ align-items: center;
835
+ gap: 5px;
836
+ flex: 0 0 auto;
837
+ font-family: var(--vscode-editor-font-family, ui-monospace, SFMono-Regular, Menlo, monospace);
838
+ font-size: 11px;
839
+ }
840
+
841
+ .viewer-git__file-additions {
842
+ color: #7ee787;
843
+ }
844
+
845
+ .viewer-git__file-deletions {
846
+ color: #ffaaa5;
847
+ }
848
+
832
849
  .viewer-git__file-kind {
833
850
  flex: 0 0 auto;
834
851
  padding: 2px 6px;
@@ -871,6 +888,35 @@
871
888
  white-space: pre;
872
889
  }
873
890
 
891
+ .viewer-git__diff-line {
892
+ display: block;
893
+ min-height: 1.35em;
894
+ padding: 0 8px;
895
+ border-left: 3px solid transparent;
896
+ }
897
+
898
+ .viewer-git__diff-line--add {
899
+ border-left-color: #2ea043;
900
+ background: rgba(46, 160, 67, 0.16);
901
+ color: #7ee787;
902
+ }
903
+
904
+ .viewer-git__diff-line--delete {
905
+ border-left-color: #f85149;
906
+ background: rgba(248, 81, 73, 0.16);
907
+ color: #ffaaa5;
908
+ }
909
+
910
+ .viewer-git__diff-line--hunk {
911
+ border-left-color: var(--vscode-textLink-foreground, #4ea1ff);
912
+ background: color-mix(in srgb, var(--vscode-textLink-foreground, #4ea1ff) 14%, transparent);
913
+ color: var(--vscode-textLink-foreground, #4ea1ff);
914
+ }
915
+
916
+ .viewer-git__diff-line--meta {
917
+ color: var(--vscode-descriptionForeground, #aaaaaa);
918
+ }
919
+
874
920
  .viewer-git__commit,
875
921
  .viewer-git__state {
876
922
  margin: 0;
@@ -496,7 +496,38 @@ def _parse_recent_git_commits(output: str) -> list[dict[str, str]]:
496
496
  return commits
497
497
 
498
498
 
499
- def _count_unique_git_status_paths(groups: dict[str, list[dict[str, str]]]) -> int:
499
+ def _parse_git_numstat(output: str) -> dict[str, dict[str, int]]:
500
+ stats: dict[str, dict[str, int]] = {}
501
+ for line in output.splitlines():
502
+ parts = line.split("\t")
503
+ if len(parts) < 3:
504
+ continue
505
+ raw_additions, raw_deletions, raw_path = parts[:3]
506
+ try:
507
+ additions = int(raw_additions)
508
+ deletions = int(raw_deletions)
509
+ except ValueError:
510
+ continue
511
+ path = raw_path.strip()
512
+ if " => " in path:
513
+ path = path.split(" => ", 1)[1].strip("{}")
514
+ if path:
515
+ stats[path] = {"additions": additions, "deletions": deletions}
516
+ return stats
517
+
518
+
519
+ def _attach_git_change_stats(groups: dict[str, list[dict[str, Any]]], staged_stats: dict[str, dict[str, int]], worktree_stats: dict[str, dict[str, int]]) -> None:
520
+ for key, entries in groups.items():
521
+ stats_source = staged_stats if key == "staged" else worktree_stats
522
+ for entry in entries:
523
+ path = str(entry.get("path", ""))
524
+ stats = stats_source.get(path) or staged_stats.get(path) or worktree_stats.get(path)
525
+ if stats:
526
+ entry["additions"] = stats["additions"]
527
+ entry["deletions"] = stats["deletions"]
528
+
529
+
530
+ def _count_unique_git_status_paths(groups: dict[str, list[dict[str, Any]]]) -> int:
500
531
  paths: set[str] = set()
501
532
  for entries in groups.values():
502
533
  for entry in entries:
@@ -543,6 +574,8 @@ def git_status_payload(repo_root: Path, *, runner: Any | None = None, which: Any
543
574
 
544
575
  try:
545
576
  status = _run_read_only_git(repo_root, ["status", "--porcelain=v1", "-b"], runner=runner)
577
+ staged_numstat = _run_read_only_git(repo_root, ["diff", "--no-ext-diff", "--numstat", "--cached"], runner=runner)
578
+ worktree_numstat = _run_read_only_git(repo_root, ["diff", "--no-ext-diff", "--numstat"], runner=runner)
546
579
  commit = _run_read_only_git(repo_root, ["log", "-1", "--pretty=format:%h %s"], runner=runner)
547
580
  recent_commits = _run_read_only_git(
548
581
  repo_root,
@@ -558,12 +591,18 @@ def git_status_payload(repo_root: Path, *, runner: Any | None = None, which: Any
558
591
 
559
592
  lines = status.stdout.splitlines()
560
593
  branch_info = _parse_git_branch_line(lines[0]) if lines else {"branch": "HEAD", "tracking": "", "ahead": 0, "behind": 0}
561
- groups: dict[str, list[dict[str, str]]] = {key: [] for key in ("staged", "modified", "deleted", "renamed", "untracked")}
594
+ groups: dict[str, list[dict[str, Any]]] = {key: [] for key in ("staged", "modified", "deleted", "renamed", "untracked")}
562
595
  for line in lines[1:]:
563
596
  classified = _classify_porcelain_entry(line)
564
597
  if classified:
565
598
  group, entry = classified
566
599
  groups[group].append(entry)
600
+ if staged_numstat.returncode == 0 or worktree_numstat.returncode == 0:
601
+ _attach_git_change_stats(
602
+ groups,
603
+ _parse_git_numstat(staged_numstat.stdout if staged_numstat.returncode == 0 else ""),
604
+ _parse_git_numstat(worktree_numstat.stdout if worktree_numstat.returncode == 0 else ""),
605
+ )
567
606
  counts = {key: len(value) for key, value in groups.items()}
568
607
  uncommitted_files = _count_unique_git_status_paths(groups)
569
608
  dirty = any(counts.values())
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@grifhinz/logics-manager",
3
3
  "displayName": "Logics Orchestrator",
4
4
  "description": "Visual orchestration for Logics workflows inside VS Code.",
5
- "version": "2.5.1",
5
+ "version": "2.5.2",
6
6
  "publisher": "cdx-logics",
7
7
  "icon": "clients/shared-web/media/icon.png",
8
8
  "repository": {
package/pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "logics-manager"
7
- version = "2.5.1"
7
+ version = "2.5.2"
8
8
  description = "Canonical Logics CLI"
9
9
  requires-python = ">=3.10"
10
10