projax 3.3.39 → 3.3.41

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 (70) hide show
  1. package/dist/api/database.d.ts +12 -1
  2. package/dist/api/database.d.ts.map +1 -1
  3. package/dist/api/database.js +139 -1
  4. package/dist/api/database.js.map +1 -1
  5. package/dist/api/index.d.ts.map +1 -1
  6. package/dist/api/index.js +8 -0
  7. package/dist/api/index.js.map +1 -1
  8. package/dist/api/routes/backup.d.ts +3 -0
  9. package/dist/api/routes/backup.d.ts.map +1 -0
  10. package/dist/api/routes/backup.js +51 -0
  11. package/dist/api/routes/backup.js.map +1 -0
  12. package/dist/api/routes/index.d.ts.map +1 -1
  13. package/dist/api/routes/index.js +4 -0
  14. package/dist/api/routes/index.js.map +1 -1
  15. package/dist/api/routes/mcp.d.ts +3 -0
  16. package/dist/api/routes/mcp.d.ts.map +1 -0
  17. package/dist/api/routes/mcp.js +147 -0
  18. package/dist/api/routes/mcp.js.map +1 -0
  19. package/dist/api/routes/projects.d.ts.map +1 -1
  20. package/dist/api/routes/projects.js +20 -0
  21. package/dist/api/routes/projects.js.map +1 -1
  22. package/dist/api/routes/settings.d.ts.map +1 -1
  23. package/dist/api/routes/settings.js +64 -11
  24. package/dist/api/routes/settings.js.map +1 -1
  25. package/dist/api/routes/workspaces.d.ts +3 -0
  26. package/dist/api/routes/workspaces.d.ts.map +1 -0
  27. package/dist/api/routes/workspaces.js +429 -0
  28. package/dist/api/routes/workspaces.js.map +1 -0
  29. package/dist/api/types.d.ts +26 -0
  30. package/dist/api/types.d.ts.map +1 -1
  31. package/dist/core/backup-utils.d.ts +17 -0
  32. package/dist/core/backup-utils.js +166 -0
  33. package/dist/core/database.d.ts +1 -0
  34. package/dist/core/git-utils.d.ts +12 -0
  35. package/dist/core/git-utils.js +96 -0
  36. package/dist/core/index.d.ts +3 -0
  37. package/dist/core/index.js +3 -0
  38. package/dist/core/workspace-utils.d.ts +37 -0
  39. package/dist/core/workspace-utils.js +152 -0
  40. package/dist/electron/core/backup-utils.d.ts +17 -0
  41. package/dist/electron/core/backup-utils.js +166 -0
  42. package/dist/electron/core/database.d.ts +1 -0
  43. package/dist/electron/core/git-utils.d.ts +12 -0
  44. package/dist/electron/core/git-utils.js +96 -0
  45. package/dist/electron/core/index.d.ts +3 -0
  46. package/dist/electron/core/index.js +3 -0
  47. package/dist/electron/core/workspace-utils.d.ts +37 -0
  48. package/dist/electron/core/workspace-utils.js +152 -0
  49. package/dist/electron/main.js +324 -9
  50. package/dist/electron/preload.d.ts +14 -0
  51. package/dist/electron/preload.js +9 -0
  52. package/dist/electron/renderer/assets/index-B-etDnj2.js +64 -0
  53. package/dist/electron/renderer/assets/index-Bx18Cyic.js +64 -0
  54. package/dist/electron/renderer/assets/index-C8f5yNYe.js +64 -0
  55. package/dist/electron/renderer/assets/index-CIZ3Wl6c.css +1 -0
  56. package/dist/electron/renderer/assets/index-CJbsU9y8.css +1 -0
  57. package/dist/electron/renderer/assets/index-CWxXs5M7.css +1 -0
  58. package/dist/electron/renderer/assets/index-CopVNRnR.js +64 -0
  59. package/dist/electron/renderer/assets/index-CtXtIMer.js +64 -0
  60. package/dist/electron/renderer/assets/index-DUvcepWm.js +64 -0
  61. package/dist/electron/renderer/assets/index-DWe2TQFv.css +1 -0
  62. package/dist/electron/renderer/assets/index-DZzB20Xf.css +1 -0
  63. package/dist/electron/renderer/assets/index-DknLdADV.js +63 -0
  64. package/dist/electron/renderer/assets/index-DocuD8Lk.js +64 -0
  65. package/dist/electron/renderer/assets/index-DyU-xfd8.css +1 -0
  66. package/dist/electron/renderer/assets/index-GwC-JVUy.css +1 -0
  67. package/dist/electron/renderer/assets/index-fehviker.js +63 -0
  68. package/dist/electron/renderer/index.html +2 -2
  69. package/dist/index.js +281 -4
  70. package/package.json +1 -1
