remote-opencode 1.3.0 → 1.3.1

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.
@@ -1,10 +1,11 @@
1
1
  import { SlashCommandBuilder, MessageFlags } from 'discord.js';
2
- import { exec } from 'node:child_process';
2
+ import { execFile } from 'node:child_process';
3
3
  import { promisify } from 'node:util';
4
4
  import * as dataStore from '../services/dataStore.js';
5
- const execAsync = promisify(exec);
5
+ const execFileAsync = promisify(execFile);
6
6
  const MAX_LENGTH = 1900;
7
7
  const CODE_BLOCK_OVERHEAD = 8; // ```diff\n...\n```
8
+ const GIT_REF_PATTERN = /^[a-zA-Z0-9._\/-]+$/;
8
9
  function formatDiff(raw) {
9
10
  const maxContent = MAX_LENGTH - CODE_BLOCK_OVERHEAD;
10
11
  if (raw.length <= maxContent) {
@@ -61,23 +62,27 @@ export const diff = {
61
62
  });
62
63
  return;
63
64
  }
65
+ if (target === 'branch' && !GIT_REF_PATTERN.test(base)) {
66
+ await i.reply({ content: '❌ Invalid base branch name.', flags: MessageFlags.Ephemeral });
67
+ return;
68
+ }
64
69
  await i.deferReply();
65
70
  try {
66
71
  let gitArgs;
67
72
  switch (target) {
68
73
  case 'staged':
69
- gitArgs = 'git diff --cached';
74
+ gitArgs = ['diff', '--cached'];
70
75
  break;
71
76
  case 'branch':
72
- gitArgs = `git diff ${base}...HEAD`;
77
+ gitArgs = ['diff', `${base}...HEAD`];
73
78
  break;
74
79
  default:
75
- gitArgs = 'git diff';
80
+ gitArgs = ['diff'];
76
81
  }
77
82
  if (stat) {
78
- gitArgs += ' --stat';
83
+ gitArgs.push('--stat');
79
84
  }
80
- const { stdout } = await execAsync(gitArgs, { cwd: projectPath });
85
+ const { stdout } = await execFileAsync('git', gitArgs, { cwd: projectPath });
81
86
  const output = stdout.trim();
82
87
  if (!output) {
83
88
  const targetLabel = target === 'branch' ? `branch (base: ${base})` : target;
@@ -1,8 +1,8 @@
1
- import { exec } from 'node:child_process';
1
+ import { execFile } from 'node:child_process';
2
2
  import { promisify } from 'node:util';
3
3
  import { existsSync } from 'node:fs';
4
4
  import { join, resolve } from 'node:path';
5
- const execAsync = promisify(exec);
5
+ const execFileAsync = promisify(execFile);
6
6
  export function sanitizeBranchName(name) {
7
7
  return name
8
8
  .trim()
@@ -13,8 +13,8 @@ export function sanitizeBranchName(name) {
13
13
  export async function branchExists(projectPath, branchName) {
14
14
  try {
15
15
  const [localRes, remoteRes] = await Promise.all([
16
- execAsync(`git branch --list ${branchName}`, { cwd: projectPath }).catch(() => ({ stdout: '' })),
17
- execAsync(`git branch -r --list origin/${branchName}`, { cwd: projectPath }).catch(() => ({ stdout: '' }))
16
+ execFileAsync('git', ['branch', '--list', branchName], { cwd: projectPath }).catch(() => ({ stdout: '' })),
17
+ execFileAsync('git', ['branch', '-r', '--list', `origin/${branchName}`], { cwd: projectPath }).catch(() => ({ stdout: '' }))
18
18
  ]);
19
19
  return {
20
20
  local: localRes.stdout.trim().length > 0,
@@ -33,12 +33,12 @@ export async function createWorktree(projectPath, branchName) {
33
33
  const { local, remote } = await branchExists(projectPath, sanitizedBranch);
34
34
  try {
35
35
  if (local || remote) {
36
- await execAsync(`git worktree add ./worktrees/${sanitizedBranch} ${sanitizedBranch}`, {
36
+ await execFileAsync('git', ['worktree', 'add', `./worktrees/${sanitizedBranch}`, sanitizedBranch], {
37
37
  cwd: projectPath
38
38
  });
39
39
  }
40
40
  else {
41
- await execAsync(`git worktree add ./worktrees/${sanitizedBranch} -b ${sanitizedBranch}`, {
41
+ await execFileAsync('git', ['worktree', 'add', `./worktrees/${sanitizedBranch}`, '-b', sanitizedBranch], {
42
42
  cwd: projectPath
43
43
  });
44
44
  }
@@ -53,13 +53,13 @@ export async function removeWorktree(worktreePath, deleteBranch) {
53
53
  try {
54
54
  let branchName;
55
55
  if (deleteBranch) {
56
- const { stdout } = await execAsync('git branch --show-current', { cwd: worktreePath });
56
+ const { stdout } = await execFileAsync('git', ['branch', '--show-current'], { cwd: worktreePath });
57
57
  branchName = stdout.trim();
58
58
  }
59
59
  const projectPath = resolve(worktreePath, '..', '..');
60
- await execAsync(`git worktree remove "${worktreePath}" --force`, { cwd: projectPath });
60
+ await execFileAsync('git', ['worktree', 'remove', worktreePath, '--force'], { cwd: projectPath });
61
61
  if (deleteBranch && branchName) {
62
- await execAsync(`git branch -D ${branchName}`, { cwd: projectPath });
62
+ await execFileAsync('git', ['branch', '-D', branchName], { cwd: projectPath });
63
63
  }
64
64
  }
65
65
  catch (error) {
@@ -69,7 +69,7 @@ export async function removeWorktree(worktreePath, deleteBranch) {
69
69
  }
70
70
  export async function getCurrentBranch(cwd) {
71
71
  try {
72
- const { stdout } = await execAsync('git rev-parse --abbrev-ref HEAD', { cwd });
72
+ const { stdout } = await execFileAsync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd });
73
73
  return stdout.trim() || null;
74
74
  }
75
75
  catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remote-opencode",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "Discord bot for remote OpenCode CLI access",
5
5
  "main": "dist/src/index.js",
6
6
  "bin": {
@@ -52,5 +52,8 @@
52
52
  "ts-node": "^10.9.2",
53
53
  "typescript": "^5.9.3",
54
54
  "vitest": "^4.0.18"
55
+ },
56
+ "overrides": {
57
+ "undici": "^6.23.0"
55
58
  }
56
59
  }