envmatic 1.0.0

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 (102) hide show
  1. package/README.md +567 -0
  2. package/dist/cli.d.ts +7 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +203 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/add.d.ts +11 -0
  7. package/dist/commands/add.d.ts.map +1 -0
  8. package/dist/commands/add.js +77 -0
  9. package/dist/commands/add.js.map +1 -0
  10. package/dist/commands/delete.d.ts +6 -0
  11. package/dist/commands/delete.d.ts.map +1 -0
  12. package/dist/commands/delete.js +78 -0
  13. package/dist/commands/delete.js.map +1 -0
  14. package/dist/commands/edit.d.ts +13 -0
  15. package/dist/commands/edit.d.ts.map +1 -0
  16. package/dist/commands/edit.js +364 -0
  17. package/dist/commands/edit.js.map +1 -0
  18. package/dist/commands/import.d.ts +11 -0
  19. package/dist/commands/import.d.ts.map +1 -0
  20. package/dist/commands/import.js +103 -0
  21. package/dist/commands/import.js.map +1 -0
  22. package/dist/commands/init.d.ts +8 -0
  23. package/dist/commands/init.d.ts.map +1 -0
  24. package/dist/commands/init.js +237 -0
  25. package/dist/commands/init.js.map +1 -0
  26. package/dist/commands/link.d.ts +16 -0
  27. package/dist/commands/link.d.ts.map +1 -0
  28. package/dist/commands/link.js +157 -0
  29. package/dist/commands/link.js.map +1 -0
  30. package/dist/commands/list.d.ts +9 -0
  31. package/dist/commands/list.d.ts.map +1 -0
  32. package/dist/commands/list.js +73 -0
  33. package/dist/commands/list.js.map +1 -0
  34. package/dist/commands/lock.d.ts +16 -0
  35. package/dist/commands/lock.d.ts.map +1 -0
  36. package/dist/commands/lock.js +245 -0
  37. package/dist/commands/lock.js.map +1 -0
  38. package/dist/commands/rotate.d.ts +15 -0
  39. package/dist/commands/rotate.d.ts.map +1 -0
  40. package/dist/commands/rotate.js +406 -0
  41. package/dist/commands/rotate.js.map +1 -0
  42. package/dist/commands/show.d.ts +9 -0
  43. package/dist/commands/show.d.ts.map +1 -0
  44. package/dist/commands/show.js +72 -0
  45. package/dist/commands/show.js.map +1 -0
  46. package/dist/commands/sync.d.ts +13 -0
  47. package/dist/commands/sync.d.ts.map +1 -0
  48. package/dist/commands/sync.js +174 -0
  49. package/dist/commands/sync.js.map +1 -0
  50. package/dist/commands/use.d.ts +19 -0
  51. package/dist/commands/use.d.ts.map +1 -0
  52. package/dist/commands/use.js +238 -0
  53. package/dist/commands/use.js.map +1 -0
  54. package/dist/constants.d.ts +20 -0
  55. package/dist/constants.d.ts.map +1 -0
  56. package/dist/constants.js +47 -0
  57. package/dist/constants.js.map +1 -0
  58. package/dist/index.d.ts +15 -0
  59. package/dist/index.d.ts.map +1 -0
  60. package/dist/index.js +21 -0
  61. package/dist/index.js.map +1 -0
  62. package/dist/services/config.d.ts +64 -0
  63. package/dist/services/config.d.ts.map +1 -0
  64. package/dist/services/config.js +133 -0
  65. package/dist/services/config.js.map +1 -0
  66. package/dist/services/encryption.d.ts +30 -0
  67. package/dist/services/encryption.d.ts.map +1 -0
  68. package/dist/services/encryption.js +146 -0
  69. package/dist/services/encryption.js.map +1 -0
  70. package/dist/services/envfile.d.ts +76 -0
  71. package/dist/services/envfile.d.ts.map +1 -0
  72. package/dist/services/envfile.js +247 -0
  73. package/dist/services/envfile.js.map +1 -0
  74. package/dist/services/git.d.ts +60 -0
  75. package/dist/services/git.d.ts.map +1 -0
  76. package/dist/services/git.js +239 -0
  77. package/dist/services/git.js.map +1 -0
  78. package/dist/services/linker.d.ts +46 -0
  79. package/dist/services/linker.d.ts.map +1 -0
  80. package/dist/services/linker.js +222 -0
  81. package/dist/services/linker.js.map +1 -0
  82. package/dist/services/protection.d.ts +32 -0
  83. package/dist/services/protection.d.ts.map +1 -0
  84. package/dist/services/protection.js +190 -0
  85. package/dist/services/protection.js.map +1 -0
  86. package/dist/types/index.d.ts +73 -0
  87. package/dist/types/index.d.ts.map +1 -0
  88. package/dist/types/index.js +5 -0
  89. package/dist/types/index.js.map +1 -0
  90. package/dist/utils/display.d.ts +74 -0
  91. package/dist/utils/display.d.ts.map +1 -0
  92. package/dist/utils/display.js +138 -0
  93. package/dist/utils/display.js.map +1 -0
  94. package/dist/utils/editor.d.ts +22 -0
  95. package/dist/utils/editor.d.ts.map +1 -0
  96. package/dist/utils/editor.js +159 -0
  97. package/dist/utils/editor.js.map +1 -0
  98. package/dist/utils/prompts.d.ts +41 -0
  99. package/dist/utils/prompts.d.ts.map +1 -0
  100. package/dist/utils/prompts.js +222 -0
  101. package/dist/utils/prompts.js.map +1 -0
  102. package/package.json +69 -0