@@ -7,6 +7,7 @@ export interface Project {
7
7
  last_scanned: number | null;
8
8
  created_at: number;
9
9
  tags?: string[];
10
+ git_branch?: string | null;
10
11
  }
11
12
  export interface Test {
12
13
  id: number;
@@ -50,6 +51,28 @@ export interface TestResult {
50
51
  timestamp: number;
51
52
  raw_output: string | null;
52
53
  }
54
+ export interface Workspace {
55
+ id: number;
56
+ name: string;
57
+ workspace_file_path: string;
58
+ description: string | null;
59
+ tags?: string[];
60
+ created_at: number;
61
+ last_opened: number | null;
62
+ }
63
+ export interface WorkspaceProject {
64
+ id: number;
65
+ workspace_id: number;
66
+ project_path: string;
67
+ order: number;
68
+ created_at: number;
69
+ }
70
+ export interface ProjectSettings {
71
+ id: number;
72
+ project_id: number;
73
+ script_sort_order: 'default' | 'alphabetical' | 'last-used';
74
+ updated_at: number;
75
+ }
53
76
  export interface DatabaseSchema {
54
77
  projects: Project[];
55
78
  tests: Test[];
@@ -61,5 +84,8 @@ export interface DatabaseSchema {
61
84
  value: string;
62
85
  updated_at: number;
63
86
  }>;
87
+ workspaces: Workspace[];
88
+ workspace_projects: WorkspaceProject[];
89
+ project_settings: ProjectSettings[];
64
90
  }
65
91
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,YAAY,EAAE,UAAU,EAAE,CAAC;IAC3B,aAAa,EAAE,WAAW,EAAE,CAAC;IAC7B,YAAY,EAAE,UAAU,EAAE,CAAC;IAC3B,QAAQ,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrE"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Create a backup of the PROJAX database
3
+ * @param outputPath Directory where the backup should be created
4
+ * @returns Path to the created backup file
5
+ */
6
+ export declare function createBackup(outputPath: string): Promise<string>;
7
+ /**
8
+ * Restore PROJAX database from a backup file
9
+ * @param backupPath Path to the .pbz backup file
10
+ */
11
+ export declare function restoreBackup(backupPath: string): Promise<void>;
12
+ /**
13
+ * Validate a backup file without restoring
14
+ * @param backupPath Path to the .pbz backup file
15
+ * @returns true if valid, throws error if invalid
16
+ */
17
+ export declare function validateBackup(backupPath: string): Promise<boolean>;
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.createBackup = createBackup;
37
+ exports.restoreBackup = restoreBackup;
38
+ exports.validateBackup = validateBackup;
39
+ const fs = __importStar(require("fs"));
40
+ const path = __importStar(require("path"));
41
+ const os = __importStar(require("os"));
42
+ /**
43
+ * Create a backup of the PROJAX database
44
+ * @param outputPath Directory where the backup should be created
45
+ * @returns Path to the created backup file
46
+ */
47
+ async function createBackup(outputPath) {
48
+ const dataDir = path.join(os.homedir(), '.projax');
49
+ const dbPath = path.join(dataDir, 'data.json');
50
+ if (!fs.existsSync(dbPath)) {
51
+ throw new Error('PROJAX database not found');
52
+ }
53
+ // Generate timestamped filename
54
+ const now = new Date();
55
+ const timestamp = now.toISOString().replace(/[:.]/g, '-').slice(0, 19); // YYYY-MM-DDTHHmmss
56
+ const filename = `projax-backup-${timestamp}.pbz`;
57
+ const backupPath = path.join(outputPath, filename);
58
+ // Ensure output directory exists
59
+ if (!fs.existsSync(outputPath)) {
60
+ fs.mkdirSync(outputPath, { recursive: true });
61
+ }
62
+ // Read database file
63
+ const dbContent = fs.readFileSync(dbPath, 'utf-8');
64
+ // Create metadata
65
+ const metadata = {
66
+ version: '1.0',
67
+ timestamp: Math.floor(Date.now() / 1000),
68
+ projax_version: '3.4.0', // This should ideally come from package.json
69
+ created_at: now.toISOString(),
70
+ };
71
+ // Create ZIP-like structure manually (simple approach)
72
+ // For a proper ZIP, we'd use a library like adm-zip or archiver
73
+ // For now, we'll create a simple JSON structure that can be restored
74
+ const backupData = {
75
+ metadata,
76
+ data: JSON.parse(dbContent),
77
+ };
78
+ // Write backup file
79
+ fs.writeFileSync(backupPath, JSON.stringify(backupData, null, 2), 'utf-8');
80
+ return backupPath;
81
+ }
82
+ /**
83
+ * Restore PROJAX database from a backup file
84
+ * @param backupPath Path to the .pbz backup file
85
+ */
86
+ async function restoreBackup(backupPath) {
87
+ if (!fs.existsSync(backupPath)) {
88
+ throw new Error(`Backup file not found: ${backupPath}`);
89
+ }
90
+ if (!backupPath.endsWith('.pbz')) {
91
+ throw new Error('Invalid backup file extension. Expected .pbz');
92
+ }
93
+ // Read and parse backup file
94
+ let backupContent;
95
+ try {
96
+ const content = fs.readFileSync(backupPath, 'utf-8');
97
+ backupContent = JSON.parse(content);
98
+ }
99
+ catch (error) {
100
+ if (error instanceof SyntaxError) {
101
+ throw new Error(`Invalid backup file format: ${error.message}`);
102
+ }
103
+ throw new Error(`Failed to read backup file: ${error instanceof Error ? error.message : 'Unknown error'}`);
104
+ }
105
+ // Validate backup structure
106
+ if (!backupContent.metadata || !backupContent.data) {
107
+ throw new Error('Invalid backup file structure: missing metadata or data');
108
+ }
109
+ // Validate metadata
110
+ const metadata = backupContent.metadata;
111
+ if (!metadata.version || !metadata.timestamp) {
112
+ throw new Error('Invalid backup metadata');
113
+ }
114
+ // Validate data structure (basic check)
115
+ if (typeof backupContent.data !== 'object' || !Array.isArray(backupContent.data.projects)) {
116
+ throw new Error('Invalid backup data structure');
117
+ }
118
+ // Create backup of current database before restoring
119
+ const dataDir = path.join(os.homedir(), '.projax');
120
+ const dbPath = path.join(dataDir, 'data.json');
121
+ if (fs.existsSync(dbPath)) {
122
+ const backupTimestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
123
+ const currentBackupPath = path.join(dataDir, `data.backup-${backupTimestamp}.json`);
124
+ fs.copyFileSync(dbPath, currentBackupPath);
125
+ }
126
+ // Ensure data directory exists
127
+ if (!fs.existsSync(dataDir)) {
128
+ fs.mkdirSync(dataDir, { recursive: true });
129
+ }
130
+ // Write restored data
131
+ fs.writeFileSync(dbPath, JSON.stringify(backupContent.data, null, 2), 'utf-8');
132
+ }
133
+ /**
134
+ * Validate a backup file without restoring
135
+ * @param backupPath Path to the .pbz backup file
136
+ * @returns true if valid, throws error if invalid
137
+ */
138
+ async function validateBackup(backupPath) {
139
+ if (!fs.existsSync(backupPath)) {
140
+ throw new Error(`Backup file not found: ${backupPath}`);
141
+ }
142
+ if (!backupPath.endsWith('.pbz')) {
143
+ throw new Error('Invalid backup file extension. Expected .pbz');
144
+ }
145
+ try {
146
+ const content = fs.readFileSync(backupPath, 'utf-8');
147
+ const backupContent = JSON.parse(content);
148
+ if (!backupContent.metadata || !backupContent.data) {
149
+ throw new Error('Invalid backup file structure');
150
+ }
151
+ const metadata = backupContent.metadata;
152
+ if (!metadata.version || !metadata.timestamp) {
153
+ throw new Error('Invalid backup metadata');
154
+ }
155
+ if (typeof backupContent.data !== 'object' || !Array.isArray(backupContent.data.projects)) {
156
+ throw new Error('Invalid backup data structure');
157
+ }
158
+ return true;
159
+ }
160
+ catch (error) {
161
+ if (error instanceof SyntaxError) {
162
+ throw new Error(`Invalid JSON in backup file: ${error.message}`);
163
+ }
164
+ throw error;
165
+ }
166
+ }
@@ -7,6 +7,7 @@ export interface Project {
7
7
  last_scanned: number | null;
8
8
  created_at: number;
9
9
  tags?: string[];
10
+ git_branch?: string | null;
10
11
  }
11
12
  export interface Test {
12
13
  id: number;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Get the current git branch for a project
3
+ * @param projectPath The path to the project directory
4
+ * @returns The current branch name, or null if not a git repo or on error
5
+ */
6
+ export declare function getCurrentBranch(projectPath: string): string | null;
7
+ /**
8
+ * Get git branches for multiple projects
9
+ * @param projectPaths Array of project paths
10
+ * @returns Map of project path to branch name (or null)
11
+ */
12
+ export declare function getBranchesForProjects(projectPaths: string[]): Map<string, string | null>;
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.getCurrentBranch = getCurrentBranch;
37
+ exports.getBranchesForProjects = getBranchesForProjects;
38
+ const child_process_1 = require("child_process");
39
+ const fs = __importStar(require("fs"));
40
+ const path = __importStar(require("path"));
41
+ /**
42
+ * Get the current git branch for a project
43
+ * @param projectPath The path to the project directory
44
+ * @returns The current branch name, or null if not a git repo or on error
45
+ */
46
+ function getCurrentBranch(projectPath) {
47
+ try {
48
+ // Check if .git directory exists
49
+ const gitDir = path.join(projectPath, '.git');
50
+ if (!fs.existsSync(gitDir) && !fs.existsSync(path.join(projectPath, '.git', 'HEAD'))) {
51
+ // Check if it's a worktree or submodule
52
+ const gitConfig = path.join(projectPath, '.git');
53
+ if (!fs.existsSync(gitConfig)) {
54
+ return null;
55
+ }
56
+ }
57
+ // Try to get the current branch
58
+ const branch = (0, child_process_1.execSync)('git rev-parse --abbrev-ref HEAD', {
59
+ cwd: projectPath,
60
+ encoding: 'utf-8',
61
+ stdio: ['pipe', 'pipe', 'pipe'],
62
+ }).trim();
63
+ // Handle detached HEAD state (returns "HEAD")
64
+ if (branch === 'HEAD') {
65
+ // Try to get the commit hash instead
66
+ try {
67
+ const commit = (0, child_process_1.execSync)('git rev-parse --short HEAD', {
68
+ cwd: projectPath,
69
+ encoding: 'utf-8',
70
+ stdio: ['pipe', 'pipe', 'pipe'],
71
+ }).trim();
72
+ return `detached@${commit}`;
73
+ }
74
+ catch {
75
+ return 'detached';
76
+ }
77
+ }
78
+ return branch || null;
79
+ }
80
+ catch (error) {
81
+ // Not a git repo, or git command failed
82
+ return null;
83
+ }
84
+ }
85
+ /**
86
+ * Get git branches for multiple projects
87
+ * @param projectPaths Array of project paths
88
+ * @returns Map of project path to branch name (or null)
89
+ */
90
+ function getBranchesForProjects(projectPaths) {
91
+ const branches = new Map();
92
+ for (const projectPath of projectPaths) {
93
+ branches.set(projectPath, getCurrentBranch(projectPath));
94
+ }
95
+ return branches;
96
+ }
@@ -2,6 +2,9 @@ export * from './database';
2
2
  export * from './detector';
3
3
  export * from './scanner';
4
4
  export * from './settings';
5
+ export * from './git-utils';
6
+ export * from './workspace-utils';
7
+ export * from './backup-utils';
5
8
  export { getDatabaseManager } from './database';
6
9
  import { Project, Test } from './database';
7
10
  export declare function getAllProjects(): Project[];
@@ -23,6 +23,9 @@ __exportStar(require("./database"), exports);
23
23
  __exportStar(require("./detector"), exports);
24
24
  __exportStar(require("./scanner"), exports);
25
25
  __exportStar(require("./settings"), exports);
26
+ __exportStar(require("./git-utils"), exports);
27
+ __exportStar(require("./workspace-utils"), exports);
28
+ __exportStar(require("./backup-utils"), exports);
26
29
  var database_1 = require("./database");
27
30
  Object.defineProperty(exports, "getDatabaseManager", { enumerable: true, get: function () { return database_1.getDatabaseManager; } });
28
31
  // Convenience functions for common operations
@@ -0,0 +1,37 @@
1
+ export interface WorkspaceFolder {
2
+ path: string;
3
+ name?: string;
4
+ }
5
+ export interface WorkspaceSettings {
6
+ [key: string]: any;
7
+ }
8
+ export interface WorkspaceExtensions {
9
+ recommendations?: string[];
10
+ unwantedRecommendations?: string[];
11
+ }
12
+ export interface ParsedWorkspace {
13
+ folders: WorkspaceFolder[];
14
+ settings?: WorkspaceSettings;
15
+ extensions?: WorkspaceExtensions;
16
+ }
17
+ /**
18
+ * Parse a .code-workspace file
19
+ * @param filePath Path to the .code-workspace file
20
+ * @returns Parsed workspace structure
21
+ */
22
+ export declare function parseWorkspaceFile(filePath: string): ParsedWorkspace;
23
+ /**
24
+ * Generate a .code-workspace file
25
+ * @param workspaceName Name of the workspace (used in comments)
26
+ * @param projects Array of project paths (absolute or relative)
27
+ * @param outputPath Path where the .code-workspace file should be created
28
+ * @param settings Optional workspace settings
29
+ * @param extensions Optional workspace extensions recommendations
30
+ */
31
+ export declare function generateWorkspaceFile(workspaceName: string, projects: string[], outputPath: string, settings?: WorkspaceSettings, extensions?: WorkspaceExtensions): void;
32
+ /**
33
+ * Validate that a path is a valid workspace file
34
+ * @param filePath Path to check
35
+ * @returns true if the path exists and is a valid .code-workspace file
36
+ */
37
+ export declare function validateWorkspacePath(filePath: string): boolean;
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.parseWorkspaceFile = parseWorkspaceFile;
37
+ exports.generateWorkspaceFile = generateWorkspaceFile;
38
+ exports.validateWorkspacePath = validateWorkspacePath;
39
+ const fs = __importStar(require("fs"));
40
+ const path = __importStar(require("path"));
41
+ /**
42
+ * Parse a .code-workspace file
43
+ * @param filePath Path to the .code-workspace file
44
+ * @returns Parsed workspace structure
45
+ */
46
+ function parseWorkspaceFile(filePath) {
47
+ if (!fs.existsSync(filePath)) {
48
+ throw new Error(`Workspace file not found: ${filePath}`);
49
+ }
50
+ try {
51
+ const content = fs.readFileSync(filePath, 'utf-8');
52
+ const workspace = JSON.parse(content);
53
+ // Validate structure
54
+ if (!workspace.folders || !Array.isArray(workspace.folders)) {
55
+ throw new Error('Invalid workspace file: missing or invalid folders array');
56
+ }
57
+ // Normalize folder paths to absolute paths
58
+ const workspaceDir = path.dirname(filePath);
59
+ workspace.folders = workspace.folders.map(folder => {
60
+ if (typeof folder === 'string') {
61
+ // Legacy format: folders can be strings
62
+ const absolutePath = path.isAbsolute(folder)
63
+ ? folder
64
+ : path.resolve(workspaceDir, folder);
65
+ return { path: absolutePath };
66
+ }
67
+ else {
68
+ // Modern format: folders are objects with path property
69
+ const absolutePath = path.isAbsolute(folder.path)
70
+ ? folder.path
71
+ : path.resolve(workspaceDir, folder.path);
72
+ return {
73
+ ...folder,
74
+ path: absolutePath,
75
+ };
76
+ }
77
+ });
78
+ return workspace;
79
+ }
80
+ catch (error) {
81
+ if (error instanceof SyntaxError) {
82
+ throw new Error(`Invalid JSON in workspace file: ${error.message}`);
83
+ }
84
+ throw error;
85
+ }
86
+ }
87
+ /**
88
+ * Generate a .code-workspace file
89
+ * @param workspaceName Name of the workspace (used in comments)
90
+ * @param projects Array of project paths (absolute or relative)
91
+ * @param outputPath Path where the .code-workspace file should be created
92
+ * @param settings Optional workspace settings
93
+ * @param extensions Optional workspace extensions recommendations
94
+ */
95
+ function generateWorkspaceFile(workspaceName, projects, outputPath, settings, extensions) {
96
+ const workspaceDir = path.dirname(outputPath);
97
+ // Convert project paths to relative paths if they're within the workspace directory
98
+ const folders = projects.map(projectPath => {
99
+ const absolutePath = path.isAbsolute(projectPath)
100
+ ? projectPath
101
+ : path.resolve(process.cwd(), projectPath);
102
+ // Try to make path relative to workspace directory if possible
103
+ let relativePath;
104
+ try {
105
+ relativePath = path.relative(workspaceDir, absolutePath);
106
+ // If relative path goes outside workspace dir, use absolute
107
+ if (relativePath.startsWith('..')) {
108
+ relativePath = absolutePath;
109
+ }
110
+ }
111
+ catch {
112
+ relativePath = absolutePath;
113
+ }
114
+ return {
115
+ path: relativePath,
116
+ };
117
+ });
118
+ const workspace = {
119
+ folders,
120
+ ...(settings && { settings }),
121
+ ...(extensions && { extensions }),
122
+ };
123
+ // Add comment header
124
+ const content = JSON.stringify(workspace, null, 2);
125
+ const withHeader = `// ${workspaceName} Workspace\n${content}`;
126
+ // Ensure output directory exists
127
+ const outputDir = path.dirname(outputPath);
128
+ if (!fs.existsSync(outputDir)) {
129
+ fs.mkdirSync(outputDir, { recursive: true });
130
+ }
131
+ fs.writeFileSync(outputPath, withHeader, 'utf-8');
132
+ }
133
+ /**
134
+ * Validate that a path is a valid workspace file
135
+ * @param filePath Path to check
136
+ * @returns true if the path exists and is a valid .code-workspace file
137
+ */
138
+ function validateWorkspacePath(filePath) {
139
+ if (!fs.existsSync(filePath)) {
140
+ return false;
141
+ }
142
+ if (!filePath.endsWith('.code-workspace')) {
143
+ return false;
144
+ }
145
+ try {
146
+ parseWorkspaceFile(filePath);
147
+ return true;
148
+ }
149
+ catch {
150
+ return false;
151
+ }
152
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Create a backup of the PROJAX database
3
+ * @param outputPath Directory where the backup should be created
4
+ * @returns Path to the created backup file
5
+ */
6
+ export declare function createBackup(outputPath: string): Promise<string>;
7
+ /**
8
+ * Restore PROJAX database from a backup file
9
+ * @param backupPath Path to the .pbz backup file
10
+ */
11
+ export declare function restoreBackup(backupPath: string): Promise<void>;
12
+ /**
13
+ * Validate a backup file without restoring
14
+ * @param backupPath Path to the .pbz backup file
15
+ * @returns true if valid, throws error if invalid
16
+ */
17
+ export declare function validateBackup(backupPath: string): Promise<boolean>;