hale-commenting-system 3.4.1 → 3.4.4

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
@@ -27,6 +27,8 @@ The automated integration script (`npx hale-commenting-system init`) works best
27
27
  npm install hale-commenting-system
28
28
  ```
29
29
 
30
+ > **⚠️ Important:** This package modifies your project files during installation. Before uninstalling, always run `npx hale-commenting-system remove` to cleanly remove the integration and avoid breaking your application.
31
+
30
32
  ## Quick Start
31
33
 
32
34
  1. **Install the package:**
@@ -50,6 +52,53 @@ npm install hale-commenting-system
50
52
  npm run start:dev
51
53
  ```
52
54
 
55
+ ## Uninstalling
56
+
57
+ **IMPORTANT:** Before uninstalling the package, you must first remove the integration to avoid breaking your application.
58
+
59
+ ### Clean Uninstall Process
60
+
61
+ 1. **Run the removal script:**
62
+ ```bash
63
+ npx hale-commenting-system remove
64
+ ```
65
+
66
+ 2. **Uninstall the package:**
67
+ ```bash
68
+ npm uninstall hale-commenting-system
69
+ ```
70
+
71
+ 3. **Restart your dev server:**
72
+ ```bash
73
+ npm run start:dev
74
+ ```
75
+
76
+ ### What the Removal Script Does
77
+
78
+ The removal script will automatically:
79
+ - Remove imports from `src/app/index.tsx`
80
+ - Remove imports from `src/app/AppLayout/AppLayout.tsx`
81
+ - Notify you about webpack middleware (may require manual removal)
82
+ - Keep `.env` and `.env.server` files (you can delete manually if needed)
83
+
84
+ ### Manual Uninstall (If Needed)
85
+
86
+ If you need to manually remove the integration:
87
+
88
+ 1. **In `src/app/index.tsx`**, remove:
89
+ ```typescript
90
+ import { CommentProvider, GitHubAuthProvider } from "hale-commenting-system";
91
+ ```
92
+ And remove the `<GitHubAuthProvider>` and `<CommentProvider>` wrappers.
93
+
94
+ 2. **In `src/app/AppLayout/AppLayout.tsx`**, remove:
95
+ ```typescript
96
+ import { CommentPanel, CommentOverlay } from "hale-commenting-system";
97
+ ```
98
+ And remove the `<CommentPanel>` and `<CommentOverlay />` components.
99
+
100
+ 3. **In `webpack.dev.js`**, remove the middleware configuration added for GitHub OAuth and Jira API proxying.
101
+
53
102
  ## Usage
54
103
 
55
104
  After running the integration script, the commenting system will be available in your PatternFly React Seed application.
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "hale-commenting-system",
3
- "version": "3.4.1",
3
+ "version": "3.4.4",
4
4
  "description": "A commenting system for PatternFly React applications that allows designers and developers to add comments directly on design pages, sync with GitHub Issues, and link Jira tickets.",
5
5
  "homepage": "https://www.npmjs.com/package/hale-commenting-system",
6
6
  "license": "MIT",
7
7
  "main": "src/app/commenting-system/index.ts",
8
8
  "types": "src/app/commenting-system/index.ts",
9
9
  "bin": {
10
- "hale-commenting-system": "scripts/integrate.js"
10
+ "hale-commenting-system": "scripts/cli.js"
11
11
  },
12
12
  "files": [
13
13
  "src/app/commenting-system/",
package/scripts/cli.js ADDED
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawn } = require('child_process');
4
+ const path = require('path');
5
+
6
+ const command = process.argv[2];
7
+
8
+ const scriptMap = {
9
+ init: 'integrate.js',
10
+ remove: 'remove.js',
11
+ uninstall: 'remove.js',
12
+ };
13
+
14
+ if (!command || command === 'init') {
15
+ // Default to init
16
+ const scriptPath = path.join(__dirname, 'integrate.js');
17
+ const child = spawn('node', [scriptPath], { stdio: 'inherit' });
18
+ child.on('exit', (code) => process.exit(code));
19
+ } else if (scriptMap[command]) {
20
+ const scriptPath = path.join(__dirname, scriptMap[command]);
21
+ const child = spawn('node', [scriptPath], { stdio: 'inherit' });
22
+ child.on('exit', (code) => process.exit(code));
23
+ } else {
24
+ console.log('\n╔════════════════════════════════════════════════════╗');
25
+ console.log('║ Hale Commenting System - CLI ║');
26
+ console.log('╚════════════════════════════════════════════════════╝\n');
27
+ console.log('Usage:');
28
+ console.log(' npx hale-commenting-system init Install and integrate the commenting system');
29
+ console.log(' npx hale-commenting-system remove Remove the commenting system');
30
+ console.log(' npx hale-commenting-system uninstall Remove the commenting system (alias)\n');
31
+ process.exit(1);
32
+ }
@@ -1266,12 +1266,13 @@ async function main() {
1266
1266
  console.log(`\n✅ Detected repository: ${owner}/${repo}\n`);
1267
1267
  }
