shiva-code 0.7.18 → 0.8.2
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/dist/{chunk-UABU5VVI.js → chunk-5RLMQDLT.js} +21 -0
- package/dist/chunk-FAMO57BL.js +417 -0
- package/dist/{chunk-W3DKHCXB.js → chunk-GHGMDDLO.js} +47 -1
- package/dist/{chunk-KUA6TMQJ.js → chunk-HNIWPFMY.js} +1 -1
- package/dist/chunk-VVP3NTOY.js +3437 -0
- package/dist/index.js +1612 -1191
- package/dist/{logger-VVWOD6AA.js → logger-G6MRCCCU.js} +1 -1
- package/dist/{login-DBN2L25M.js → login-KKEDZS7J.js} +2 -2
- package/dist/{manager-CCRAV6A5.js → manager-UAYJV6E3.js} +1 -1
- package/dist/{package-manager-UORON74F.js → package-manager-U3IHQIDC.js} +2 -2
- package/dist/postinstall.d.ts +1 -0
- package/dist/postinstall.js +50 -0
- package/dist/settings-sync-WVIRHPCR.js +11 -0
- package/package.json +4 -3
- package/dist/chunk-IWDZCN4S.js +0 -917
|
@@ -187,6 +187,27 @@ var log = {
|
|
|
187
187
|
// Done message (for completing operations)
|
|
188
188
|
done: (message) => {
|
|
189
189
|
console.log(`${shivaSuccess("\u25CF")} ${message}`);
|
|
190
|
+
},
|
|
191
|
+
// Auth required shorthand - for consistent auth error messages
|
|
192
|
+
authRequired: () => {
|
|
193
|
+
console.log(shivaError("\u2717"), "Nicht angemeldet");
|
|
194
|
+
console.log(chalk.dim(" \u2192"), shivaSecondary("Anmelden mit: shiva login"));
|
|
195
|
+
},
|
|
196
|
+
// Section header with centered box (like in onboarding)
|
|
197
|
+
sectionBox: (title, width = 45) => {
|
|
198
|
+
const innerWidth = width - 2;
|
|
199
|
+
const visibleLen = title.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, "").length;
|
|
200
|
+
const paddingLeft = Math.floor((innerWidth - visibleLen) / 2);
|
|
201
|
+
const paddingRight = innerWidth - visibleLen - paddingLeft;
|
|
202
|
+
console.log(shivaPrimary(" \u256D" + "\u2500".repeat(innerWidth) + "\u256E"));
|
|
203
|
+
console.log(shivaPrimary(" \u2502") + " ".repeat(paddingLeft) + title + " ".repeat(paddingRight) + shivaPrimary("\u2502"));
|
|
204
|
+
console.log(shivaPrimary(" \u2570" + "\u2500".repeat(innerWidth) + "\u256F"));
|
|
205
|
+
},
|
|
206
|
+
// Inline key-value pairs with consistent padding
|
|
207
|
+
inlineKeyValue: (pairs) => {
|
|
208
|
+
for (const { key, value } of pairs) {
|
|
209
|
+
console.log(` ${chalk.dim(key.padEnd(15))} ${shivaSecondary(value)}`);
|
|
210
|
+
}
|
|
190
211
|
}
|
|
191
212
|
};
|
|
192
213
|
var colors = {
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
import {
|
|
2
|
+
api
|
|
3
|
+
} from "./chunk-KB6M24M3.js";
|
|
4
|
+
import {
|
|
5
|
+
getExtendedConfig,
|
|
6
|
+
setClaudeArgs,
|
|
7
|
+
setClaudeSkipPermissions,
|
|
8
|
+
setDefaultTerminal
|
|
9
|
+
} from "./chunk-OP4HYQZZ.js";
|
|
10
|
+
|
|
11
|
+
// src/services/data/settings-sync.ts
|
|
12
|
+
import * as crypto from "crypto";
|
|
13
|
+
import Conf from "conf";
|
|
14
|
+
var settingsStore = new Conf({
|
|
15
|
+
projectName: "shiva-code-settings",
|
|
16
|
+
defaults: {
|
|
17
|
+
syncableSettings: {
|
|
18
|
+
version: 1,
|
|
19
|
+
lastModified: (/* @__PURE__ */ new Date()).toISOString(),
|
|
20
|
+
defaultTerminal: "auto",
|
|
21
|
+
claudeArgs: [],
|
|
22
|
+
claudeSkipPermissions: true,
|
|
23
|
+
docker: {
|
|
24
|
+
enabled: false,
|
|
25
|
+
defaultImage: "shiva/claude-runner:latest",
|
|
26
|
+
autoStart: true,
|
|
27
|
+
volumeMounts: {},
|
|
28
|
+
environment: {}
|
|
29
|
+
},
|
|
30
|
+
language: "de",
|
|
31
|
+
theme: "auto",
|
|
32
|
+
features: {
|
|
33
|
+
autoSync: true,
|
|
34
|
+
githubContext: true,
|
|
35
|
+
secretsInjection: true
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
syncState: {
|
|
39
|
+
lastSyncedAt: null,
|
|
40
|
+
localHash: "",
|
|
41
|
+
cloudHash: null,
|
|
42
|
+
conflictStrategy: "manual",
|
|
43
|
+
pendingChanges: false
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
var SettingsSyncService = class {
|
|
48
|
+
// ============================================
|
|
49
|
+
// Local Settings Management
|
|
50
|
+
// ============================================
|
|
51
|
+
/**
|
|
52
|
+
* Get local syncable settings
|
|
53
|
+
* Merges config.ts values with syncable settings store
|
|
54
|
+
*/
|
|
55
|
+
getLocalSettings() {
|
|
56
|
+
const stored = settingsStore.get("syncableSettings");
|
|
57
|
+
const extConfig = getExtendedConfig();
|
|
58
|
+
const settings = {
|
|
59
|
+
...stored,
|
|
60
|
+
defaultTerminal: extConfig.defaultTerminal,
|
|
61
|
+
claudeArgs: extConfig.claudeArgs,
|
|
62
|
+
claudeSkipPermissions: extConfig.claudeSkipPermissions,
|
|
63
|
+
lastModified: (/* @__PURE__ */ new Date()).toISOString()
|
|
64
|
+
};
|
|
65
|
+
return settings;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Update local settings
|
|
69
|
+
*/
|
|
70
|
+
setLocalSettings(settings) {
|
|
71
|
+
const current = this.getLocalSettings();
|
|
72
|
+
const updated = {
|
|
73
|
+
...current,
|
|
74
|
+
...settings,
|
|
75
|
+
lastModified: (/* @__PURE__ */ new Date()).toISOString()
|
|
76
|
+
};
|
|
77
|
+
settingsStore.set("syncableSettings", updated);
|
|
78
|
+
if (settings.defaultTerminal !== void 0) {
|
|
79
|
+
setDefaultTerminal(settings.defaultTerminal);
|
|
80
|
+
}
|
|
81
|
+
if (settings.claudeArgs !== void 0) {
|
|
82
|
+
setClaudeArgs(settings.claudeArgs);
|
|
83
|
+
}
|
|
84
|
+
if (settings.claudeSkipPermissions !== void 0) {
|
|
85
|
+
setClaudeSkipPermissions(settings.claudeSkipPermissions);
|
|
86
|
+
}
|
|
87
|
+
this.updateSyncState({ pendingChanges: true });
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Calculate hash of settings for conflict detection
|
|
91
|
+
*/
|
|
92
|
+
getLocalHash() {
|
|
93
|
+
const settings = this.getLocalSettings();
|
|
94
|
+
const { lastModified, ...hashable } = settings;
|
|
95
|
+
return crypto.createHash("md5").update(JSON.stringify(hashable)).digest("hex").substring(0, 8);
|
|
96
|
+
}
|
|
97
|
+
// ============================================
|
|
98
|
+
// Sync State Management
|
|
99
|
+
// ============================================
|
|
100
|
+
/**
|
|
101
|
+
* Get current sync state
|
|
102
|
+
*/
|
|
103
|
+
getSyncState() {
|
|
104
|
+
const state = settingsStore.get("syncState");
|
|
105
|
+
return {
|
|
106
|
+
...state,
|
|
107
|
+
localHash: this.getLocalHash()
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Update sync state
|
|
112
|
+
*/
|
|
113
|
+
updateSyncState(partial) {
|
|
114
|
+
const current = settingsStore.get("syncState");
|
|
115
|
+
settingsStore.set("syncState", { ...current, ...partial });
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Set conflict resolution strategy
|
|
119
|
+
*/
|
|
120
|
+
setConflictStrategy(strategy) {
|
|
121
|
+
this.updateSyncState({ conflictStrategy: strategy });
|
|
122
|
+
}
|
|
123
|
+
// ============================================
|
|
124
|
+
// Cloud Sync Operations
|
|
125
|
+
// ============================================
|
|
126
|
+
/**
|
|
127
|
+
* Get settings from cloud
|
|
128
|
+
*/
|
|
129
|
+
async getCloudSettings() {
|
|
130
|
+
try {
|
|
131
|
+
const response = await api.getUserSettings();
|
|
132
|
+
return response.settings || null;
|
|
133
|
+
} catch (error) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Push local settings to cloud
|
|
139
|
+
*/
|
|
140
|
+
async pushToCloud(settings) {
|
|
141
|
+
const localSettings = settings || this.getLocalSettings();
|
|
142
|
+
const localHash = this.getLocalHash();
|
|
143
|
+
await api.updateUserSettings({
|
|
144
|
+
settings: localSettings,
|
|
145
|
+
localHash
|
|
146
|
+
});
|
|
147
|
+
this.updateSyncState({
|
|
148
|
+
lastSyncedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
149
|
+
cloudHash: localHash,
|
|
150
|
+
pendingChanges: false
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Pull settings from cloud and apply locally
|
|
155
|
+
*/
|
|
156
|
+
async pullFromCloud() {
|
|
157
|
+
const cloudSettings = await this.getCloudSettings();
|
|
158
|
+
if (!cloudSettings) {
|
|
159
|
+
throw new Error("No cloud settings found");
|
|
160
|
+
}
|
|
161
|
+
this.setLocalSettings(cloudSettings);
|
|
162
|
+
const cloudHash = this.calculateHash(cloudSettings);
|
|
163
|
+
this.updateSyncState({
|
|
164
|
+
lastSyncedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
165
|
+
cloudHash,
|
|
166
|
+
pendingChanges: false
|
|
167
|
+
});
|
|
168
|
+
return cloudSettings;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Calculate hash for any settings object
|
|
172
|
+
*/
|
|
173
|
+
calculateHash(settings) {
|
|
174
|
+
const { lastModified, ...hashable } = settings;
|
|
175
|
+
return crypto.createHash("md5").update(JSON.stringify(hashable)).digest("hex").substring(0, 8);
|
|
176
|
+
}
|
|
177
|
+
// ============================================
|
|
178
|
+
// Sync Operations
|
|
179
|
+
// ============================================
|
|
180
|
+
/**
|
|
181
|
+
* Check if local and cloud are out of sync
|
|
182
|
+
*/
|
|
183
|
+
async isOutOfSync() {
|
|
184
|
+
const cloudSettings = await this.getCloudSettings();
|
|
185
|
+
if (!cloudSettings) {
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
const localHash = this.getLocalHash();
|
|
189
|
+
const cloudHash = this.calculateHash(cloudSettings);
|
|
190
|
+
return localHash !== cloudHash;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Perform sync with optional strategy override
|
|
194
|
+
*/
|
|
195
|
+
async sync(strategy) {
|
|
196
|
+
const resolveStrategy = strategy || this.getSyncState().conflictStrategy;
|
|
197
|
+
const localSettings = this.getLocalSettings();
|
|
198
|
+
const localHash = this.getLocalHash();
|
|
199
|
+
try {
|
|
200
|
+
const response = await api.syncUserSettings({
|
|
201
|
+
settings: localSettings,
|
|
202
|
+
localHash
|
|
203
|
+
});
|
|
204
|
+
if (response.conflict) {
|
|
205
|
+
if (resolveStrategy === "local-wins") {
|
|
206
|
+
await api.updateUserSettings({
|
|
207
|
+
settings: localSettings,
|
|
208
|
+
localHash,
|
|
209
|
+
forceOverwrite: true
|
|
210
|
+
});
|
|
211
|
+
this.updateSyncState({
|
|
212
|
+
lastSyncedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
213
|
+
cloudHash: localHash,
|
|
214
|
+
pendingChanges: false
|
|
215
|
+
});
|
|
216
|
+
return {
|
|
217
|
+
success: true,
|
|
218
|
+
action: "pushed",
|
|
219
|
+
settings: localSettings,
|
|
220
|
+
message: "Lokale Einstellungen hochgeladen (local-wins)"
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
if (resolveStrategy === "cloud-wins") {
|
|
224
|
+
const cloudSettings = response.conflict.cloudSettings;
|
|
225
|
+
this.setLocalSettings(cloudSettings);
|
|
226
|
+
const cloudHash = this.calculateHash(cloudSettings);
|
|
227
|
+
this.updateSyncState({
|
|
228
|
+
lastSyncedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
229
|
+
cloudHash,
|
|
230
|
+
pendingChanges: false
|
|
231
|
+
});
|
|
232
|
+
return {
|
|
233
|
+
success: true,
|
|
234
|
+
action: "pulled",
|
|
235
|
+
settings: cloudSettings,
|
|
236
|
+
message: "Cloud-Einstellungen \xFCbernommen (cloud-wins)"
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
return {
|
|
240
|
+
success: false,
|
|
241
|
+
action: "conflict",
|
|
242
|
+
conflict: {
|
|
243
|
+
type: response.conflict.type,
|
|
244
|
+
localSettings,
|
|
245
|
+
cloudSettings: response.conflict.cloudSettings
|
|
246
|
+
},
|
|
247
|
+
message: "Konflikt erkannt. Manuelle Aufl\xF6sung erforderlich."
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
this.updateSyncState({
|
|
251
|
+
lastSyncedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
252
|
+
cloudHash: response.cloudHash,
|
|
253
|
+
pendingChanges: false
|
|
254
|
+
});
|
|
255
|
+
return {
|
|
256
|
+
success: true,
|
|
257
|
+
action: "pushed",
|
|
258
|
+
settings: response.settings,
|
|
259
|
+
message: "Sync erfolgreich"
|
|
260
|
+
};
|
|
261
|
+
} catch (error) {
|
|
262
|
+
if (error instanceof Error && error.message.includes("404")) {
|
|
263
|
+
await this.pushToCloud(localSettings);
|
|
264
|
+
return {
|
|
265
|
+
success: true,
|
|
266
|
+
action: "pushed",
|
|
267
|
+
settings: localSettings,
|
|
268
|
+
message: "Erste Synchronisation erfolgreich"
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
throw error;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Merge settings from local and cloud
|
|
276
|
+
*/
|
|
277
|
+
mergeSettings(local, cloud) {
|
|
278
|
+
const localTime = new Date(local.lastModified).getTime();
|
|
279
|
+
const cloudTime = new Date(cloud.lastModified).getTime();
|
|
280
|
+
return {
|
|
281
|
+
version: Math.max(local.version, cloud.version),
|
|
282
|
+
lastModified: (/* @__PURE__ */ new Date()).toISOString(),
|
|
283
|
+
// CLI-specific: prefer local
|
|
284
|
+
defaultTerminal: local.defaultTerminal,
|
|
285
|
+
claudeArgs: local.claudeArgs,
|
|
286
|
+
claudeSkipPermissions: local.claudeSkipPermissions,
|
|
287
|
+
// Docker: merge
|
|
288
|
+
docker: {
|
|
289
|
+
...cloud.docker,
|
|
290
|
+
...local.docker,
|
|
291
|
+
volumeMounts: { ...cloud.docker.volumeMounts, ...local.docker.volumeMounts },
|
|
292
|
+
environment: { ...cloud.docker.environment, ...local.docker.environment }
|
|
293
|
+
},
|
|
294
|
+
// Preferences: prefer newer
|
|
295
|
+
language: localTime > cloudTime ? local.language : cloud.language,
|
|
296
|
+
theme: localTime > cloudTime ? local.theme : cloud.theme,
|
|
297
|
+
// Features: prefer cloud (browser-configurable)
|
|
298
|
+
features: cloud.features
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Resolve conflict with specific resolution
|
|
303
|
+
*/
|
|
304
|
+
async resolveConflict(resolution) {
|
|
305
|
+
const localSettings = this.getLocalSettings();
|
|
306
|
+
const cloudSettings = await this.getCloudSettings();
|
|
307
|
+
if (!cloudSettings) {
|
|
308
|
+
await this.pushToCloud(localSettings);
|
|
309
|
+
return {
|
|
310
|
+
success: true,
|
|
311
|
+
action: "pushed",
|
|
312
|
+
settings: localSettings,
|
|
313
|
+
message: "Lokale Einstellungen hochgeladen"
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
let finalSettings;
|
|
317
|
+
let action;
|
|
318
|
+
switch (resolution) {
|
|
319
|
+
case "local":
|
|
320
|
+
finalSettings = localSettings;
|
|
321
|
+
action = "pushed";
|
|
322
|
+
break;
|
|
323
|
+
case "cloud":
|
|
324
|
+
finalSettings = cloudSettings;
|
|
325
|
+
action = "pulled";
|
|
326
|
+
break;
|
|
327
|
+
case "merge":
|
|
328
|
+
finalSettings = this.mergeSettings(localSettings, cloudSettings);
|
|
329
|
+
action = "merged";
|
|
330
|
+
break;
|
|
331
|
+
}
|
|
332
|
+
if (resolution === "cloud") {
|
|
333
|
+
this.setLocalSettings(finalSettings);
|
|
334
|
+
} else {
|
|
335
|
+
await api.updateUserSettings({
|
|
336
|
+
settings: finalSettings,
|
|
337
|
+
localHash: this.calculateHash(finalSettings),
|
|
338
|
+
forceOverwrite: true
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
const finalHash = this.calculateHash(finalSettings);
|
|
342
|
+
this.updateSyncState({
|
|
343
|
+
lastSyncedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
344
|
+
cloudHash: finalHash,
|
|
345
|
+
pendingChanges: false
|
|
346
|
+
});
|
|
347
|
+
return {
|
|
348
|
+
success: true,
|
|
349
|
+
action,
|
|
350
|
+
settings: finalSettings,
|
|
351
|
+
message: `Konflikt aufgel\xF6st: ${resolution}`
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
// ============================================
|
|
355
|
+
// Docker Settings Helpers
|
|
356
|
+
// ============================================
|
|
357
|
+
/**
|
|
358
|
+
* Get Docker settings
|
|
359
|
+
*/
|
|
360
|
+
getDockerSettings() {
|
|
361
|
+
return this.getLocalSettings().docker;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Update Docker settings
|
|
365
|
+
*/
|
|
366
|
+
setDockerSettings(docker) {
|
|
367
|
+
const current = this.getLocalSettings();
|
|
368
|
+
this.setLocalSettings({
|
|
369
|
+
docker: { ...current.docker, ...docker }
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Enable/disable Docker mode
|
|
374
|
+
*/
|
|
375
|
+
setDockerEnabled(enabled) {
|
|
376
|
+
this.setDockerSettings({ enabled });
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Set default Docker image
|
|
380
|
+
*/
|
|
381
|
+
setDockerImage(image) {
|
|
382
|
+
this.setDockerSettings({ defaultImage: image });
|
|
383
|
+
}
|
|
384
|
+
// ============================================
|
|
385
|
+
// Feature Flags
|
|
386
|
+
// ============================================
|
|
387
|
+
/**
|
|
388
|
+
* Get feature flags
|
|
389
|
+
*/
|
|
390
|
+
getFeatures() {
|
|
391
|
+
return this.getLocalSettings().features;
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Set feature flag
|
|
395
|
+
*/
|
|
396
|
+
setFeature(feature, enabled) {
|
|
397
|
+
const current = this.getLocalSettings();
|
|
398
|
+
this.setLocalSettings({
|
|
399
|
+
features: { ...current.features, [feature]: enabled }
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
// ============================================
|
|
403
|
+
// Settings History (for debugging)
|
|
404
|
+
// ============================================
|
|
405
|
+
/**
|
|
406
|
+
* Get settings history from cloud
|
|
407
|
+
*/
|
|
408
|
+
async getHistory() {
|
|
409
|
+
return api.getSettingsHistory();
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
var settingsSync = new SettingsSyncService();
|
|
413
|
+
|
|
414
|
+
export {
|
|
415
|
+
SettingsSyncService,
|
|
416
|
+
settingsSync
|
|
417
|
+
};
|
|
@@ -95,7 +95,53 @@ function encodeProjectPath(projectPath) {
|
|
|
95
95
|
}
|
|
96
96
|
function decodeProjectPath(encoded) {
|
|
97
97
|
const parts = encoded.split("-").filter(Boolean);
|
|
98
|
-
|
|
98
|
+
let currentPath = "";
|
|
99
|
+
let i = 0;
|
|
100
|
+
while (i < parts.length) {
|
|
101
|
+
const part = parts[i];
|
|
102
|
+
const testPath = currentPath + "/" + part;
|
|
103
|
+
if (fs.existsSync(testPath)) {
|
|
104
|
+
currentPath = testPath;
|
|
105
|
+
i++;
|
|
106
|
+
} else {
|
|
107
|
+
let found = false;
|
|
108
|
+
for (let j = i + 1; j < parts.length && j <= i + 5 && !found; j++) {
|
|
109
|
+
const partsToJoin = parts.slice(i, j + 1);
|
|
110
|
+
const withHyphen = partsToJoin.join("-");
|
|
111
|
+
const hyphenPath = currentPath + "/" + withHyphen;
|
|
112
|
+
if (fs.existsSync(hyphenPath)) {
|
|
113
|
+
currentPath = hyphenPath;
|
|
114
|
+
i = j + 1;
|
|
115
|
+
found = true;
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
const withDot = partsToJoin.join(".");
|
|
119
|
+
const dotPath = currentPath + "/" + withDot;
|
|
120
|
+
if (fs.existsSync(dotPath)) {
|
|
121
|
+
currentPath = dotPath;
|
|
122
|
+
i = j + 1;
|
|
123
|
+
found = true;
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
const withUnderscore = partsToJoin.join("_");
|
|
127
|
+
const underscorePath = currentPath + "/" + withUnderscore;
|
|
128
|
+
if (fs.existsSync(underscorePath)) {
|
|
129
|
+
currentPath = underscorePath;
|
|
130
|
+
i = j + 1;
|
|
131
|
+
found = true;
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (!found) {
|
|
136
|
+
currentPath = testPath;
|
|
137
|
+
i++;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (!currentPath || currentPath === "/") {
|
|
142
|
+
return "/" + parts.join("/");
|
|
143
|
+
}
|
|
144
|
+
return currentPath;
|
|
99
145
|
}
|
|
100
146
|
function getProjectName(projectPath) {
|
|
101
147
|
return path2.basename(projectPath);
|