@@ -0,0 +1,247 @@
1
+ /**
2
+ * Env File Service
3
+ * Manages .env files in the vault
4
+ */
5
+ import fs from 'fs-extra';
6
+ import path from 'path';
7
+ import { parse as parseDotenv } from 'dotenv';
8
+ import { VAULT_PATH, ENCRYPTED_EXT } from '../constants.js';
9
+ import { encrypt, decrypt } from './encryption.js';
10
+ import { getManifest, saveManifest, commitChanges } from './git.js';
11
+ import { getConfig } from './config.js';
12
+ /**
13
+ * Generate file ID from project and environment
14
+ */
15
+ export function generateFileId(project, environment, name = '.env') {
16
+ return `${project}/${environment}/${name}`;
17
+ }
18
+ /**
19
+ * Get the full path for an env file in the vault
20
+ */
21
+ export function getEnvFilePath(fileId, encrypted = false) {
22
+ const ext = encrypted ? ENCRYPTED_EXT : '';
23
+ return path.join(VAULT_PATH, fileId + ext);
24
+ }
25
+ /**
26
+ * Parse .env content to key-value pairs
27
+ */
28
+ export function parseEnvContent(content) {
29
+ // Use dotenv parser
30
+ const parsed = parseDotenv(Buffer.from(content));
31
+ return parsed;
32
+ }
33
+ /**
34
+ * Serialize key-value pairs to .env format
35
+ */
36
+ export function serializeEnvContent(variables) {
37
+ const lines = [];
38
+ for (const [key, value] of Object.entries(variables)) {
39
+ // Quote values that contain special characters
40
+ const needsQuotes = value.includes(' ') ||
41
+ value.includes('#') ||
42
+ value.includes('\n') ||
43
+ value.includes('"') ||
44
+ value.includes("'");
45
+ if (needsQuotes) {
46
+ // Escape double quotes and use double quotes
47
+ const escaped = value.replace(/"/g, '\\"').replace(/\n/g, '\\n');
48
+ lines.push(`${key}="${escaped}"`);
49
+ }
50
+ else {
51
+ lines.push(`${key}=${value}`);
52
+ }
53
+ }
54
+ return lines.join('\n') + '\n';
55
+ }
56
+ /**
57
+ * Create a new env file
58
+ */
59
+ export async function createEnvFile(project, environment, variables, options = {}) {
60
+ const config = await getConfig();
61
+ if (!config) {
62
+ throw new Error('Envmatic not configured. Run `envmatic init` first.');
63
+ }
64
+ const name = options.name || '.env';
65
+ const fileId = generateFileId(project, environment, name);
66
+ const encrypted = config.encryptionEnabled && !!options.encryptionOptions;
67
+ const filePath = getEnvFilePath(fileId, encrypted);
68
+ // Ensure directory exists
69
+ await fs.ensureDir(path.dirname(filePath));
70
+ // Serialize content
71
+ let content = serializeEnvContent(variables);
72
+ // Encrypt if needed
73
+ if (encrypted && options.encryptionOptions) {
74
+ content = await encrypt(content, options.encryptionOptions);
75
+ }
76
+ // Write file
77
+ await fs.writeFile(filePath, content);
78
+ // Create metadata
79
+ const now = new Date().toISOString();
80
+ const envFile = {
81
+ id: fileId,
82
+ name,
83
+ project,
84
+ environment,
85
+ description: options.description,
86
+ createdAt: now,
87
+ updatedAt: now,
88
+ encrypted,
89
+ immutable: options.immutable ?? config.immutableByDefault,
90
+ };
91
+ // Update manifest
92
+ const manifest = await getManifest();
93
+ // Add project if new
94
+ if (!manifest.projects.includes(project)) {
95
+ manifest.projects.push(project);
96
+ }
97
+ // Add or update file entry
98
+ const existingIndex = manifest.files.findIndex(f => f.id === fileId);
99
+ if (existingIndex >= 0) {
100
+ manifest.files[existingIndex] = envFile;
101
+ }
102
+ else {
103
+ manifest.files.push(envFile);
104
+ }
105
+ await saveManifest(manifest);
106
+ // Commit changes
107
+ await commitChanges(`Add ${project}/${environment}/${name}`);
108
+ return envFile;
109
+ }
110
+ /**
111
+ * Read an env file
112
+ */
113
+ export async function readEnvFile(fileId, encryptionOptions) {
114
+ const manifest = await getManifest();
115
+ const metadata = manifest.files.find(f => f.id === fileId);
116
+ if (!metadata) {
117
+ throw new Error(`Env file not found: ${fileId}`);
118
+ }
119
+ const filePath = getEnvFilePath(fileId, metadata.encrypted);
120
+ if (!(await fs.pathExists(filePath))) {
121
+ throw new Error(`Env file not found on disk: ${filePath}`);
122
+ }
123
+ let content = await fs.readFile(filePath, 'utf-8');
124
+ // Decrypt if needed
125
+ if (metadata.encrypted) {
126
+ if (!encryptionOptions) {
127
+ throw new Error('Encryption options required to read encrypted file');
128
+ }
129
+ content = await decrypt(content, encryptionOptions);
130
+ }
131
+ const variables = parseEnvContent(content);
132
+ return {
133
+ metadata,
134
+ variables,
135
+ };
136
+ }
137
+ /**
138
+ * Update an env file
139
+ */
140
+ export async function updateEnvFile(fileId, variables, encryptionOptions) {
141
+ const manifest = await getManifest();
142
+ const metadataIndex = manifest.files.findIndex(f => f.id === fileId);
143
+ if (metadataIndex < 0) {
144
+ throw new Error(`Env file not found: ${fileId}`);
145
+ }
146
+ const metadata = manifest.files[metadataIndex];
147
+ const filePath = getEnvFilePath(fileId, metadata.encrypted);
148
+ // Serialize content
149
+ let content = serializeEnvContent(variables);
150
+ // Encrypt if needed
151
+ if (metadata.encrypted) {
152
+ if (!encryptionOptions) {
153
+ throw new Error('Encryption options required to update encrypted file');
154
+ }
155
+ content = await encrypt(content, encryptionOptions);
156
+ }
157
+ // Write file
158
+ await fs.writeFile(filePath, content);
159
+ // Update metadata
160
+ metadata.updatedAt = new Date().toISOString();
161
+ manifest.files[metadataIndex] = metadata;
162
+ await saveManifest(manifest);
163
+ await commitChanges(`Update ${metadata.project}/${metadata.environment}/${metadata.name}`);
164
+ return metadata;
165
+ }
166
+ /**
167
+ * Delete an env file
168
+ */
169
+ export async function deleteEnvFile(fileId) {
170
+ const manifest = await getManifest();
171
+ const metadata = manifest.files.find(f => f.id === fileId);
172
+ if (!metadata) {
173
+ throw new Error(`Env file not found: ${fileId}`);
174
+ }
175
+ const filePath = getEnvFilePath(fileId, metadata.encrypted);
176
+ // Remove file
177
+ if (await fs.pathExists(filePath)) {
178
+ await fs.remove(filePath);
179
+ }
180
+ // Update manifest
181
+ manifest.files = manifest.files.filter(f => f.id !== fileId);
182
+ // Remove project if no more files
183
+ const projectFiles = manifest.files.filter(f => f.project === metadata.project);
184
+ if (projectFiles.length === 0) {
185
+ manifest.projects = manifest.projects.filter(p => p !== metadata.project);
186
+ }
187
+ await saveManifest(manifest);
188
+ await commitChanges(`Delete ${metadata.project}/${metadata.environment}/${metadata.name}`);
189
+ }
190
+ /**
191
+ * List all env files
192
+ */
193
+ export async function listEnvFiles(project) {
194
+ const manifest = await getManifest();
195
+ if (project) {
196
+ return manifest.files.filter(f => f.project === project);
197
+ }
198
+ return manifest.files;
199
+ }
200
+ /**
201
+ * List all projects
202
+ */
203
+ export async function listProjects() {
204
+ const manifest = await getManifest();
205
+ return manifest.projects;
206
+ }
207
+ /**
208
+ * Import an existing .env file into the vault
209
+ */
210
+ export async function importEnvFile(sourcePath, project, environment, options = {}) {
211
+ const content = await fs.readFile(sourcePath, 'utf-8');
212
+ const variables = parseEnvContent(content);
213
+ return createEnvFile(project, environment, variables, options);
214
+ }
215
+ /**
216
+ * Export an env file to a target path
217
+ */
218
+ export async function exportEnvFile(fileId, targetPath, encryptionOptions) {
219
+ const { variables } = await readEnvFile(fileId, encryptionOptions);
220
+ const content = serializeEnvContent(variables);
221
+ await fs.ensureDir(path.dirname(targetPath));
222
+ await fs.writeFile(targetPath, content);
223
+ }
224
+ /**
225
+ * Add or update a single variable in an env file
226
+ */
227
+ export async function setVariable(fileId, key, value, encryptionOptions) {
228
+ const { variables } = await readEnvFile(fileId, encryptionOptions);
229
+ variables[key] = value;
230
+ await updateEnvFile(fileId, variables, encryptionOptions);
231
+ }
232
+ /**
233
+ * Remove a variable from an env file
234
+ */
235
+ export async function removeVariable(fileId, key, encryptionOptions) {
236
+ const { variables } = await readEnvFile(fileId, encryptionOptions);
237
+ delete variables[key];
238
+ await updateEnvFile(fileId, variables, encryptionOptions);
239
+ }
240
+ /**
241
+ * Get a single variable value
242
+ */
243
+ export async function getVariable(fileId, key, encryptionOptions) {
244
+ const { variables } = await readEnvFile(fileId, encryptionOptions);
245
+ return variables[key];
246
+ }
247
+ //# sourceMappingURL=envfile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envfile.js","sourceRoot":"","sources":["../../src/services/envfile.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Git Service
3
+ * Handles all Git operations for the vault repository
4
+ */
5
+ import type { EnvmaticManifest } from '../types/index.js';
6
+ /**
7
+ * Check if vault is initialized (git repo exists)
8
+ */
9
+ export declare function isVaultInitialized(): Promise<boolean>;
10
+ /**
11
+ * Clone the remote repository to vault path
12
+ */
13
+ export declare function cloneRepository(repoUrl: string, branch?: string): Promise<void>;
14
+ /**
15
+ * Initialize a new git repository in vault (for first-time setup with empty repo)
16
+ */
17
+ export declare function initRepository(repoUrl: string, branch?: string): Promise<void>;
18
+ /**
19
+ * Pull latest changes from remote
20
+ */
21
+ export declare function pull(): Promise<void>;
22
+ /**
23
+ * Push changes to remote (always sets upstream to handle fresh repos)
24
+ */
25
+ export declare function push(): Promise<void>;
26
+ /**
27
+ * Stage and commit changes
28
+ */
29
+ export declare function commitChanges(message: string): Promise<void>;
30
+ /**
31
+ * Sync: commit changes, pull, then push
32
+ */
33
+ export declare function sync(): Promise<{
34
+ pulled: boolean;
35
+ pushed: boolean;
36
+ committed: boolean;
37
+ }>;
38
+ /**
39
+ * Get current status
40
+ */
41
+ export declare function getStatus(): Promise<{
42
+ branch: string;
43
+ ahead: number;
44
+ behind: number;
45
+ modified: number;
46
+ staged: number;
47
+ }>;
48
+ /**
49
+ * Check if remote is accessible
50
+ */
51
+ export declare function checkRemoteAccess(repoUrl: string): Promise<boolean>;
52
+ /**
53
+ * Get the manifest from the vault
54
+ */
55
+ export declare function getManifest(): Promise<EnvmaticManifest>;
56
+ /**
57
+ * Save the manifest to the vault
58
+ */
59
+ export declare function saveManifest(manifest: EnvmaticManifest): Promise<void>;
60
+ //# sourceMappingURL=git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/services/git.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAoB1D;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,OAAO,CAAC,CAO3D;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,GAAE,MAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBrG;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,GAAE,MAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmDpG;AAED;;GAEG;AACH,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAG1C;AAED;;GAEG;AACH,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAiB1C;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWlE;AAED;;GAEG;AACH,wBAAsB,IAAI,IAAI,OAAO,CAAC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC,CA4C9F;AAED;;GAEG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,CAWD;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQzE;AAED;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAa7D;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAG5E"}
@@ -0,0 +1,239 @@
1
+ /**
2
+ * Git Service
3
+ * Handles all Git operations for the vault repository
4
+ */
5
+ import { simpleGit } from 'simple-git';
6
+ import fs from 'fs-extra';
7
+ import path from 'path';
8
+ import { VAULT_PATH, DEFAULT_BRANCH, MANIFEST_FILE } from '../constants.js';
9
+ let gitInstance = null;
10
+ /**
11
+ * Get or create git instance for vault
12
+ */
13
+ function getGit() {
14
+ if (!gitInstance) {
15
+ const options = {
16
+ baseDir: VAULT_PATH,
17
+ binary: 'git',
18
+ maxConcurrentProcesses: 1,
19
+ trimmed: false,
20
+ };
21
+ gitInstance = simpleGit(options);
22
+ }
23
+ return gitInstance;
24
+ }
25
+ /**
26
+ * Check if vault is initialized (git repo exists)
27
+ */
28
+ export async function isVaultInitialized() {
29
+ try {
30
+ const gitDir = path.join(VAULT_PATH, '.git');
31
+ return await fs.pathExists(gitDir);
32
+ }
33
+ catch {
34
+ return false;
35
+ }
36
+ }
37
+ /**
38
+ * Clone the remote repository to vault path
39
+ */
40
+ export async function cloneRepository(repoUrl, branch = DEFAULT_BRANCH) {
41
+ await fs.ensureDir(VAULT_PATH);
42
+ // Check if directory is empty
43
+ const files = await fs.readdir(VAULT_PATH);
44
+ const nonHiddenFiles = files.filter(f => !f.startsWith('.'));
45
+ if (nonHiddenFiles.length > 0 || files.includes('.git')) {
46
+ throw new Error('Vault directory is not empty. Please remove existing files first.');
47
+ }
48
+ const git = simpleGit();
49
+ await git.clone(repoUrl, VAULT_PATH, ['--branch', branch]);
50
+ // Reset instance to use new repo
51
+ gitInstance = null;
52
+ }
53
+ /**
54
+ * Initialize a new git repository in vault (for first-time setup with empty repo)
55
+ */
56
+ export async function initRepository(repoUrl, branch = DEFAULT_BRANCH) {
57
+ await fs.ensureDir(VAULT_PATH);
58
+ const git = getGit();
59
+ await git.init();
60
+ await git.addRemote('origin', repoUrl);
61
+ await git.checkout(['-b', branch]);
62
+ // Create initial manifest
63
+ const manifest = {
64
+ version: '1.0.0',
65
+ files: [],
66
+ projects: [],
67
+ };
68
+ const manifestPath = path.join(VAULT_PATH, MANIFEST_FILE);
69
+ await fs.writeJson(manifestPath, manifest, { spaces: 2 });
70
+ // Create .gitignore to exclude local-only files
71
+ const gitignorePath = path.join(VAULT_PATH, '.gitignore');
72
+ await fs.writeFile(gitignorePath, '# Local files\n.envmatic-local\n');
73
+ // Create README
74
+ const readmePath = path.join(VAULT_PATH, 'README.md');
75
+ await fs.writeFile(readmePath, `# Envmatic Vault
76
+
77
+ This repository is managed by [Envmatic](https://github.com/envmatic).
78
+
79
+ **⚠️ This is a private repository containing encrypted secrets.**
80
+
81
+ ## Structure
82
+
83
+ \`\`\`
84
+ vault/
85
+ ├── <project-name>/
86
+ │ ├── development/
87
+ │ │ └── .env.enc
88
+ │ ├── staging/
89
+ │ │ └── .env.enc
90
+ │ └── production/
91
+ │ └── .env.enc
92
+ └── shared/
93
+ └── common/
94
+ └── .env.enc
95
+ \`\`\`
96
+
97
+ Do not manually edit encrypted files. Use the Envmatic CLI to manage secrets.
98
+ `);
99
+ await git.add('.');
100
+ await git.commit('Initial envmatic vault setup');
101
+ }
102
+ /**
103
+ * Pull latest changes from remote
104
+ */
105
+ export async function pull() {
106
+ const git = getGit();
107
+ await git.pull();
108
+ }
109
+ /**
110
+ * Push changes to remote (always sets upstream to handle fresh repos)
111
+ */
112
+ export async function push() {
113
+ const git = getGit();
114
+ const status = await git.status();
115
+ const branch = status.current || 'main';
116
+ try {
117
+ // Try normal push first
118
+ await git.push();
119
+ }
120
+ catch (error) {
121
+ const errorMessage = error instanceof Error ? error.message : String(error);
122
+ // If no upstream, set it and push
123
+ if (errorMessage.includes('no upstream') || errorMessage.includes('set-upstream')) {
124
+ await git.push(['-u', 'origin', branch]);
125
+ }
126
+ else {
127
+ throw error;
128
+ }
129
+ }
130
+ }
131
+ /**
132
+ * Stage and commit changes
133
+ */
134
+ export async function commitChanges(message) {
135
+ const git = getGit();
136
+ await git.add('.');
137
+ // Check if there are changes to commit
138
+ const status = await git.status();
139
+ if (status.files.length === 0) {
140
+ return; // Nothing to commit
141
+ }
142
+ await git.commit(message);
143
+ }
144
+ /**
145
+ * Sync: commit changes, pull, then push
146
+ */
147
+ export async function sync() {
148
+ const git = getGit();
149
+ let pulled = false;
150
+ let pushed = false;
151
+ let committed = false;
152
+ // First, commit any uncommitted changes
153
+ const preStatus = await git.status();
154
+ if (preStatus.files.length > 0) {
155
+ await git.add('.');
156
+ await git.commit('Sync from envmatic');
157
+ committed = true;
158
+ }
159
+ try {
160
+ await git.pull();
161
+ pulled = true;
162
+ }
163
+ catch (error) {
164
+ // If pull fails due to no upstream, that's okay for new repos
165
+ const errorMessage = error instanceof Error ? error.message : String(error);
166
+ if (!errorMessage.includes('no tracking information')) {
167
+ throw error;
168
+ }
169
+ }
170
+ try {
171
+ const status = await git.status();
172
+ if (status.ahead > 0) {
173
+ await git.push(['-u', 'origin', 'HEAD']);
174
+ pushed = true;
175
+ }
176
+ }
177
+ catch (error) {
178
+ const errorMessage = error instanceof Error ? error.message : String(error);
179
+ // Handle first push to empty remote
180
+ if (errorMessage.includes('has no upstream')) {
181
+ await git.push(['-u', 'origin', 'HEAD']);
182
+ pushed = true;
183
+ }
184
+ else {
185
+ throw error;
186
+ }
187
+ }
188
+ return { pulled, pushed, committed };
189
+ }
190
+ /**
191
+ * Get current status
192
+ */
193
+ export async function getStatus() {
194
+ const git = getGit();
195
+ const status = await git.status();
196
+ return {
197
+ branch: status.current || DEFAULT_BRANCH,
198
+ ahead: status.ahead,
199
+ behind: status.behind,
200
+ modified: status.modified.length + status.not_added.length,
201
+ staged: status.staged.length,
202
+ };
203
+ }
204
+ /**
205
+ * Check if remote is accessible
206
+ */
207
+ export async function checkRemoteAccess(repoUrl) {
208
+ try {
209
+ const git = simpleGit();
210
+ await git.listRemote([repoUrl]);
211
+ return true;
212
+ }
213
+ catch {
214
+ return false;
215
+ }
216
+ }
217
+ /**
218
+ * Get the manifest from the vault
219
+ */
220
+ export async function getManifest() {
221
+ const manifestPath = path.join(VAULT_PATH, MANIFEST_FILE);
222
+ if (await fs.pathExists(manifestPath)) {
223
+ return fs.readJson(manifestPath);
224
+ }
225
+ // Return empty manifest if not found
226
+ return {
227
+ version: '1.0.0',
228
+ files: [],
229
+ projects: [],
230
+ };
231
+ }
232
+ /**
233
+ * Save the manifest to the vault
234
+ */
235
+ export async function saveManifest(manifest) {
236
+ const manifestPath = path.join(VAULT_PATH, MANIFEST_FILE);
237
+ await fs.writeJson(manifestPath, manifest, { spaces: 2 });
238
+ }
239
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/services/git.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Linker Service
3
+ * Handles symlinks and copies for project integration
4
+ */
5
+ export { getLinksForEnvFile } from './config.js';
6
+ import type { LinkInfo, EncryptionOptions } from '../types/index.js';
7
+ /**
8
+ * Create a symlink from source to target
9
+ * On Windows, this may require admin privileges for file symlinks
10
+ */
11
+ export declare function createSymlink(sourceFileId: string, targetPath: string, encryptionOptions?: EncryptionOptions): Promise<LinkInfo>;
12
+ /**
13
+ * Create a copy of an env file at target path
14
+ * This is useful for encrypted files or when symlinks aren't suitable
15
+ */
16
+ export declare function createCopy(sourceFileId: string, targetPath: string, encryptionOptions?: EncryptionOptions, autoSync?: boolean): Promise<LinkInfo>;
17
+ /**
18
+ * Update all copies for a given source file
19
+ */
20
+ export declare function syncCopies(sourceFileId: string, encryptionOptions?: EncryptionOptions): Promise<number>;
21
+ /**
22
+ * Unlink a target path (remove symlink or copy)
23
+ */
24
+ export declare function unlink(targetPath: string): Promise<boolean>;
25
+ /**
26
+ * List all links
27
+ */
28
+ export declare function listLinks(): Promise<LinkInfo[]>;
29
+ /**
30
+ * Check if a link is valid (target exists and matches source)
31
+ */
32
+ export declare function validateLink(link: LinkInfo): Promise<{
33
+ valid: boolean;
34
+ exists: boolean;
35
+ isSymlink: boolean;
36
+ error?: string;
37
+ }>;
38
+ /**
39
+ * Repair broken links
40
+ */
41
+ export declare function repairLinks(encryptionOptions?: EncryptionOptions): Promise<{
42
+ repaired: number;
43
+ removed: number;
44
+ errors: string[];
45
+ }>;
46
+ //# sourceMappingURL=linker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linker.d.ts","sourceRoot":"","sources":["../../src/services/linker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGjD,OAAO,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAWrE;;;GAGG;AACH,wBAAsB,aAAa,CACjC,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,iBAAiB,CAAC,EAAE,iBAAiB,GACpC,OAAO,CAAC,QAAQ,CAAC,CAwEnB;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,iBAAiB,CAAC,EAAE,iBAAiB,EACrC,QAAQ,GAAE,OAAe,GACxB,OAAO,CAAC,QAAQ,CAAC,CAyBnB;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,YAAY,EAAE,MAAM,EACpB,iBAAiB,CAAC,EAAE,iBAAiB,GACpC,OAAO,CAAC,MAAM,CAAC,CAkBjB;AAED;;GAEG;AACH,wBAAsB,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAYjE;AAED;;GAEG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,CAErD;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC;IAC1D,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CAkCD;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC;IAChF,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC,CAoCD"}