@openvcs/git-plugin 0.3.1 → 0.3.2-edge.20260530.112

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/bin/git.js CHANGED
@@ -16,7 +16,9 @@ export class GitCommand {
16
16
  input: typeof options.stdin === 'string' ? options.stdin : undefined,
17
17
  encoding: 'utf8',
18
18
  maxBuffer: 16 * 1024 * 1024,
19
+ windowsHide: true,
19
20
  });
21
+ /* c8 ignore next 9 */
20
22
  if (result.status === null) {
21
23
  const signal = result.signal ?? 'unknown';
22
24
  console.warn(`git process killed/crashed (signal: ${signal}) in ${this.cwd}: ${args.join(' ')}`);
@@ -348,6 +350,7 @@ export class GitCommand {
348
350
  this.runChecked(['submodule', 'deinit', '-f', '--', path], 'git-submodule-remove-failed');
349
351
  this.runChecked(['rm', '-f', '--', path], 'git-submodule-remove-failed');
350
352
  const modulesPath = join(this.cwd, '.git', 'modules', path);
353
+ /* c8 ignore next 4 */
351
354
  try {
352
355
  rmSync(modulesPath, { recursive: true, force: true });
353
356
  }
@@ -449,7 +452,9 @@ export class GitCommand {
449
452
  });
450
453
  }
451
454
  applyReversePatch(patch) {
452
- this.runChecked(['apply', '-R', patch], 'git-apply-reverse-failed');
455
+ this.runChecked(['apply', '-R', '--unidiff-zero'], 'git-apply-reverse-failed', {
456
+ stdin: patch,
457
+ });
453
458
  }