1268
1268
  } else if (projectSetup === 'cloned') {
1269
- console.log('\n📝 Since you cloned the repo, you\'ll need to create your own GitHub repository.\n');
1270
- console.log('Steps:');
1269
+ console.log('\n📝 Since you cloned the repo, you can create your own GitHub repository to store comments.\n');
1270
+ console.log('Note: This is optional! You can test the system locally first and add GitHub integration later.\n');
1271
+ console.log('Steps to create a GitHub repository (optional):');
1271
1272
  console.log('1. Create a new repository on GitHub');
1272
1273
  console.log('2. Add it as a remote: git remote add origin <your-repo-url>');
1273
1274
  console.log('3. Push your code: git push -u origin main\n');
1274
-
1275
+
1275
1276
  const hasCreated = await prompt([
1276
1277
  {
1277
1278
  type: 'confirm',
@@ -1282,34 +1283,36 @@ async function main() {
1282
1283
  ]);
1283
1284
 
1284
1285
  if (!hasCreated.created) {
1285
- console.log('\nPlease complete the steps above and run this setup again.');
1286
- rl.close();
1287
- return;
1288
- }
1289
-
1290
- // Ask for owner/repo
1291
- const repoAnswers = await prompt([
1292
- {
1293
- type: 'input',
1294
- name: 'owner',
1295
- message: 'What is your GitHub username or organization name?',
1296
- validate: (input) => {
1297
- if (!input.trim()) return 'Owner is required';
1298
- return true;
1299
- }
1300
- },
1301
- {
1302
- type: 'input',
1303
- name: 'repo',
1304
- message: 'What is the name of your GitHub repository?',
1305
- validate: (input) => {
1306
- if (!input.trim()) return 'Repository name is required';
1307
- return true;
1286
+ console.log('\n⏭️ No problem! You can set up the GitHub repository later.');
1287
+ console.log(' The system will still work locally for testing.\n');
1288
+ // Set placeholder values that can be updated later
1289
+ owner = 'YOUR_GITHUB_USERNAME';
1290
+ repo = 'YOUR_REPO_NAME';
1291
+ } else {
1292
+ // Ask for owner/repo
1293
+ const repoAnswers = await prompt([
1294
+ {
1295
+ type: 'input',
1296
+ name: 'owner',
1297
+ message: 'What is your GitHub username or organization name?',
1298
+ validate: (input) => {
1299
+ if (!input.trim()) return 'Owner is required';
1300
+ return true;
1301
+ }
1302
+ },
1303
+ {
1304
+ type: 'input',
1305
+ name: 'repo',
1306
+ message: 'What is the name of your GitHub repository?',
1307
+ validate: (input) => {
1308
+ if (!input.trim()) return 'Repository name is required';
1309
+ return true;
1310
+ }
1308
1311
  }
1309
- }
1310
- ]);
1311
- owner = repoAnswers.owner;
1312
- repo = repoAnswers.repo;
1312
+ ]);
1313
+ owner = repoAnswers.owner;
1314
+ repo = repoAnswers.repo;
1315
+ }
1313
1316
  } else if (projectSetup === 'unknown') {
1314
1317
  // Try to detect from git
1315
1318
  if (gitInfo && gitInfo.owner && gitInfo.repo) {
@@ -1761,6 +1764,18 @@ async function main() {
1761
1764
  console.log(' (If it\'s already running, restart it to load the new configuration)');
1762
1765
  console.log('2. The commenting system will be available in your app!\n');
1763
1766
 
1767
+ // Check if placeholders were used
1768
+ const hasPlaceholders = owner === 'YOUR_GITHUB_USERNAME' || repo === 'YOUR_REPO_NAME';
1769
+
1770
+ if (hasPlaceholders) {
1771
+ console.log('⚠️ Important: Placeholder values were used for GitHub repository.');
1772
+ console.log(' The UI will work for testing, but comments won\'t sync to GitHub until you:');
1773
+ console.log(' 1. Create a GitHub repository');
1774
+ console.log(' 2. Update VITE_GITHUB_OWNER and VITE_GITHUB_REPO in .env');
1775
+ console.log(' 3. Set up GitHub OAuth (optional - for authentication)');
1776
+ console.log(' 4. Restart your dev server\n');
1777
+ }
1778
+
1764
1779
  if (!githubConfig || !jiraConfig) {
1765
1780
  console.log('📝 To add integrations later:');
1766
1781
  if (!githubConfig) {
@@ -0,0 +1,134 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const readline = require('readline');
6
+
7
+ const rl = readline.createInterface({
8
+ input: process.stdin,
9
+ output: process.stdout,
10
+ });
11
+
12
+ const prompt = (questions) => {
13
+ return new Promise((resolve) => {
14
+ const answers = {};
15
+ let currentIndex = 0;
16
+
17
+ const askNext = () => {
18
+ if (currentIndex >= questions.length) {
19
+ rl.close();
20
+ resolve(answers);
21
+ return;
22
+ }
23
+
24
+ const q = questions[currentIndex];
25
+ rl.question(q.message + ' ', (answer) => {
26
+ answers[q.name] = answer.trim();
27
+ currentIndex++;
28
+ askNext();
29
+ });
30
+ };
31
+
32
+ askNext();
33
+ });
34
+ };
35
+
36
+ console.log('\n╔════════════════════════════════════════════════════╗');
37
+ console.log('║ Hale Commenting System - Uninstall Script ║');
38
+ console.log('╚════════════════════════════════════════════════════╝\n');
39
+
40
+ console.log('⚠️ This will remove the Hale Commenting System from your project.\n');
41
+ console.log('The following changes will be reverted:');
42
+ console.log(' • Remove imports from src/app/index.tsx');
43
+ console.log(' • Remove imports from src/app/AppLayout/AppLayout.tsx');
44
+ console.log(' • Remove middleware from webpack.dev.js');
45
+ console.log(' • Keep .env and .env.server files (you can delete manually if needed)\n');
46
+
47
+ async function main() {
48
+ const confirm = await prompt([
49
+ {
50
+ name: 'proceed',
51
+ message: 'Do you want to proceed? (yes/no):',
52
+ },
53
+ ]);
54
+
55
+ if (confirm.proceed.toLowerCase() !== 'yes' && confirm.proceed.toLowerCase() !== 'y') {
56
+ console.log('\n❌ Uninstall cancelled.\n');
57
+ rl.close();
58
+ return;
59
+ }
60
+
61
+ console.log('\n🔧 Removing Hale Commenting System...\n');
62
+
63
+ // Find project root
64
+ const projectRoot = process.cwd();
65
+ let filesModified = 0;
66
+
67
+ // 1. Remove from src/app/index.tsx
68
+ const indexPath = path.join(projectRoot, 'src/app/index.tsx');
69
+ if (fs.existsSync(indexPath)) {
70
+ let content = fs.readFileSync(indexPath, 'utf8');
71
+ const originalContent = content;
72
+
73
+ // Remove the import
74
+ content = content.replace(/import\s*{\s*CommentProvider\s*,\s*GitHubAuthProvider\s*}\s*from\s*["']hale-commenting-system["'];?\s*\n?/g, '');
75
+
76
+ // Remove the providers from JSX
77
+ content = content.replace(/<GitHubAuthProvider>\s*/g, '');
78
+ content = content.replace(/<\/GitHubAuthProvider>/g, '');
79
+ content = content.replace(/<CommentProvider>\s*/g, '');
80
+ content = content.replace(/<\/CommentProvider>/g, '');
81
+
82
+ if (content !== originalContent) {
83
+ fs.writeFileSync(indexPath, content, 'utf8');
84
+ console.log('✅ Removed from src/app/index.tsx');
85
+ filesModified++;
86
+ }
87
+ }
88
+
89
+ // 2. Remove from src/app/AppLayout/AppLayout.tsx
90
+ const appLayoutPath = path.join(projectRoot, 'src/app/AppLayout/AppLayout.tsx');
91
+ if (fs.existsSync(appLayoutPath)) {
92
+ let content = fs.readFileSync(appLayoutPath, 'utf8');
93
+ const originalContent = content;
94
+
95
+ // Remove the import
96
+ content = content.replace(/import\s*{\s*CommentPanel\s*,\s*CommentOverlay\s*}\s*from\s*["']hale-commenting-system["'];?\s*\n?/g, '');
97
+
98
+ // Remove the components from JSX
99
+ content = content.replace(/<CommentPanel>\s*/g, '');
100
+ content = content.replace(/<\/CommentPanel>/g, '');
101
+ content = content.replace(/<CommentOverlay\s*\/>\s*/g, '');
102
+
103
+ if (content !== originalContent) {
104
+ fs.writeFileSync(appLayoutPath, content, 'utf8');
105
+ console.log('✅ Removed from src/app/AppLayout/AppLayout.tsx');
106
+ filesModified++;
107
+ }
108
+ }
109
+
110
+ // 3. Remove middleware from webpack.dev.js (optional - can be complex)
111
+ const webpackPath = path.join(projectRoot, 'webpack.dev.js');
112
+ if (fs.existsSync(webpackPath)) {
113
+ console.log('ℹ️ webpack.dev.js - You may want to manually remove the middleware configuration');
114
+ }
115
+
116
+ console.log('\n╔══════════════════════════════════════════════════════════╗');
117
+ console.log('║ ✅ Uninstall Complete! ║');
118
+ console.log('╚══════════════════════════════════════════════════════════╝\n');
119
+
120
+ console.log(`Modified ${filesModified} file(s)\n`);
121
+
122
+ console.log('Next steps:');
123
+ console.log('1. Run: npm uninstall hale-commenting-system');
124
+ console.log('2. Restart your dev server: npm run start:dev');
125
+ console.log('3. (Optional) Delete .env and .env.server if no longer needed\n');
126
+
127
+ rl.close();
128
+ }
129
+
130
+ main().catch((err) => {
131
+ console.error('❌ Error during uninstall:', err);
132
+ rl.close();
133
+ process.exit(1);
134
+ });
@@ -530,7 +530,13 @@ export const JiraTab: React.FunctionComponent = () => {
530
530
  const scopeLabel =
531
531
  source === 'page' ? 'This page' : source === 'section' ? `Section (${sectionRoute}/*)` : null;
532
532
  const key = record.jiraKey || '';
533
- const url = issue?.url || (process.env.VITE_JIRA_BASE_URL ? `${process.env.VITE_JIRA_BASE_URL}/browse/${key}` : '');
533
+ let jiraBaseUrl: string | undefined;
534
+ try {
535
+ jiraBaseUrl = typeof process !== 'undefined' && process.env ? process.env.VITE_JIRA_BASE_URL : undefined;
536
+ } catch (e) {
537
+ jiraBaseUrl = undefined;
538
+ }
539
+ const url = issue?.url || (jiraBaseUrl ? `${jiraBaseUrl}/browse/${key}` : '');
534
540
 
535
541
  const parsedSections = parseJiraTemplateSections(issue?.description || '');
536
542
  const byTitle = new Map(parsedSections.map((s) => [s.title, s.body]));
@@ -40,7 +40,12 @@ export const GitHubAuthProvider: React.FunctionComponent<{ children: React.React
40
40
  }, []);
41
41
 
42
42
  const login = () => {
43
- const clientId = process.env.VITE_GITHUB_CLIENT_ID;
43
+ let clientId: string | undefined;
44
+ try {
45
+ clientId = typeof process !== 'undefined' && process.env ? process.env.VITE_GITHUB_CLIENT_ID : undefined;
46
+ } catch (e) {
47
+ clientId = undefined;
48
+ }
44
49
  if (!clientId) {
45
50
  // eslint-disable-next-line no-alert
46
51
  alert('GitHub login is not configured (missing VITE_GITHUB_CLIENT_ID).');
@@ -1,3 +1,5 @@
1
+ import { getEnv } from '../utils/env';
2
+
1
3
  export interface GitHubUser {
2
4
  login: string;
3
5
  avatar: string;
@@ -31,14 +33,16 @@ export const getStoredUser = (): GitHubUser | null => {
31
33
  };
32
34
 
33
35
  export const isGitHubConfigured = (): boolean => {
34
- return Boolean(getStoredToken() && process.env.VITE_GITHUB_OWNER && process.env.VITE_GITHUB_REPO);
36
+ const owner = getEnv('VITE_GITHUB_OWNER');
37
+ const repo = getEnv('VITE_GITHUB_REPO');
38
+ return Boolean(getStoredToken() && owner && repo);
35
39
  };
36
40
 
37
41
  export const diagnoseGitHubSetup = () => {
38
42
  const token = getStoredToken();
39
43
  const user = getStoredUser();
40
- const owner = process.env.VITE_GITHUB_OWNER;
41
- const repo = process.env.VITE_GITHUB_REPO;
44
+ const owner = getEnv('VITE_GITHUB_OWNER');
45
+ const repo = getEnv('VITE_GITHUB_REPO');
42
46
 
43
47
  console.log('🔍 GitHub Configuration Diagnostic:');
44
48
  console.log(' Token:', token ? `Present (${token.substring(0, 10)}...)` : 'Missing ❌');
@@ -100,8 +104,8 @@ async function githubProxyRequest(method: string, endpoint: string, data?: any):
100
104
  4. Token has expired or been revoked
101
105
 
102
106
  Current config:
103
- - Owner: ${process.env.VITE_GITHUB_OWNER}
104
- - Repo: ${process.env.VITE_GITHUB_REPO}
107
+ - Owner: ${getEnv('VITE_GITHUB_OWNER')}
108
+ - Repo: ${getEnv('VITE_GITHUB_REPO')}
105
109
  - Endpoint: ${endpoint}
106
110
  `);
107
111
  }
@@ -153,8 +157,8 @@ export const githubAdapter = {
153
157
  }): Promise<GitHubResult<{ number: number; html_url: string }>> {
154
158
  if (!isGitHubConfigured()) return { success: false, error: 'Please sign in with GitHub' };
155
159
 
156
- const owner = process.env.VITE_GITHUB_OWNER;
157
- const repo = process.env.VITE_GITHUB_REPO;
160
+ const owner = getEnv('VITE_GITHUB_OWNER');
161
+ const repo = getEnv('VITE_GITHUB_REPO');
158
162
 
159
163
  try {
160
164
  const metadata = [
@@ -193,8 +197,8 @@ export const githubAdapter = {
193
197
 
194
198
  async createComment(issueNumber: number, body: string): Promise<GitHubResult> {
195
199
  if (!isGitHubConfigured()) return { success: false, error: 'Please sign in with GitHub' };
196
- const owner = process.env.VITE_GITHUB_OWNER;
197
- const repo = process.env.VITE_GITHUB_REPO;
200
+ const owner = getEnv('VITE_GITHUB_OWNER');
201
+ const repo = getEnv('VITE_GITHUB_REPO');
198
202
 
199
203
  try {
200
204
  const data = await githubProxyRequest('POST', `/repos/${owner}/${repo}/issues/${issueNumber}/comments`, { body });
@@ -210,8 +214,8 @@ export const githubAdapter = {
210
214
 
211
215
  async fetchIssuesForRouteAndVersion(route: string, version?: string): Promise<GitHubResult<any[]>> {
212
216
  if (!isGitHubConfigured()) return { success: false, error: 'Please sign in with GitHub' };
213
- const owner = process.env.VITE_GITHUB_OWNER;
214
- const repo = process.env.VITE_GITHUB_REPO;
217
+ const owner = getEnv('VITE_GITHUB_OWNER');
218
+ const repo = getEnv('VITE_GITHUB_REPO');
215
219
  try {
216
220
  const data = await githubProxyRequest(
217
221
  'GET',
@@ -247,8 +251,8 @@ export const githubAdapter = {
247
251
 
248
252
  async fetchIssueComments(issueNumber: number): Promise<GitHubResult<any[]>> {
249
253
  if (!isGitHubConfigured()) return { success: false, error: 'Please sign in with GitHub' };
250
- const owner = process.env.VITE_GITHUB_OWNER;
251
- const repo = process.env.VITE_GITHUB_REPO;
254
+ const owner = getEnv('VITE_GITHUB_OWNER');
255
+ const repo = getEnv('VITE_GITHUB_REPO');
252
256
  try {
253
257
  const data = await githubProxyRequest(
254
258
  'GET',
@@ -262,8 +266,8 @@ export const githubAdapter = {
262
266
 
263
267
  async updateComment(commentId: number, body: string): Promise<GitHubResult> {
264
268
  if (!isGitHubConfigured()) return { success: false, error: 'Please sign in with GitHub' };
265
- const owner = process.env.VITE_GITHUB_OWNER;
266
- const repo = process.env.VITE_GITHUB_REPO;
269
+ const owner = getEnv('VITE_GITHUB_OWNER');
270
+ const repo = getEnv('VITE_GITHUB_REPO');
267
271
  try {
268
272
  const data = await githubProxyRequest('PATCH', `/repos/${owner}/${repo}/issues/comments/${commentId}`, { body });
269
273
  return { success: true, data };
@@ -274,8 +278,8 @@ export const githubAdapter = {
274
278
 
275
279
  async deleteComment(commentId: number): Promise<GitHubResult> {
276
280
  if (!isGitHubConfigured()) return { success: false, error: 'Please sign in with GitHub' };
277
- const owner = process.env.VITE_GITHUB_OWNER;
278
- const repo = process.env.VITE_GITHUB_REPO;
281
+ const owner = getEnv('VITE_GITHUB_OWNER');
282
+ const repo = getEnv('VITE_GITHUB_REPO');
279
283
  try {
280
284
  await githubProxyRequest('DELETE', `/repos/${owner}/${repo}/issues/comments/${commentId}`);
281
285
  return { success: true, data: {} };
@@ -286,8 +290,8 @@ export const githubAdapter = {
286
290
 
287
291
  async closeIssue(issueNumber: number): Promise<GitHubResult> {
288
292
  if (!isGitHubConfigured()) return { success: false, error: 'Please sign in with GitHub' };
289
- const owner = process.env.VITE_GITHUB_OWNER;
290
- const repo = process.env.VITE_GITHUB_REPO;
293
+ const owner = getEnv('VITE_GITHUB_OWNER');
294
+ const repo = getEnv('VITE_GITHUB_REPO');
291
295
  try {
292
296
  const data = await githubProxyRequest('PATCH', `/repos/${owner}/${repo}/issues/${issueNumber}`, { state: 'closed' });
293
297
  return { success: true, data };
@@ -298,8 +302,8 @@ export const githubAdapter = {
298
302
 
299
303
  async reopenIssue(issueNumber: number): Promise<GitHubResult> {
300
304
  if (!isGitHubConfigured()) return { success: false, error: 'Please sign in with GitHub' };
301
- const owner = process.env.VITE_GITHUB_OWNER;
302
- const repo = process.env.VITE_GITHUB_REPO;
305
+ const owner = getEnv('VITE_GITHUB_OWNER');
306
+ const repo = getEnv('VITE_GITHUB_REPO');
303
307
  try {
304
308
  const data = await githubProxyRequest('PATCH', `/repos/${owner}/${repo}/issues/${issueNumber}`, { state: 'open' });
305
309
  return { success: true, data };
@@ -310,8 +314,8 @@ export const githubAdapter = {
310
314
 
311
315
  async getRepoFile(path: string): Promise<GitHubResult<{ text: string; sha: string } | null>> {
312
316
  if (!isGitHubConfigured()) return { success: false, error: 'Please sign in with GitHub' };
313
- const owner = process.env.VITE_GITHUB_OWNER;
314
- const repo = process.env.VITE_GITHUB_REPO;
317
+ const owner = getEnv('VITE_GITHUB_OWNER');
318
+ const repo = getEnv('VITE_GITHUB_REPO');
315
319
  try {
316
320
  const data = await githubProxyRequest('GET', `/repos/${owner}/${repo}/contents/${encodePath(path)}`);
317
321
  const content = typeof data?.content === 'string' ? data.content.replace(/\n/g, '') : '';
@@ -335,8 +339,8 @@ export const githubAdapter = {
335
339
  sha?: string;
336
340
  }): Promise<GitHubResult<{ sha: string }>> {
337
341
  if (!isGitHubConfigured()) return { success: false, error: 'Please sign in with GitHub' };
338
- const owner = process.env.VITE_GITHUB_OWNER;
339
- const repo = process.env.VITE_GITHUB_REPO;
342
+ const owner = getEnv('VITE_GITHUB_OWNER');
343
+ const repo = getEnv('VITE_GITHUB_REPO');
340
344
  try {
341
345
  const payload: any = {
342
346
  message: params.message,
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Safely access environment variables
3
+ * Returns undefined if process or env vars are not available
4
+ */
5
+ export const getEnv = (key: string): string | undefined => {
6
+ // Check if running in an environment with process.env (webpack with DefinePlugin or similar)
7
+ try {
8
+ if (typeof process !== 'undefined' && process.env) {
9
+ return process.env[key];
10
+ }
11
+ } catch (e) {
12
+ // process might be defined but accessing it throws an error
13
+ }
14
+ return undefined;
15
+ };