@doriandev/devcc 0.1.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.
Files changed (284) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +659 -0
  3. package/bin/devcc.mjs +66 -0
  4. package/dist/devcc/app/App.d.ts +178 -0
  5. package/dist/devcc/app/App.d.ts.map +1 -0
  6. package/dist/devcc/app/App.js +1255 -0
  7. package/dist/devcc/app/App.js.map +1 -0
  8. package/dist/devcc/app/builtinCommands.d.ts +17 -0
  9. package/dist/devcc/app/builtinCommands.d.ts.map +1 -0
  10. package/dist/devcc/app/builtinCommands.js +389 -0
  11. package/dist/devcc/app/builtinCommands.js.map +1 -0
  12. package/dist/devcc/app/keymap.d.ts +21 -0
  13. package/dist/devcc/app/keymap.d.ts.map +1 -0
  14. package/dist/devcc/app/keymap.js +162 -0
  15. package/dist/devcc/app/keymap.js.map +1 -0
  16. package/dist/devcc/app/theme.d.ts +49 -0
  17. package/dist/devcc/app/theme.d.ts.map +1 -0
  18. package/dist/devcc/app/theme.js +68 -0
  19. package/dist/devcc/app/theme.js.map +1 -0
  20. package/dist/devcc/cli.d.ts +3 -0
  21. package/dist/devcc/cli.d.ts.map +1 -0
  22. package/dist/devcc/cli.js +113 -0
  23. package/dist/devcc/cli.js.map +1 -0
  24. package/dist/devcc/components/CommandPalette.d.ts +26 -0
  25. package/dist/devcc/components/CommandPalette.d.ts.map +1 -0
  26. package/dist/devcc/components/CommandPalette.js +113 -0
  27. package/dist/devcc/components/CommandPalette.js.map +1 -0
  28. package/dist/devcc/components/ConfirmDialog.d.ts +31 -0
  29. package/dist/devcc/components/ConfirmDialog.d.ts.map +1 -0
  30. package/dist/devcc/components/ConfirmDialog.js +147 -0
  31. package/dist/devcc/components/ConfirmDialog.js.map +1 -0
  32. package/dist/devcc/components/Footer.d.ts +22 -0
  33. package/dist/devcc/components/Footer.d.ts.map +1 -0
  34. package/dist/devcc/components/Footer.js +72 -0
  35. package/dist/devcc/components/Footer.js.map +1 -0
  36. package/dist/devcc/components/Header.d.ts +12 -0
  37. package/dist/devcc/components/Header.d.ts.map +1 -0
  38. package/dist/devcc/components/Header.js +84 -0
  39. package/dist/devcc/components/Header.js.map +1 -0
  40. package/dist/devcc/components/HelpOverlay.d.ts +18 -0
  41. package/dist/devcc/components/HelpOverlay.d.ts.map +1 -0
  42. package/dist/devcc/components/HelpOverlay.js +48 -0
  43. package/dist/devcc/components/HelpOverlay.js.map +1 -0
  44. package/dist/devcc/components/Overlay.d.ts +31 -0
  45. package/dist/devcc/components/Overlay.d.ts.map +1 -0
  46. package/dist/devcc/components/Overlay.js +60 -0
  47. package/dist/devcc/components/Overlay.js.map +1 -0
  48. package/dist/devcc/components/ProjectPicker.d.ts +26 -0
  49. package/dist/devcc/components/ProjectPicker.d.ts.map +1 -0
  50. package/dist/devcc/components/ProjectPicker.js +114 -0
  51. package/dist/devcc/components/ProjectPicker.js.map +1 -0
  52. package/dist/devcc/components/Sidebar.d.ts +42 -0
  53. package/dist/devcc/components/Sidebar.d.ts.map +1 -0
  54. package/dist/devcc/components/Sidebar.js +127 -0
  55. package/dist/devcc/components/Sidebar.js.map +1 -0
  56. package/dist/devcc/components/StatusBadge.d.ts +16 -0
  57. package/dist/devcc/components/StatusBadge.d.ts.map +1 -0
  58. package/dist/devcc/components/StatusBadge.js +30 -0
  59. package/dist/devcc/components/StatusBadge.js.map +1 -0
  60. package/dist/devcc/components/primitives.d.ts +62 -0
  61. package/dist/devcc/components/primitives.d.ts.map +1 -0
  62. package/dist/devcc/components/primitives.js +169 -0
  63. package/dist/devcc/components/primitives.js.map +1 -0
  64. package/dist/devcc/components/styled.d.ts +16 -0
  65. package/dist/devcc/components/styled.d.ts.map +1 -0
  66. package/dist/devcc/components/styled.js +35 -0
  67. package/dist/devcc/components/styled.js.map +1 -0
  68. package/dist/devcc/core/commands.d.ts +89 -0
  69. package/dist/devcc/core/commands.d.ts.map +1 -0
  70. package/dist/devcc/core/commands.js +68 -0
  71. package/dist/devcc/core/commands.js.map +1 -0
  72. package/dist/devcc/core/config.d.ts +81 -0
  73. package/dist/devcc/core/config.d.ts.map +1 -0
  74. package/dist/devcc/core/config.js +313 -0
  75. package/dist/devcc/core/config.js.map +1 -0
  76. package/dist/devcc/core/events.d.ts +21 -0
  77. package/dist/devcc/core/events.d.ts.map +1 -0
  78. package/dist/devcc/core/events.js +27 -0
  79. package/dist/devcc/core/events.js.map +1 -0
  80. package/dist/devcc/core/state.d.ts +104 -0
  81. package/dist/devcc/core/state.d.ts.map +1 -0
  82. package/dist/devcc/core/state.js +139 -0
  83. package/dist/devcc/core/state.js.map +1 -0
  84. package/dist/devcc/deps/DependencyService.d.ts +50 -0
  85. package/dist/devcc/deps/DependencyService.d.ts.map +1 -0
  86. package/dist/devcc/deps/DependencyService.js +109 -0
  87. package/dist/devcc/deps/DependencyService.js.map +1 -0
  88. package/dist/devcc/deps/parse.d.ts +49 -0
  89. package/dist/devcc/deps/parse.d.ts.map +1 -0
  90. package/dist/devcc/deps/parse.js +158 -0
  91. package/dist/devcc/deps/parse.js.map +1 -0
  92. package/dist/devcc/git/GitService.d.ts +60 -0
  93. package/dist/devcc/git/GitService.d.ts.map +1 -0
  94. package/dist/devcc/git/GitService.js +160 -0
  95. package/dist/devcc/git/GitService.js.map +1 -0
  96. package/dist/devcc/git/parse.d.ts +57 -0
  97. package/dist/devcc/git/parse.d.ts.map +1 -0
  98. package/dist/devcc/git/parse.js +174 -0
  99. package/dist/devcc/git/parse.js.map +1 -0
  100. package/dist/devcc/index.d.ts +37 -0
  101. package/dist/devcc/index.d.ts.map +1 -0
  102. package/dist/devcc/index.js +36 -0
  103. package/dist/devcc/index.js.map +1 -0
  104. package/dist/devcc/logs/LogBuffer.d.ts +86 -0
  105. package/dist/devcc/logs/LogBuffer.d.ts.map +1 -0
  106. package/dist/devcc/logs/LogBuffer.js +200 -0
  107. package/dist/devcc/logs/LogBuffer.js.map +1 -0
  108. package/dist/devcc/logs/merge.d.ts +36 -0
  109. package/dist/devcc/logs/merge.d.ts.map +1 -0
  110. package/dist/devcc/logs/merge.js +71 -0
  111. package/dist/devcc/logs/merge.js.map +1 -0
  112. package/dist/devcc/processes/ManagedProcess.d.ts +129 -0
  113. package/dist/devcc/processes/ManagedProcess.d.ts.map +1 -0
  114. package/dist/devcc/processes/ManagedProcess.js +80 -0
  115. package/dist/devcc/processes/ManagedProcess.js.map +1 -0
  116. package/dist/devcc/processes/ProcessManager.d.ts +112 -0
  117. package/dist/devcc/processes/ProcessManager.d.ts.map +1 -0
  118. package/dist/devcc/processes/ProcessManager.js +525 -0
  119. package/dist/devcc/processes/ProcessManager.js.map +1 -0
  120. package/dist/devcc/processes/graph.d.ts +35 -0
  121. package/dist/devcc/processes/graph.d.ts.map +1 -0
  122. package/dist/devcc/processes/graph.js +68 -0
  123. package/dist/devcc/processes/graph.js.map +1 -0
  124. package/dist/devcc/projects/ProjectRegistry.d.ts +52 -0
  125. package/dist/devcc/projects/ProjectRegistry.d.ts.map +1 -0
  126. package/dist/devcc/projects/ProjectRegistry.js +177 -0
  127. package/dist/devcc/projects/ProjectRegistry.js.map +1 -0
  128. package/dist/devcc/services/ServiceManager.d.ts +48 -0
  129. package/dist/devcc/services/ServiceManager.d.ts.map +1 -0
  130. package/dist/devcc/services/ServiceManager.js +146 -0
  131. package/dist/devcc/services/ServiceManager.js.map +1 -0
  132. package/dist/devcc/services/docker.d.ts +37 -0
  133. package/dist/devcc/services/docker.d.ts.map +1 -0
  134. package/dist/devcc/services/docker.js +179 -0
  135. package/dist/devcc/services/docker.js.map +1 -0
  136. package/dist/devcc/services/node.d.ts +40 -0
  137. package/dist/devcc/services/node.d.ts.map +1 -0
  138. package/dist/devcc/services/node.js +107 -0
  139. package/dist/devcc/services/node.js.map +1 -0
  140. package/dist/devcc/services/ollama.d.ts +27 -0
  141. package/dist/devcc/services/ollama.d.ts.map +1 -0
  142. package/dist/devcc/services/ollama.js +66 -0
  143. package/dist/devcc/services/ollama.js.map +1 -0
  144. package/dist/devcc/services/postgres.d.ts +30 -0
  145. package/dist/devcc/services/postgres.d.ts.map +1 -0
  146. package/dist/devcc/services/postgres.js +47 -0
  147. package/dist/devcc/services/postgres.js.map +1 -0
  148. package/dist/devcc/services/redis.d.ts +20 -0
  149. package/dist/devcc/services/redis.d.ts.map +1 -0
  150. package/dist/devcc/services/redis.js +39 -0
  151. package/dist/devcc/services/redis.js.map +1 -0
  152. package/dist/devcc/services/types.d.ts +51 -0
  153. package/dist/devcc/services/types.d.ts.map +1 -0
  154. package/dist/devcc/services/types.js +10 -0
  155. package/dist/devcc/services/types.js.map +1 -0
  156. package/dist/devcc/system/SystemMonitor.d.ts +87 -0
  157. package/dist/devcc/system/SystemMonitor.d.ts.map +1 -0
  158. package/dist/devcc/system/SystemMonitor.js +142 -0
  159. package/dist/devcc/system/SystemMonitor.js.map +1 -0
  160. package/dist/devcc/utils/errors.d.ts +31 -0
  161. package/dist/devcc/utils/errors.d.ts.map +1 -0
  162. package/dist/devcc/utils/errors.js +52 -0
  163. package/dist/devcc/utils/errors.js.map +1 -0
  164. package/dist/devcc/utils/exec.d.ts +41 -0
  165. package/dist/devcc/utils/exec.d.ts.map +1 -0
  166. package/dist/devcc/utils/exec.js +112 -0
  167. package/dist/devcc/utils/exec.js.map +1 -0
  168. package/dist/devcc/utils/format.d.ts +18 -0
  169. package/dist/devcc/utils/format.d.ts.map +1 -0
  170. package/dist/devcc/utils/format.js +85 -0
  171. package/dist/devcc/utils/format.js.map +1 -0
  172. package/dist/devcc/utils/fuzzy.d.ts +12 -0
  173. package/dist/devcc/utils/fuzzy.d.ts.map +1 -0
  174. package/dist/devcc/utils/fuzzy.js +20 -0
  175. package/dist/devcc/utils/fuzzy.js.map +1 -0
  176. package/dist/devcc/utils/logger.d.ts +41 -0
  177. package/dist/devcc/utils/logger.d.ts.map +1 -0
  178. package/dist/devcc/utils/logger.js +117 -0
  179. package/dist/devcc/utils/logger.js.map +1 -0
  180. package/dist/devcc/utils/packageManager.d.ts +39 -0
  181. package/dist/devcc/utils/packageManager.d.ts.map +1 -0
  182. package/dist/devcc/utils/packageManager.js +85 -0
  183. package/dist/devcc/utils/packageManager.js.map +1 -0
  184. package/dist/devcc/utils/paths.d.ts +12 -0
  185. package/dist/devcc/utils/paths.d.ts.map +1 -0
  186. package/dist/devcc/utils/paths.js +39 -0
  187. package/dist/devcc/utils/paths.js.map +1 -0
  188. package/dist/devcc/views/DependenciesView.d.ts +34 -0
  189. package/dist/devcc/views/DependenciesView.d.ts.map +1 -0
  190. package/dist/devcc/views/DependenciesView.js +170 -0
  191. package/dist/devcc/views/DependenciesView.js.map +1 -0
  192. package/dist/devcc/views/GitView.d.ts +29 -0
  193. package/dist/devcc/views/GitView.d.ts.map +1 -0
  194. package/dist/devcc/views/GitView.js +226 -0
  195. package/dist/devcc/views/GitView.js.map +1 -0
  196. package/dist/devcc/views/LogsView.d.ts +39 -0
  197. package/dist/devcc/views/LogsView.d.ts.map +1 -0
  198. package/dist/devcc/views/LogsView.js +249 -0
  199. package/dist/devcc/views/LogsView.js.map +1 -0
  200. package/dist/devcc/views/OverviewView.d.ts +16 -0
  201. package/dist/devcc/views/OverviewView.d.ts.map +1 -0
  202. package/dist/devcc/views/OverviewView.js +135 -0
  203. package/dist/devcc/views/OverviewView.js.map +1 -0
  204. package/dist/devcc/views/ProcessesView.d.ts +26 -0
  205. package/dist/devcc/views/ProcessesView.d.ts.map +1 -0
  206. package/dist/devcc/views/ProcessesView.js +161 -0
  207. package/dist/devcc/views/ProcessesView.js.map +1 -0
  208. package/dist/devcc/views/ScriptsView.d.ts +30 -0
  209. package/dist/devcc/views/ScriptsView.d.ts.map +1 -0
  210. package/dist/devcc/views/ScriptsView.js +168 -0
  211. package/dist/devcc/views/ScriptsView.js.map +1 -0
  212. package/dist/devcc/views/ServicesView.d.ts +28 -0
  213. package/dist/devcc/views/ServicesView.d.ts.map +1 -0
  214. package/dist/devcc/views/ServicesView.js +153 -0
  215. package/dist/devcc/views/ServicesView.js.map +1 -0
  216. package/dist/devcc/views/SettingsView.d.ts +20 -0
  217. package/dist/devcc/views/SettingsView.d.ts.map +1 -0
  218. package/dist/devcc/views/SettingsView.js +114 -0
  219. package/dist/devcc/views/SettingsView.js.map +1 -0
  220. package/dist/devcc/views/SystemView.d.ts +13 -0
  221. package/dist/devcc/views/SystemView.d.ts.map +1 -0
  222. package/dist/devcc/views/SystemView.js +82 -0
  223. package/dist/devcc/views/SystemView.js.map +1 -0
  224. package/dist/devcc/views/View.d.ts +35 -0
  225. package/dist/devcc/views/View.d.ts.map +1 -0
  226. package/dist/devcc/views/View.js +42 -0
  227. package/dist/devcc/views/View.js.map +1 -0
  228. package/package.json +79 -0
  229. package/src/devcc/app/App.ts +1463 -0
  230. package/src/devcc/app/builtinCommands.ts +429 -0
  231. package/src/devcc/app/keymap.ts +167 -0
  232. package/src/devcc/app/theme.ts +83 -0
  233. package/src/devcc/cli.ts +122 -0
  234. package/src/devcc/components/CommandPalette.ts +136 -0
  235. package/src/devcc/components/ConfirmDialog.ts +174 -0
  236. package/src/devcc/components/Footer.ts +85 -0
  237. package/src/devcc/components/Header.ts +93 -0
  238. package/src/devcc/components/HelpOverlay.ts +62 -0
  239. package/src/devcc/components/Overlay.ts +91 -0
  240. package/src/devcc/components/ProjectPicker.ts +138 -0
  241. package/src/devcc/components/Sidebar.ts +163 -0
  242. package/src/devcc/components/StatusBadge.ts +36 -0
  243. package/src/devcc/components/primitives.ts +213 -0
  244. package/src/devcc/components/styled.ts +44 -0
  245. package/src/devcc/core/commands.ts +140 -0
  246. package/src/devcc/core/config.ts +405 -0
  247. package/src/devcc/core/events.ts +41 -0
  248. package/src/devcc/core/state.ts +236 -0
  249. package/src/devcc/deps/DependencyService.ts +152 -0
  250. package/src/devcc/deps/parse.ts +210 -0
  251. package/src/devcc/git/GitService.ts +205 -0
  252. package/src/devcc/git/parse.ts +203 -0
  253. package/src/devcc/index.ts +115 -0
  254. package/src/devcc/logs/LogBuffer.ts +237 -0
  255. package/src/devcc/logs/merge.ts +87 -0
  256. package/src/devcc/processes/ManagedProcess.ts +195 -0
  257. package/src/devcc/processes/ProcessManager.ts +625 -0
  258. package/src/devcc/processes/graph.ts +98 -0
  259. package/src/devcc/projects/ProjectRegistry.ts +219 -0
  260. package/src/devcc/services/ServiceManager.ts +180 -0
  261. package/src/devcc/services/docker.ts +220 -0
  262. package/src/devcc/services/node.ts +137 -0
  263. package/src/devcc/services/ollama.ts +80 -0
  264. package/src/devcc/services/postgres.ts +57 -0
  265. package/src/devcc/services/redis.ts +47 -0
  266. package/src/devcc/services/types.ts +59 -0
  267. package/src/devcc/system/SystemMonitor.ts +207 -0
  268. package/src/devcc/utils/errors.ts +64 -0
  269. package/src/devcc/utils/exec.ts +165 -0
  270. package/src/devcc/utils/format.ts +83 -0
  271. package/src/devcc/utils/fuzzy.ts +44 -0
  272. package/src/devcc/utils/logger.ts +140 -0
  273. package/src/devcc/utils/packageManager.ts +112 -0
  274. package/src/devcc/utils/paths.ts +39 -0
  275. package/src/devcc/views/DependenciesView.ts +206 -0
  276. package/src/devcc/views/GitView.ts +259 -0
  277. package/src/devcc/views/LogsView.ts +300 -0
  278. package/src/devcc/views/OverviewView.ts +187 -0
  279. package/src/devcc/views/ProcessesView.ts +177 -0
  280. package/src/devcc/views/ScriptsView.ts +187 -0
  281. package/src/devcc/views/ServicesView.ts +188 -0
  282. package/src/devcc/views/SettingsView.ts +146 -0
  283. package/src/devcc/views/SystemView.ts +110 -0
  284. package/src/devcc/views/View.ts +63 -0