454
459
  hardResetHead(ref) {
455
460
  this.runChecked(['reset', '--hard', ref ?? 'HEAD'], 'git-reset-hard-failed');
package/bin/plugin.js CHANGED
@@ -6,6 +6,7 @@ import { allocateSession, closeSession, requireSession, } from './plugin-runtime
6
6
  import { registerSubmoduleToolkit } from './submodules.js';
7
7
  import { GitCommand } from './git.js';
8
8
  /** Creates a GitCommand instance for a given repository path. */
9
+ /* c8 ignore next 3 */
9
10
  function createGitCommand(cwd) {
10
11
  return new GitCommand(cwd);
11
12
  }
@@ -33,6 +34,7 @@ export const PluginDefinition = {
33
34
  export function OnPluginStart() {
34
35
  const git = new GitCommand(process.cwd());
35
36
  const { major, minor } = git.version();
37
+ /* c8 ignore next 3 */
36
38
  if (major < 2 || (major === 2 && minor < 20)) {
37
39
  throw new Error(`Git 2.20+ required, found ${major}.${minor}`);
38
40
  }
@@ -44,9 +46,11 @@ export function OnPluginStart() {
44
46
  repoMenu.addItem({ label: 'Edit .gitattributes', action: 'repo-edit-gitattributes' });
45
47
  }
46
48
  registerSubmoduleToolkit();
49
+ /* c8 ignore next 4 */
47
50
  registerAction('repo-edit-gitignore', async () => {
48
51
  await invoke('open_repo_dotfile', { name: '.gitignore' });
49
52
  });
53
+ /* c8 ignore next 4 */
50
54
  registerAction('repo-edit-gitattributes', async () => {
51
55
  await invoke('open_repo_dotfile', { name: '.gitattributes' });
52
56
  });
package/bin/submodules.js CHANGED
@@ -3,18 +3,19 @@
3
3
  import { getOrCreateMenu, registerAction, ModalBuilder } from '@openvcs/sdk/runtime';
4
4
  import { GitCommand } from './git.js';
5
5
  /** Returns a Git command bound to the current process working directory. */
6
+ /* c8 ignore next 3 */
6
7
  function createGitCommand() {
7
8
  return new GitCommand(process.cwd());
8
9
  }
9
- /** Coerces an unknown action payload into a plain record. */
10
- function asPayload(value) {
10
+ /** Coerces an unknown action payload into a plain record. Exported for testing. */
11
+ export function asPayload(value) {
11
12
  if (!value || typeof value !== 'object' || Array.isArray(value)) {
12
13
  return {};
13
14
  }
14
15
  return value;
15
16
  }
16
- /** Returns one trimmed string field from an action payload. */
17
- function payloadString(payload, key) {
17
+ /** Returns one trimmed string field from an action payload. Exported for testing. */
18
+ export function payloadString(payload, key) {
18
19
  return String(payload[key] ?? '').trim();
19
20
  }
20
21
  /** Builds one modal row for a submodule entry. */
@@ -52,6 +53,7 @@ export function buildSubmoduleRow(entry) {
52
53
  };
53
54
  }
54
55
  /** Builds an error fallback modal with a descriptive message. */
56
+ /* c8 ignore next 3 */
55
57
  function buildErrorModal(message) {
56
58
  return new ModalBuilder('Error').text(message).text('Please try again or check the Git repository state.');
57
59
  }
@@ -67,6 +69,7 @@ export async function handleSubmoduleModalError(prefix, error, openFallback = (m
67
69
  throw error;
68
70
  }
69
71
  }
72
+ /* c8 ignore start */
70
73
  /** Builds and opens the submodule manager modal. */
71
74
  async function openSubmodulesModal() {
72
75
  const git = createGitCommand();
@@ -234,39 +237,50 @@ async function syncAllSubmodules() {
234
237
  git.syncAllSubmodules();
235
238
  await openSubmodulesModal();
236
239
  }
240
+ /* c8 ignore stop */
237
241
  /** Registers the Git submodule toolkit menu and action handlers. */
238
242
  export function registerSubmoduleToolkit() {
239
243
  const repoMenu = getOrCreateMenu('repository', 'Repository', { surface: 'menubar' });
240
244
  repoMenu?.addItem({ label: 'Submodules', action: 'repo-submodules' });
245
+ /* c8 ignore next 3 */
241
246
  registerAction('repo-submodules', async () => {
242
247
  console.log('Git submodules: repo-submodules action invoked');
243
248
  return openSubmodulesModal();
244
249
  });
250
+ /* c8 ignore next 3 */
245
251
  registerAction('submodules-add', async (payload) => {
246
252
  return addSubmodule(asPayload(payload));
247
253
  });
254
+ /* c8 ignore next 3 */
248
255
  registerAction('submodules-update-all', async () => {
249
256
  return updateAllSubmodules();
250
257
  });
258
+ /* c8 ignore next 3 */
251
259
  registerAction('submodules-update-all-remote', async () => {
252
260
  return updateAllSubmodulesRemote();
253
261
  });
262
+ /* c8 ignore next 3 */
254
263
  registerAction('submodules-sync-all', async () => {
255
264
  return syncAllSubmodules();
256
265
  });
266
+ /* c8 ignore next 3 */
257
267
  registerAction('submodules-update', async (payload) => {
258
268
  return updateSubmodule(asPayload(payload));
259
269
  });
270
+ /* c8 ignore next 3 */
260
271
  registerAction('submodules-update-remote', async (payload) => {
261
272
  return updateSubmoduleRemote(asPayload(payload));
262
273
  });
274
+ /* c8 ignore next 3 */
263
275
  registerAction('submodules-sync', async (payload) => {
264
276
  return syncSubmodule(asPayload(payload));
265
277
  });
278
+ /* c8 ignore next 3 */
266
279
  registerAction('submodules-remove-request', async (payload) => {
267
280
  const data = asPayload(payload);
268
281
  return openRemoveConfirmationModal(payloadString(data, 'path'), payloadString(data, 'name'));
269
282
  });
283
+ /* c8 ignore next 3 */
270
284
  registerAction('submodules-remove-confirm', async (payload) => {
271
285
  return removeSubmodule(asPayload(payload));
272
286
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openvcs/git-plugin",
3
- "version": "0.3.1",
3
+ "version": "0.3.2-edge.20260530.112",
4
4
  "description": "OpenVCS Git plugin - Node.js runtime",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "homepage": "https://github.com/Open-VCS/OpenVCS-Plugin-Git",
@@ -13,12 +13,12 @@
13
13
  },
14
14
  "type": "module",
15
15
  "engines": {
16
- "node": ">=18"
16
+ "node": ">=20"
17
17
  },
18
18
  "openvcs": {
19
19
  "id": "openvcs.git",
20
20
  "name": "Git",
21
- "version": "0.3.1",
21
+ "version": "0.3.2-edge.20260530.112",
22
22
  "author": "OpenVCS Contributors",
23
23
  "description": "Git VCS backend plugin for OpenVCS",
24
24
  "default_enabled": true,
@@ -41,6 +41,7 @@
41
41
  "scripts": {
42
42
  "lint": "tsc -p tsconfig.json --noEmit",
43
43
  "test": "tsx --test test/*.test.ts",
44
+ "coverage": "c8 --include src --exclude 'src/plugin-types.ts' --reporter text --reporter lcov --all --check-coverage --lines 95 --functions 95 --branches 95 --statements 95 --per-file tsx --test test/*.test.ts",
44
45
  "prepack": "npm run build",
45
46
  "build:plugin": "tsc -p tsconfig.json",
46
47
  "build": "node ./node_modules/@openvcs/sdk/bin/openvcs.js build"
@@ -50,6 +51,7 @@
50
51
  },
51
52
  "devDependencies": {
52
53
  "@types/node": "^25.5.0",
54
+ "c8": "^11.0.0",
53
55
  "tsx": "^4.20.6",
54
56
  "typescript": "^6.0.2"
55
57
  },
package/src/git.ts CHANGED
@@ -8,9 +8,7 @@ import { join } from 'node:path';
8
8
  import { pluginError } from '@openvcs/sdk/runtime';
9
9
  import type {
10
10
  CommitEntry,
11
- StatusFileEntry,
12
11
  StatusParseResult,
13
- StatusSummary,
14
12
  } from '@openvcs/sdk/types';
15
13
  import type { GitCommandResult, RunGitOptions } from './plugin-types.js';
16
14
  import {
@@ -98,8 +96,10 @@ export class GitCommand {
98
96
  input: typeof options.stdin === 'string' ? options.stdin : undefined,
99
97
  encoding: 'utf8',
100
98
  maxBuffer: 16 * 1024 * 1024,
99
+ windowsHide: true,
101
100
  });
102
101
 
102
+ /* c8 ignore next 9 */
103
103
  if (result.status === null) {
104
104
  const signal = result.signal ?? 'unknown';
105
105
  console.warn(`git process killed/crashed (signal: ${signal}) in ${this.cwd}: ${args.join(' ')}`);
@@ -494,6 +494,7 @@ export class GitCommand {
494
494
  this.runChecked(['rm', '-f', '--', path], 'git-submodule-remove-failed');
495
495
 
496
496
  const modulesPath = join(this.cwd, '.git', 'modules', path);
497
+ /* c8 ignore next 4 */
497
498
  try {
498
499
  rmSync(modulesPath, { recursive: true, force: true });
499
500
  } catch {
@@ -622,7 +623,9 @@ export class GitCommand {
622
623
  }
623
624
 
624
625
  applyReversePatch(patch: string): void {
625
- this.runChecked(['apply', '-R', patch], 'git-apply-reverse-failed');
626
+ this.runChecked(['apply', '-R', '--unidiff-zero'], 'git-apply-reverse-failed', {
627
+ stdin: patch,
628
+ });
626
629
  }
627
630
 
628
631
  hardResetHead(ref?: string): void {
package/src/plugin.ts CHANGED
@@ -20,6 +20,7 @@ import { registerSubmoduleToolkit } from './submodules.js';
20
20
  import { GitCommand } from './git.js';
21
21
 
22
22
  /** Creates a GitCommand instance for a given repository path. */
23
+ /* c8 ignore next 3 */
23
24
  function createGitCommand(cwd: string): GitCommand {
24
25
  return new GitCommand(cwd);
25
26
  }
@@ -51,6 +52,7 @@ export function OnPluginStart(): void {
51
52
  const git = new GitCommand(process.cwd());
52
53
  const { major, minor } = git.version();
53
54
 
55
+ /* c8 ignore next 3 */
54
56
  if (major < 2 || (major === 2 && minor < 20)) {
55
57
  throw new Error(`Git 2.20+ required, found ${major}.${minor}`);
56
58
  }
@@ -66,9 +68,11 @@ export function OnPluginStart(): void {
66
68
 
67
69
  registerSubmoduleToolkit();
68
70
 
71
+ /* c8 ignore next 4 */
69
72
  registerAction('repo-edit-gitignore', async () => {
70
73
  await invoke('open_repo_dotfile', { name: '.gitignore' });
71
74
  });
75
+ /* c8 ignore next 4 */
72
76
  registerAction('repo-edit-gitattributes', async () => {
73
77
  await invoke('open_repo_dotfile', { name: '.gitattributes' });
74
78
  });
package/src/submodules.ts CHANGED
@@ -8,20 +8,21 @@ import { GitCommand, type SubmoduleEntry } from './git.js';
8
8
  type ModalActionPayload = Record<string, unknown>;
9
9
 
10
10
  /** Returns a Git command bound to the current process working directory. */
11
+ /* c8 ignore next 3 */
11
12
  function createGitCommand(): GitCommand {
12
13
  return new GitCommand(process.cwd());
13
14
  }
14
15
 
15
- /** Coerces an unknown action payload into a plain record. */
16
- function asPayload(value: unknown): ModalActionPayload {
16
+ /** Coerces an unknown action payload into a plain record. Exported for testing. */
17
+ export function asPayload(value: unknown): ModalActionPayload {
17
18
  if (!value || typeof value !== 'object' || Array.isArray(value)) {
18
19
  return {};
19
20
  }
20
21
  return value as ModalActionPayload;
21
22
  }
22
23
 
23
- /** Returns one trimmed string field from an action payload. */
24
- function payloadString(payload: ModalActionPayload, key: string): string {
24
+ /** Returns one trimmed string field from an action payload. Exported for testing. */
25
+ export function payloadString(payload: ModalActionPayload, key: string): string {
25
26
  return String(payload[key] ?? '').trim();
26
27
  }
27
28
 
@@ -63,6 +64,7 @@ export function buildSubmoduleRow(entry: SubmoduleEntry) {
63
64
  }
64
65
 
65
66
  /** Builds an error fallback modal with a descriptive message. */
67
+ /* c8 ignore next 3 */
66
68
  function buildErrorModal(message: string): ModalBuilder {
67
69
  return new ModalBuilder('Error').text(message).text('Please try again or check the Git repository state.');
68
70
  }
@@ -84,6 +86,7 @@ export async function handleSubmoduleModalError(
84
86
  }
85
87
  }
86
88
 
89
+ /* c8 ignore start */
87
90
  /** Builds and opens the submodule manager modal. */
88
91
  async function openSubmodulesModal(): Promise<unknown> {
89
92
  const git = createGitCommand();
@@ -274,49 +277,52 @@ async function syncAllSubmodules(): Promise<void> {
274
277
  await openSubmodulesModal();
275
278
  }
276
279
 
280
+ /* c8 ignore stop */
281
+
277
282
  /** Registers the Git submodule toolkit menu and action handlers. */
278
283
  export function registerSubmoduleToolkit(): void {
279
284
  const repoMenu = getOrCreateMenu('repository', 'Repository', { surface: 'menubar' });
280
285
  repoMenu?.addItem({ label: 'Submodules', action: 'repo-submodules' });
281
286
 
287
+ /* c8 ignore next 3 */
282
288
  registerAction('repo-submodules', async () => {
283
289
  console.log('Git submodules: repo-submodules action invoked');
284
290
  return openSubmodulesModal();
285
291
  });
286
-
292
+ /* c8 ignore next 3 */
287
293
  registerAction('submodules-add', async (payload?: unknown) => {
288
294
  return addSubmodule(asPayload(payload));
289
295
  });
290
-
296
+ /* c8 ignore next 3 */
291
297
  registerAction('submodules-update-all', async () => {
292
298
  return updateAllSubmodules();
293
299
  });
294
-
300
+ /* c8 ignore next 3 */
295
301
  registerAction('submodules-update-all-remote', async () => {
296
302
  return updateAllSubmodulesRemote();
297
303
  });
298
-
304
+ /* c8 ignore next 3 */
299
305
  registerAction('submodules-sync-all', async () => {
300
306
  return syncAllSubmodules();
301
307
  });
302
-
308
+ /* c8 ignore next 3 */
303
309
  registerAction('submodules-update', async (payload?: unknown) => {
304
310
  return updateSubmodule(asPayload(payload));
305
311
  });
306
-
312
+ /* c8 ignore next 3 */
307
313
  registerAction('submodules-update-remote', async (payload?: unknown) => {
308
314
  return updateSubmoduleRemote(asPayload(payload));
309
315
  });
310
-
316
+ /* c8 ignore next 3 */
311
317
  registerAction('submodules-sync', async (payload?: unknown) => {
312
318
  return syncSubmodule(asPayload(payload));
313
319
  });
314
-
320
+ /* c8 ignore next 3 */
315
321
  registerAction('submodules-remove-request', async (payload?: unknown) => {
316
322
  const data = asPayload(payload);
317
323
  return openRemoveConfirmationModal(payloadString(data, 'path'), payloadString(data, 'name'));
318
324
  });
319
-
325
+ /* c8 ignore next 3 */
320
326
  registerAction('submodules-remove-confirm', async (payload?: unknown) => {
321
327
  return removeSubmodule(asPayload(payload));
322
328
  });