@@ -0,0 +1,158 @@
1
+ /** Managers whose `outdated` command can emit machine-readable output. */
2
+ export const JSON_CAPABLE_MANAGERS = ["pnpm", "npm", "yarn"];
3
+ export function supportsOutdatedJson(manager) {
4
+ return JSON_CAPABLE_MANAGERS.includes(manager);
5
+ }
6
+ /** The argv that produces JSON `outdated` output for each manager. */
7
+ export function outdatedArgs(manager) {
8
+ switch (manager) {
9
+ case "pnpm":
10
+ return ["outdated", "--format", "json"];
11
+ case "npm":
12
+ return ["outdated", "--json", "--long"];
13
+ case "yarn":
14
+ return ["outdated", "--json"];
15
+ case "bun":
16
+ return ["outdated"];
17
+ }
18
+ }
19
+ /** Strip range operators and build metadata: `^1.2.3-beta.1` -> `[1, 2, 3]`. */
20
+ export function parseVersion(version) {
21
+ const match = /(\d+)\.(\d+)\.(\d+)/u.exec(version.trim());
22
+ if (!match)
23
+ return null;
24
+ return [Number(match[1]), Number(match[2]), Number(match[3])];
25
+ }
26
+ /**
27
+ * Classify the gap between two versions. `unknown` when either side is not a
28
+ * plain semver triple (git refs, `latest`, workspace protocols).
29
+ */
30
+ export function severityBetween(current, latest) {
31
+ const from = parseVersion(current);
32
+ const to = parseVersion(latest);
33
+ if (!from || !to)
34
+ return "unknown";
35
+ if (to[0] !== from[0])
36
+ return "major";
37
+ if (to[1] !== from[1])
38
+ return "minor";
39
+ if (to[2] !== from[2])
40
+ return "patch";
41
+ return "unknown";
42
+ }
43
+ function normaliseKind(value) {
44
+ switch (typeof value === "string" ? value.toLowerCase() : "") {
45
+ case "devdependencies":
46
+ case "dev":
47
+ return "devDependencies";
48
+ case "peerdependencies":
49
+ case "peer":
50
+ return "peerDependencies";
51
+ case "optionaldependencies":
52
+ case "optional":
53
+ return "optionalDependencies";
54
+ default:
55
+ return "dependencies";
56
+ }
57
+ }
58
+ function asRecord(value) {
59
+ return typeof value === "object" && value !== null && !Array.isArray(value)
60
+ ? value
61
+ : undefined;
62
+ }
63
+ function asString(value) {
64
+ return typeof value === "string" && value.length > 0 ? value : undefined;
65
+ }
66
+ function buildEntry(name, current, wanted, latest, kind, deprecated) {
67
+ return {
68
+ name,
69
+ current,
70
+ wanted,
71
+ latest,
72
+ kind,
73
+ severity: severityBetween(current, latest),
74
+ onlyLatest: current === wanted && wanted !== latest,
75
+ deprecated,
76
+ };
77
+ }
78
+ /**
79
+ * pnpm (`--format json`) and npm (`--json`) both emit an object keyed by package
80
+ * name; only the field names around it differ slightly.
81
+ */
82
+ export function parseNpmStyleOutdated(json) {
83
+ const root = asRecord(json);
84
+ if (!root)
85
+ return [];
86
+ const packages = [];
87
+ for (const [name, raw] of Object.entries(root)) {
88
+ // npm --json can produce an array when a package is present at several paths.
89
+ const entry = asRecord(Array.isArray(raw) ? raw[0] : raw);
90
+ if (!entry)
91
+ continue;
92
+ const current = asString(entry.current);
93
+ const latest = asString(entry.latest);
94
+ if (!latest)
95
+ continue;
96
+ packages.push(buildEntry(name, current ?? "-", asString(entry.wanted) ?? current ?? "-", latest, normaliseKind(entry.dependencyType ?? entry.type), entry.isDeprecated === true));
97
+ }
98
+ return packages;
99
+ }
100
+ /** yarn classic emits newline-delimited JSON with a `table` payload. */
101
+ export function parseYarnOutdated(output) {
102
+ for (const line of output.split("\n")) {
103
+ if (line.trim() === "")
104
+ continue;
105
+ let parsed;
106
+ try {
107
+ parsed = JSON.parse(line);
108
+ }
109
+ catch {
110
+ continue;
111
+ }
112
+ const record = asRecord(parsed);
113
+ if (record?.type !== "table")
114
+ continue;
115
+ const body = asRecord(record.data)?.body;
116
+ if (!Array.isArray(body))
117
+ continue;
118
+ return body
119
+ .filter((row) => Array.isArray(row))
120
+ .map((row) => {
121
+ const [name, current, wanted, latest, kind] = row.map((cell) => typeof cell === "string" ? cell : "");
122
+ return buildEntry(name ?? "", current ?? "-", wanted ?? "-", latest ?? "-", normaliseKind(kind));
123
+ })
124
+ .filter((entry) => entry.name !== "");
125
+ }
126
+ return [];
127
+ }
128
+ /** Dispatch to the right parser for the manager that produced `output`. */
129
+ export function parseOutdated(manager, output) {
130
+ const trimmed = output.trim();
131
+ if (trimmed === "")
132
+ return [];
133
+ if (manager === "yarn")
134
+ return parseYarnOutdated(trimmed);
135
+ try {
136
+ return parseNpmStyleOutdated(JSON.parse(trimmed));
137
+ }
138
+ catch {
139
+ return [];
140
+ }
141
+ }
142
+ const SEVERITY_ORDER = { major: 0, minor: 1, patch: 2, unknown: 3 };
143
+ /** Most-significant updates first, then alphabetically. */
144
+ export function sortOutdated(packages) {
145
+ return [...packages].sort((a, b) => {
146
+ const bySeverity = SEVERITY_ORDER[a.severity] - SEVERITY_ORDER[b.severity];
147
+ return bySeverity !== 0 ? bySeverity : a.name.localeCompare(b.name);
148
+ });
149
+ }
150
+ export function summariseOutdated(packages) {
151
+ return {
152
+ total: packages.length,
153
+ major: packages.filter((entry) => entry.severity === "major").length,
154
+ minor: packages.filter((entry) => entry.severity === "minor").length,
155
+ patch: packages.filter((entry) => entry.severity === "patch").length,
156
+ };
157
+ }
158
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../../src/devcc/deps/parse.ts"],"names":[],"mappings":"AAsBA,0EAA0E;AAC1E,MAAM,CAAC,MAAM,qBAAqB,GAA8B,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAA;AAEvF,MAAM,UAAU,oBAAoB,CAAC,OAAuB;IAC1D,OAAO,qBAAqB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;AAChD,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,YAAY,CAAC,OAAuB;IAClD,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,MAAM;YACT,OAAO,CAAC,UAAU,EAAE,UAAU,EAAE,MAAM,CAAC,CAAA;QACzC,KAAK,KAAK;YACR,OAAO,CAAC,UAAU,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;QACzC,KAAK,MAAM;YACT,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;QAC/B,KAAK,KAAK;YACR,OAAO,CAAC,UAAU,CAAC,CAAA;IACvB,CAAC;AACH,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,MAAM,KAAK,GAAG,sBAAsB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAA;IACzD,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IACvB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAC/D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,OAAe,EAAE,MAAc;IAC7D,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,CAAC,CAAA;IAClC,MAAM,EAAE,GAAG,YAAY,CAAC,MAAM,CAAC,CAAA;IAC/B,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE;QAAE,OAAO,SAAS,CAAA;IAClC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,OAAO,CAAA;IACrC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,OAAO,CAAA;IACrC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,OAAO,CAAA;IACrC,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,QAAQ,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QAC7D,KAAK,iBAAiB,CAAC;QACvB,KAAK,KAAK;YACR,OAAO,iBAAiB,CAAA;QAC1B,KAAK,kBAAkB,CAAC;QACxB,KAAK,MAAM;YACT,OAAO,kBAAkB,CAAA;QAC3B,KAAK,sBAAsB,CAAC;QAC5B,KAAK,UAAU;YACb,OAAO,sBAAsB,CAAA;QAC/B;YACE,OAAO,cAAc,CAAA;IACzB,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACzE,CAAC,CAAE,KAAiC;QACpC,CAAC,CAAC,SAAS,CAAA;AACf,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAA;AAC1E,CAAC;AAED,SAAS,UAAU,CACjB,IAAY,EACZ,OAAe,EACf,MAAc,EACd,MAAc,EACd,IAAoB,EACpB,UAAoB;IAEpB,OAAO;QACL,IAAI;QACJ,OAAO;QACP,MAAM;QACN,MAAM;QACN,IAAI;QACJ,QAAQ,EAAE,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC;QAC1C,UAAU,EAAE,OAAO,KAAK,MAAM,IAAI,MAAM,KAAK,MAAM;QACnD,UAAU;KACX,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAa;IACjD,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAA;IAC3B,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAA;IAEpB,MAAM,QAAQ,GAAsB,EAAE,CAAA;IACtC,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/C,8EAA8E;QAC9E,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;QACzD,IAAI,CAAC,KAAK;YAAE,SAAQ;QAEpB,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QACvC,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;QACrC,IAAI,CAAC,MAAM;YAAE,SAAQ;QAErB,QAAQ,CAAC,IAAI,CACX,UAAU,CACR,IAAI,EACJ,OAAO,IAAI,GAAG,EACd,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,OAAO,IAAI,GAAG,EACxC,MAAM,EACN,aAAa,CAAC,KAAK,CAAC,cAAc,IAAI,KAAK,CAAC,IAAI,CAAC,EACjD,KAAK,CAAC,YAAY,KAAK,IAAI,CAC5B,CACF,CAAA;IACH,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,SAAQ;QAChC,IAAI,MAAe,CAAA;QACnB,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,SAAQ;QACV,CAAC;QACD,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAA;QAC/B,IAAI,MAAM,EAAE,IAAI,KAAK,OAAO;YAAE,SAAQ;QAEtC,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,CAAA;QACxC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;YAAE,SAAQ;QAElC,OAAO,IAAI;aACR,MAAM,CAAC,CAAC,GAAG,EAAoB,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;aACrD,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;YACX,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAC7D,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CACrC,CAAA;YACD,OAAO,UAAU,CAAC,IAAI,IAAI,EAAE,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,IAAI,GAAG,EAAE,MAAM,IAAI,GAAG,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAA;QAClG,CAAC,CAAC;aACD,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,EAAE,CAAC,CAAA;IACzC,CAAC;IACD,OAAO,EAAE,CAAA;AACX,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,aAAa,CAAC,OAAuB,EAAE,MAAc;IACnE,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAA;IAC7B,IAAI,OAAO,KAAK,EAAE;QAAE,OAAO,EAAE,CAAA;IAE7B,IAAI,OAAO,KAAK,MAAM;QAAE,OAAO,iBAAiB,CAAC,OAAO,CAAC,CAAA;IAEzD,IAAI,CAAC;QACH,OAAO,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAA;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC;AAED,MAAM,cAAc,GAAmC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAA;AAEnG,2DAA2D;AAC3D,MAAM,UAAU,YAAY,CAAC,QAAoC;IAC/D,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACjC,MAAM,UAAU,GAAG,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAA;QAC1E,OAAO,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;IACrE,CAAC,CAAC,CAAA;AACJ,CAAC;AASD,MAAM,UAAU,iBAAiB,CAAC,QAAoC;IACpE,OAAO;QACL,KAAK,EAAE,QAAQ,CAAC,MAAM;QACtB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,MAAM;QACpE,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,MAAM;QACpE,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,MAAM;KACrE,CAAA;AACH,CAAC"}
@@ -0,0 +1,60 @@
1
+ import { TypedEmitter } from "../core/events.js";
2
+ import { DevccError } from "../utils/errors.js";
3
+ import type { ScopedLogger } from "../utils/logger.js";
4
+ import { type GitCommit, type GitStatus } from "./parse.js";
5
+ export interface GitSnapshot {
6
+ available: boolean;
7
+ isRepository: boolean;
8
+ status: GitStatus;
9
+ commits: GitCommit[];
10
+ version: string | null;
11
+ lastRefreshedAt: Date | null;
12
+ /** Set when the last refresh failed; the previous snapshot is kept. */
13
+ error: string | null;
14
+ }
15
+ export declare const EMPTY_GIT_SNAPSHOT: GitSnapshot;
16
+ export type GitServiceEvents = {
17
+ "git:changed": [GitSnapshot];
18
+ "git:error": [DevccError];
19
+ };
20
+ export interface GitServiceOptions {
21
+ rootDir: string;
22
+ logger: ScopedLogger;
23
+ commitLimit?: number;
24
+ timeoutMs?: number;
25
+ }
26
+ /**
27
+ * Thin wrapper around the `git` executable.
28
+ *
29
+ * We call git directly rather than adding a git abstraction library: the six
30
+ * commands the dashboard needs are stable plumbing, and porcelain v2 output is
31
+ * far easier to keep honest than a dependency's changing object model.
32
+ */
33
+ export declare class GitService extends TypedEmitter<GitServiceEvents> {
34
+ private readonly options;
35
+ private snapshot;
36
+ private refreshing;
37
+ private readonly commitLimit;
38
+ private readonly timeoutMs;
39
+ constructor(options: GitServiceOptions);
40
+ getSnapshot(): GitSnapshot;
41
+ /** Refresh branch/status/commits. Concurrent calls share one run. */
42
+ refresh(): Promise<GitSnapshot>;
43
+ private doRefresh;
44
+ /** `git fetch` is deliberately manual: it touches the network. */
45
+ fetch(): Promise<void>;
46
+ pull(): Promise<void>;
47
+ push(): Promise<void>;
48
+ stage(paths: readonly string[]): Promise<void>;
49
+ stageAll(): Promise<void>;
50
+ unstage(paths: readonly string[]): Promise<void>;
51
+ /** Destructive: throws away worktree changes. Callers must confirm first. */
52
+ discard(paths: readonly string[]): Promise<void>;
53
+ commit(message: string): Promise<void>;
54
+ /** Read-only diff for the inspect panel. */
55
+ diff(path: string, staged: boolean): Promise<string>;
56
+ private mutate;
57
+ private git;
58
+ private publish;
59
+ }
60
+ //# sourceMappingURL=GitService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GitService.d.ts","sourceRoot":"","sources":["../../../src/devcc/git/GitService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAE/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,EAKL,KAAK,SAAS,EACd,KAAK,SAAS,EACf,MAAM,YAAY,CAAA;AAEnB,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,OAAO,CAAA;IAClB,YAAY,EAAE,OAAO,CAAA;IACrB,MAAM,EAAE,SAAS,CAAA;IACjB,OAAO,EAAE,SAAS,EAAE,CAAA;IACpB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,eAAe,EAAE,IAAI,GAAG,IAAI,CAAA;IAC5B,uEAAuE;IACvE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB;AAED,eAAO,MAAM,kBAAkB,EAAE,WAQhC,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,aAAa,EAAE,CAAC,WAAW,CAAC,CAAA;IAC5B,WAAW,EAAE,CAAC,UAAU,CAAC,CAAA;CAC1B,CAAA;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,YAAY,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;GAMG;AACH,qBAAa,UAAW,SAAQ,YAAY,CAAC,gBAAgB,CAAC;IAMhD,OAAO,CAAC,QAAQ,CAAC,OAAO;IALpC,OAAO,CAAC,QAAQ,CAAyC;IACzD,OAAO,CAAC,UAAU,CAAoC;IACtD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAQ;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAQ;gBAEL,OAAO,EAAE,iBAAiB;IAMvD,WAAW,IAAI,WAAW;IAI1B,qEAAqE;IAC/D,OAAO,IAAI,OAAO,CAAC,WAAW,CAAC;YAQvB,SAAS;IA6CvB,kEAAkE;IAC5D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,KAAK,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAK9C,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAIzB,OAAO,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAKtD,6EAA6E;IACvE,OAAO,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAKhD,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ5C,4CAA4C;IACtC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;YAQ5C,MAAM;IAiBpB,OAAO,CAAC,GAAG;IASX,OAAO,CAAC,OAAO;CAKhB"}
@@ -0,0 +1,160 @@
1
+ import { TypedEmitter } from "../core/events.js";
2
+ import { DevccError } from "../utils/errors.js";
3
+ import { exec } from "../utils/exec.js";
4
+ import { EMPTY_GIT_STATUS, LOG_FORMAT, parseCommits, parsePorcelainV2, } from "./parse.js";
5
+ export const EMPTY_GIT_SNAPSHOT = {
6
+ available: false,
7
+ isRepository: false,
8
+ status: EMPTY_GIT_STATUS,
9
+ commits: [],
10
+ version: null,
11
+ lastRefreshedAt: null,
12
+ error: null,
13
+ };
14
+ /**
15
+ * Thin wrapper around the `git` executable.
16
+ *
17
+ * We call git directly rather than adding a git abstraction library: the six
18
+ * commands the dashboard needs are stable plumbing, and porcelain v2 output is
19
+ * far easier to keep honest than a dependency's changing object model.
20
+ */
21
+ export class GitService extends TypedEmitter {
22
+ options;
23
+ snapshot = { ...EMPTY_GIT_SNAPSHOT };
24
+ refreshing = null;
25
+ commitLimit;
26
+ timeoutMs;
27
+ constructor(options) {
28
+ super();
29
+ this.options = options;
30
+ this.commitLimit = options.commitLimit ?? 8;
31
+ this.timeoutMs = options.timeoutMs ?? 5_000;
32
+ }
33
+ getSnapshot() {
34
+ return this.snapshot;
35
+ }
36
+ /** Refresh branch/status/commits. Concurrent calls share one run. */
37
+ async refresh() {
38
+ if (this.refreshing)
39
+ return this.refreshing;
40
+ this.refreshing = this.doRefresh().finally(() => {
41
+ this.refreshing = null;
42
+ });
43
+ return this.refreshing;
44
+ }
45
+ async doRefresh() {
46
+ const [versionResult, statusResult, logResult] = await Promise.all([
47
+ this.git(["--version"]),
48
+ this.git(["status", "--porcelain=v2", "--branch", "--untracked-files=all"]),
49
+ this.git(["log", `--max-count=${this.commitLimit}`, `--pretty=format:${LOG_FORMAT}`]),
50
+ ]);
51
+ const available = versionResult.spawnError === undefined;
52
+ if (!available) {
53
+ return this.publish({
54
+ ...EMPTY_GIT_SNAPSHOT,
55
+ available: false,
56
+ lastRefreshedAt: new Date(),
57
+ error: "git executable not found",
58
+ });
59
+ }
60
+ const version = versionResult.ok ? versionResult.stdout.trim().replace(/^git version /u, "") : null;
61
+ if (!statusResult.ok) {
62
+ const notARepo = /not a git repository/iu.test(statusResult.stderr);
63
+ return this.publish({
64
+ ...this.snapshot,
65
+ available: true,
66
+ isRepository: false,
67
+ status: EMPTY_GIT_STATUS,
68
+ commits: [],
69
+ version,
70
+ lastRefreshedAt: new Date(),
71
+ error: notARepo ? null : statusResult.stderr.trim() || "git status failed",
72
+ });
73
+ }
74
+ return this.publish({
75
+ available: true,
76
+ isRepository: true,
77
+ status: parsePorcelainV2(statusResult.stdout),
78
+ // A fresh repository with no commits fails `git log`; an empty list is correct there.
79
+ commits: logResult.ok ? parseCommits(logResult.stdout) : [],
80
+ version,
81
+ lastRefreshedAt: new Date(),
82
+ error: null,
83
+ });
84
+ }
85
+ /** `git fetch` is deliberately manual: it touches the network. */
86
+ async fetch() {
87
+ await this.mutate(["fetch", "--prune"], "git fetch", 30_000);
88
+ }
89
+ async pull() {
90
+ await this.mutate(["pull", "--ff-only"], "git pull", 60_000);
91
+ }
92
+ async push() {
93
+ await this.mutate(["push"], "git push", 60_000);
94
+ }
95
+ async stage(paths) {
96
+ if (paths.length === 0)
97
+ return;
98
+ await this.mutate(["add", "--", ...paths], "git add");
99
+ }
100
+ async stageAll() {
101
+ await this.mutate(["add", "--all"], "git add --all");
102
+ }
103
+ async unstage(paths) {
104
+ if (paths.length === 0)
105
+ return;
106
+ await this.mutate(["restore", "--staged", "--", ...paths], "git restore --staged");
107
+ }
108
+ /** Destructive: throws away worktree changes. Callers must confirm first. */
109
+ async discard(paths) {
110
+ if (paths.length === 0)
111
+ return;
112
+ await this.mutate(["restore", "--worktree", "--", ...paths], "git restore");
113
+ }
114
+ async commit(message) {
115
+ const trimmed = message.trim();
116
+ if (trimmed === "") {
117
+ throw new DevccError({ scope: "git", message: "Commit message is empty" });
118
+ }
119
+ await this.mutate(["commit", "--message", trimmed], "git commit");
120
+ }
121
+ /** Read-only diff for the inspect panel. */
122
+ async diff(path, staged) {
123
+ const args = ["--no-pager", "diff", "--no-color"];
124
+ if (staged)
125
+ args.push("--staged");
126
+ args.push("--", path);
127
+ const result = await this.git(args, 10_000);
128
+ return result.ok ? result.stdout : result.stderr;
129
+ }
130
+ async mutate(args, label, timeoutMs) {
131
+ const result = await this.git(args, timeoutMs);
132
+ if (!result.ok) {
133
+ const detail = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
134
+ this.options.logger.warn(`${label} failed`, { code: result.code, detail });
135
+ const error = new DevccError({
136
+ scope: "git",
137
+ message: `${label} failed`,
138
+ detail: detail || (result.timedOut ? "timed out" : undefined),
139
+ });
140
+ this.emit("git:error", error);
141
+ throw error;
142
+ }
143
+ this.options.logger.info(`${label} ok`);
144
+ await this.refresh();
145
+ }
146
+ git(args, timeoutMs) {
147
+ return exec("git", args, {
148
+ cwd: this.options.rootDir,
149
+ timeoutMs: timeoutMs ?? this.timeoutMs,
150
+ // Never let git open an editor or a credential prompt under the TUI.
151
+ env: { ...process.env, GIT_TERMINAL_PROMPT: "0", GIT_OPTIONAL_LOCKS: "0", GIT_EDITOR: "true" },
152
+ });
153
+ }
154
+ publish(snapshot) {
155
+ this.snapshot = snapshot;
156
+ this.emit("git:changed", snapshot);
157
+ return snapshot;
158
+ }
159
+ }
160
+ //# sourceMappingURL=GitService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GitService.js","sourceRoot":"","sources":["../../../src/devcc/git/GitService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Pure parsers for git plumbing output.
3
+ *
4
+ * Kept separate from `GitService` so they can be unit tested without a repo,
5
+ * and so the shape of the data the UI consumes is defined in one place.
6
+ */
7
+ export type GitFileState = "staged" | "modified" | "untracked" | "conflicted";
8
+ export interface GitFile {
9
+ path: string;
10
+ state: GitFileState;
11
+ /** Two-letter porcelain code, e.g. `M.`, `.M`, `A.`, `??`. */
12
+ code: string;
13
+ /** Original path for renames. */
14
+ origPath?: string;
15
+ }
16
+ export interface GitStatus {
17
+ branch: string | null;
18
+ upstream: string | null;
19
+ ahead: number;
20
+ behind: number;
21
+ /** Short commit hash of HEAD, when known. */
22
+ head: string | null;
23
+ files: GitFile[];
24
+ clean: boolean;
25
+ }
26
+ export interface GitCommit {
27
+ hash: string;
28
+ shortHash: string;
29
+ author: string;
30
+ relativeDate: string;
31
+ subject: string;
32
+ }
33
+ export declare const EMPTY_GIT_STATUS: GitStatus;
34
+ /**
35
+ * Parse `git status --porcelain=v2 --branch --untracked-files=all`.
36
+ *
37
+ * Format reference: `man git-status`, "Porcelain Format Version 2".
38
+ */
39
+ export declare function parsePorcelainV2(output: string): GitStatus;
40
+ /** ASCII unit separator (0x1F), used as the field separator in our git log format. */
41
+ export declare const LOG_SEPARATOR: string;
42
+ /** Format string matching {@link parseCommits}. */
43
+ export declare const LOG_FORMAT: string;
44
+ /** Parse `git log --pretty=format:<LOG_FORMAT>`. */
45
+ export declare function parseCommits(output: string): GitCommit[];
46
+ export interface GitCounts {
47
+ staged: number;
48
+ modified: number;
49
+ untracked: number;
50
+ conflicted: number;
51
+ }
52
+ export declare function countByState(files: readonly GitFile[]): GitCounts;
53
+ /** Short summary such as `3 staged / 2 modified / 1 untracked`, or `clean`. */
54
+ export declare function summariseStatus(status: GitStatus): string;
55
+ /** `ahead 2, behind 1`, or `up to date` / `no upstream`. */
56
+ export declare function summariseTracking(status: GitStatus): string;
57
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../../src/devcc/git/parse.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,UAAU,GAAG,WAAW,GAAG,YAAY,CAAA;AAE7E,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,YAAY,CAAA;IACnB,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAA;IACZ,iCAAiC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,6CAA6C;IAC7C,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,KAAK,EAAE,OAAO,EAAE,CAAA;IAChB,KAAK,EAAE,OAAO,CAAA;CACf;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,eAAO,MAAM,gBAAgB,EAAE,SAQ9B,CAAA;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAiE1D;AA4BD,sFAAsF;AACtF,eAAO,MAAM,aAAa,QAA0B,CAAA;AAEpD,mDAAmD;AACnD,eAAO,MAAM,UAAU,QAAuD,CAAA;AAE9E,oDAAoD;AACpD,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,CAexD;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,GAAG,SAAS,CAIjE;AAED,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CASzD;AAED,4DAA4D;AAC5D,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAO3D"}
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Pure parsers for git plumbing output.
3
+ *
4
+ * Kept separate from `GitService` so they can be unit tested without a repo,
5
+ * and so the shape of the data the UI consumes is defined in one place.
6
+ */
7
+ export const EMPTY_GIT_STATUS = {
8
+ branch: null,
9
+ upstream: null,
10
+ ahead: 0,
11
+ behind: 0,
12
+ head: null,
13
+ files: [],
14
+ clean: true,
15
+ };
16
+ /**
17
+ * Parse `git status --porcelain=v2 --branch --untracked-files=all`.
18
+ *
19
+ * Format reference: `man git-status`, "Porcelain Format Version 2".
20
+ */
21
+ export function parsePorcelainV2(output) {
22
+ const status = { ...EMPTY_GIT_STATUS, files: [] };
23
+ for (const rawLine of output.split("\n")) {
24
+ const line = rawLine.replace(/\r$/u, "");
25
+ if (line.length === 0)
26
+ continue;
27
+ if (line.startsWith("# branch.head ")) {
28
+ const value = line.slice("# branch.head ".length).trim();
29
+ status.branch = value === "(detached)" ? null : value;
30
+ continue;
31
+ }
32
+ if (line.startsWith("# branch.oid ")) {
33
+ const value = line.slice("# branch.oid ".length).trim();
34
+ status.head = value === "(initial)" ? null : value.slice(0, 7);
35
+ continue;
36
+ }
37
+ if (line.startsWith("# branch.upstream ")) {
38
+ status.upstream = line.slice("# branch.upstream ".length).trim();
39
+ continue;
40
+ }
41
+ if (line.startsWith("# branch.ab ")) {
42
+ for (const part of line.slice("# branch.ab ".length).trim().split(" ")) {
43
+ const value = Number.parseInt(part.slice(1), 10);
44
+ if (Number.isNaN(value))
45
+ continue;
46
+ if (part.startsWith("+"))
47
+ status.ahead = value;
48
+ else if (part.startsWith("-"))
49
+ status.behind = value;
50
+ }
51
+ continue;
52
+ }
53
+ if (line.startsWith("# "))
54
+ continue;
55
+ const kind = line[0];
56
+ if (kind === "1") {
57
+ // 1 <XY> <sub> <mH> <mI> <mW> <hH> <hI> <path>
58
+ const fields = splitFields(line, 8);
59
+ const code = fields[1] ?? "..";
60
+ const path = fields[8] ?? "";
61
+ if (path)
62
+ status.files.push({ path, code, state: stateFromCode(code) });
63
+ continue;
64
+ }
65
+ if (kind === "2") {
66
+ // 2 <XY> <sub> <mH> <mI> <mW> <hH> <hI> <X><score> <path><TAB><origPath>
67
+ const fields = splitFields(line, 9);
68
+ const code = fields[1] ?? "..";
69
+ const rest = fields[9] ?? "";
70
+ const [path = "", origPath] = rest.split("\t");
71
+ if (path)
72
+ status.files.push({ path, code, state: stateFromCode(code), origPath });
73
+ continue;
74
+ }
75
+ if (kind === "u") {
76
+ const fields = splitFields(line, 10);
77
+ const path = fields[10] ?? "";
78
+ if (path)
79
+ status.files.push({ path, code: fields[1] ?? "UU", state: "conflicted" });
80
+ continue;
81
+ }
82
+ if (kind === "?") {
83
+ const path = line.slice(2);
84
+ if (path)
85
+ status.files.push({ path, code: "??", state: "untracked" });
86
+ continue;
87
+ }
88
+ }
89
+ status.clean = status.files.length === 0;
90
+ return status;
91
+ }
92
+ /**
93
+ * Porcelain v2 codes are `XY` where X is the staged change and Y the worktree
94
+ * change; `.` means "unchanged".
95
+ */
96
+ function stateFromCode(code) {
97
+ const staged = code[0] ?? ".";
98
+ return staged !== "." && staged !== "?" ? "staged" : "modified";
99
+ }
100
+ /** Split a porcelain line into `count` space-separated fields plus the remainder. */
101
+ function splitFields(line, count) {
102
+ const fields = [];
103
+ let index = 0;
104
+ for (let i = 0; i < count; i += 1) {
105
+ const next = line.indexOf(" ", index);
106
+ if (next === -1) {
107
+ fields.push(line.slice(index));
108
+ return fields;
109
+ }
110
+ fields.push(line.slice(index, next));
111
+ index = next + 1;
112
+ }
113
+ fields.push(line.slice(index));
114
+ return fields;
115
+ }
116
+ /** ASCII unit separator (0x1F), used as the field separator in our git log format. */
117
+ export const LOG_SEPARATOR = String.fromCharCode(31);
118
+ /** Format string matching {@link parseCommits}. */
119
+ export const LOG_FORMAT = ["%H", "%h", "%an", "%ar", "%s"].join(LOG_SEPARATOR);
120
+ /** Parse `git log --pretty=format:<LOG_FORMAT>`. */
121
+ export function parseCommits(output) {
122
+ const commits = [];
123
+ for (const line of output.split("\n")) {
124
+ if (line.trim() === "")
125
+ continue;
126
+ const [hash, shortHash, author, relativeDate, ...subject] = line.split(LOG_SEPARATOR);
127
+ if (!hash || !shortHash)
128
+ continue;
129
+ commits.push({
130
+ hash,
131
+ shortHash,
132
+ author: author ?? "",
133
+ relativeDate: relativeDate ?? "",
134
+ subject: subject.join(LOG_SEPARATOR),
135
+ });
136
+ }
137
+ return commits;
138
+ }
139
+ export function countByState(files) {
140
+ const counts = { staged: 0, modified: 0, untracked: 0, conflicted: 0 };
141
+ for (const file of files)
142
+ counts[file.state] += 1;
143
+ return counts;
144
+ }
145
+ /** Short summary such as `3 staged / 2 modified / 1 untracked`, or `clean`. */
146
+ export function summariseStatus(status) {
147
+ if (status.clean)
148
+ return "clean";
149
+ const counts = countByState(status.files);
150
+ const parts = [];
151
+ if (counts.staged)
152
+ parts.push(`${counts.staged} staged`);
153
+ if (counts.modified)
154
+ parts.push(`${counts.modified} modified`);
155
+ if (counts.untracked)
156
+ parts.push(`${counts.untracked} untracked`);
157
+ if (counts.conflicted)
158
+ parts.push(`${counts.conflicted} conflicted`);
159
+ return parts.join(" / ");
160
+ }
161
+ /** `ahead 2, behind 1`, or `up to date` / `no upstream`. */
162
+ export function summariseTracking(status) {
163
+ if (!status.upstream)
164
+ return "no upstream";
165
+ if (status.ahead === 0 && status.behind === 0)
166
+ return "up to date";
167
+ const parts = [];
168
+ if (status.ahead)
169
+ parts.push(`ahead ${status.ahead}`);
170
+ if (status.behind)
171
+ parts.push(`behind ${status.behind}`);
172
+ return parts.join(", ");
173
+ }
174
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../../src/devcc/git/parse.ts"],"names":[],"mappings":"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"}