shiva-code 0.5.2 → 0.5.3
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-EGRMFBG6.js +472 -0
- package/dist/chunk-OP4HYQZZ.js +163 -0
- package/dist/client-Z6ZMO5QE.js +8 -0
- package/dist/config-FGMZONWV.js +49 -0
- package/dist/index.js +560 -1018
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
api
|
|
4
|
+
} from "./chunk-EGRMFBG6.js";
|
|
5
|
+
import {
|
|
6
|
+
CONFIG_PATH,
|
|
7
|
+
clearAuth,
|
|
8
|
+
clearConfig,
|
|
9
|
+
getClaudeArgs,
|
|
10
|
+
getClaudeLaunchArgs,
|
|
11
|
+
getClaudeSkipPermissions,
|
|
12
|
+
getConfig,
|
|
13
|
+
getDefaultTerminal,
|
|
14
|
+
getExtendedConfig,
|
|
15
|
+
getToken,
|
|
16
|
+
isAuthenticated,
|
|
17
|
+
migrateConfig,
|
|
18
|
+
setAuth,
|
|
19
|
+
setClaudeArgs,
|
|
20
|
+
setClaudeSkipPermissions,
|
|
21
|
+
setConfig,
|
|
22
|
+
setDefaultTerminal
|
|
23
|
+
} from "./chunk-OP4HYQZZ.js";
|
|
2
24
|
import {
|
|
3
25
|
SECURITY_PRESETS,
|
|
4
26
|
addDockerMount,
|
|
@@ -88,597 +110,6 @@ import * as readline from "readline";
|
|
|
88
110
|
import { Command } from "commander";
|
|
89
111
|
import inquirer2 from "inquirer";
|
|
90
112
|
|
|
91
|
-
// src/utils/config.ts
|
|
92
|
-
import Conf from "conf";
|
|
93
|
-
import * as os from "os";
|
|
94
|
-
import * as path from "path";
|
|
95
|
-
var DEFAULT_API_ENDPOINT = "https://shiva.li/api";
|
|
96
|
-
var OLD_API_ENDPOINTS = [
|
|
97
|
-
"https://shiva-ai-api.slither-mutiplayer.workers.dev/api",
|
|
98
|
-
"https://shiva-ai-api.slither-multiplayer.workers.dev/api"
|
|
99
|
-
];
|
|
100
|
-
var DEFAULT_CLAUDE_PROJECTS_PATH = path.join(os.homedir(), ".claude", "projects");
|
|
101
|
-
var config = new Conf({
|
|
102
|
-
projectName: "shiva-code",
|
|
103
|
-
defaults: {
|
|
104
|
-
apiEndpoint: DEFAULT_API_ENDPOINT,
|
|
105
|
-
token: null,
|
|
106
|
-
tokenExpiry: null,
|
|
107
|
-
userId: null,
|
|
108
|
-
email: null,
|
|
109
|
-
tier: null,
|
|
110
|
-
// Control Station defaults
|
|
111
|
-
packages: {},
|
|
112
|
-
defaultTerminal: "auto",
|
|
113
|
-
claudeProjectsPath: DEFAULT_CLAUDE_PROJECTS_PATH,
|
|
114
|
-
// Claude Code launch settings
|
|
115
|
-
claudeArgs: [],
|
|
116
|
-
claudeSkipPermissions: true
|
|
117
|
-
// Default: skip permissions for smoother workflow
|
|
118
|
-
}
|
|
119
|
-
});
|
|
120
|
-
function getConfig() {
|
|
121
|
-
return {
|
|
122
|
-
apiEndpoint: config.get("apiEndpoint"),
|
|
123
|
-
token: config.get("token"),
|
|
124
|
-
tokenExpiry: config.get("tokenExpiry"),
|
|
125
|
-
userId: config.get("userId"),
|
|
126
|
-
email: config.get("email"),
|
|
127
|
-
tier: config.get("tier")
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
function setConfig(key, value) {
|
|
131
|
-
config.set(key, value);
|
|
132
|
-
}
|
|
133
|
-
function getToken() {
|
|
134
|
-
const token = config.get("token");
|
|
135
|
-
const expiry = config.get("tokenExpiry");
|
|
136
|
-
if (token && expiry && Date.now() > expiry) {
|
|
137
|
-
clearAuth();
|
|
138
|
-
return null;
|
|
139
|
-
}
|
|
140
|
-
return token;
|
|
141
|
-
}
|
|
142
|
-
function setAuth(token, user) {
|
|
143
|
-
let expiry;
|
|
144
|
-
try {
|
|
145
|
-
const payload = JSON.parse(atob(token.includes(".") ? token.split(".")[1] : token));
|
|
146
|
-
expiry = payload.exp > 1e12 ? payload.exp : payload.exp * 1e3;
|
|
147
|
-
} catch {
|
|
148
|
-
expiry = Date.now() + 7 * 24 * 60 * 60 * 1e3;
|
|
149
|
-
}
|
|
150
|
-
config.set("token", token);
|
|
151
|
-
config.set("tokenExpiry", expiry);
|
|
152
|
-
config.set("userId", user.id);
|
|
153
|
-
config.set("email", user.email);
|
|
154
|
-
config.set("tier", user.tier);
|
|
155
|
-
}
|
|
156
|
-
function clearAuth() {
|
|
157
|
-
config.set("token", null);
|
|
158
|
-
config.set("tokenExpiry", null);
|
|
159
|
-
config.set("userId", null);
|
|
160
|
-
config.set("email", null);
|
|
161
|
-
config.set("tier", null);
|
|
162
|
-
}
|
|
163
|
-
function isAuthenticated() {
|
|
164
|
-
return getToken() !== null;
|
|
165
|
-
}
|
|
166
|
-
function getApiEndpoint() {
|
|
167
|
-
return config.get("apiEndpoint");
|
|
168
|
-
}
|
|
169
|
-
var CONFIG_PATH = config.path;
|
|
170
|
-
function clearConfig() {
|
|
171
|
-
config.clear();
|
|
172
|
-
config.set("apiEndpoint", DEFAULT_API_ENDPOINT);
|
|
173
|
-
}
|
|
174
|
-
function getExtendedConfig() {
|
|
175
|
-
return {
|
|
176
|
-
...getConfig(),
|
|
177
|
-
packages: config.get("packages") || {},
|
|
178
|
-
defaultTerminal: config.get("defaultTerminal") || "auto",
|
|
179
|
-
claudeProjectsPath: config.get("claudeProjectsPath") || DEFAULT_CLAUDE_PROJECTS_PATH,
|
|
180
|
-
claudeArgs: config.get("claudeArgs") || [],
|
|
181
|
-
claudeSkipPermissions: config.get("claudeSkipPermissions") ?? true
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
function getDefaultTerminal() {
|
|
185
|
-
return config.get("defaultTerminal") || "auto";
|
|
186
|
-
}
|
|
187
|
-
function setDefaultTerminal(terminal) {
|
|
188
|
-
config.set("defaultTerminal", terminal);
|
|
189
|
-
}
|
|
190
|
-
function getClaudeSkipPermissions() {
|
|
191
|
-
return config.get("claudeSkipPermissions") ?? true;
|
|
192
|
-
}
|
|
193
|
-
function setClaudeSkipPermissions(skip) {
|
|
194
|
-
config.set("claudeSkipPermissions", skip);
|
|
195
|
-
}
|
|
196
|
-
function getClaudeArgs() {
|
|
197
|
-
return config.get("claudeArgs") || [];
|
|
198
|
-
}
|
|
199
|
-
function setClaudeArgs(args) {
|
|
200
|
-
config.set("claudeArgs", args);
|
|
201
|
-
}
|
|
202
|
-
function getClaudeLaunchArgs() {
|
|
203
|
-
const args = [];
|
|
204
|
-
if (config.get("claudeSkipPermissions") ?? true) {
|
|
205
|
-
args.push("--dangerously-skip-permissions");
|
|
206
|
-
}
|
|
207
|
-
const customArgs = config.get("claudeArgs") || [];
|
|
208
|
-
args.push(...customArgs);
|
|
209
|
-
return args;
|
|
210
|
-
}
|
|
211
|
-
function migrateConfig() {
|
|
212
|
-
const currentEndpoint = config.get("apiEndpoint");
|
|
213
|
-
if (currentEndpoint && OLD_API_ENDPOINTS.includes(currentEndpoint)) {
|
|
214
|
-
config.set("apiEndpoint", DEFAULT_API_ENDPOINT);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
// src/services/api/client.ts
|
|
219
|
-
var ApiClient = class {
|
|
220
|
-
getHeaders() {
|
|
221
|
-
const headers = {
|
|
222
|
-
"Content-Type": "application/json"
|
|
223
|
-
};
|
|
224
|
-
const token = getToken();
|
|
225
|
-
if (token) {
|
|
226
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
227
|
-
}
|
|
228
|
-
return headers;
|
|
229
|
-
}
|
|
230
|
-
async request(endpoint, options = {}) {
|
|
231
|
-
const baseUrl = getApiEndpoint();
|
|
232
|
-
const url = `${baseUrl}${endpoint}`;
|
|
233
|
-
const response = await fetch(url, {
|
|
234
|
-
...options,
|
|
235
|
-
headers: {
|
|
236
|
-
...this.getHeaders(),
|
|
237
|
-
...options.headers
|
|
238
|
-
}
|
|
239
|
-
});
|
|
240
|
-
if (!response.ok) {
|
|
241
|
-
const error = await response.json().catch(() => ({ error: "Unknown error" }));
|
|
242
|
-
throw new Error(error.error || error.message || `HTTP ${response.status}`);
|
|
243
|
-
}
|
|
244
|
-
return response.json();
|
|
245
|
-
}
|
|
246
|
-
// Auth endpoints
|
|
247
|
-
async requestOtp(email) {
|
|
248
|
-
return this.request("/auth/otp/request", {
|
|
249
|
-
method: "POST",
|
|
250
|
-
body: JSON.stringify({ email })
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
async verifyOtp(token, otp) {
|
|
254
|
-
return this.request("/auth/otp/verify", {
|
|
255
|
-
method: "POST",
|
|
256
|
-
body: JSON.stringify({ token, otp })
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
async getCurrentUser() {
|
|
260
|
-
return this.request("/auth/me");
|
|
261
|
-
}
|
|
262
|
-
// Project endpoints
|
|
263
|
-
async getProjects() {
|
|
264
|
-
return this.request("/projects");
|
|
265
|
-
}
|
|
266
|
-
async getProject(id) {
|
|
267
|
-
return this.request(`/projects/${id}`);
|
|
268
|
-
}
|
|
269
|
-
async createOrUpdateProject(data) {
|
|
270
|
-
return this.request("/projects", {
|
|
271
|
-
method: "POST",
|
|
272
|
-
body: JSON.stringify(data)
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
async syncProject(id, data) {
|
|
276
|
-
return this.request(`/projects/${id}/sync`, {
|
|
277
|
-
method: "POST",
|
|
278
|
-
body: JSON.stringify(data)
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
async deleteProject(id) {
|
|
282
|
-
return this.request(`/projects/${id}`, {
|
|
283
|
-
method: "DELETE"
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
async addMemory(projectId, memory) {
|
|
287
|
-
return this.request(`/projects/${projectId}/memories`, {
|
|
288
|
-
method: "POST",
|
|
289
|
-
body: JSON.stringify(memory)
|
|
290
|
-
});
|
|
291
|
-
}
|
|
292
|
-
async deleteMemory(projectId, memoryId) {
|
|
293
|
-
return this.request(`/projects/${projectId}/memories/${memoryId}`, {
|
|
294
|
-
method: "DELETE"
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
async connectProjects(projectA, projectB, connectionType) {
|
|
298
|
-
return this.request("/projects/connect", {
|
|
299
|
-
method: "POST",
|
|
300
|
-
body: JSON.stringify({
|
|
301
|
-
projectA,
|
|
302
|
-
projectB,
|
|
303
|
-
connectionType: connectionType || "related"
|
|
304
|
-
})
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
|
-
async disconnectProjects(projectA, projectB) {
|
|
308
|
-
return this.request("/projects/disconnect", {
|
|
309
|
-
method: "DELETE",
|
|
310
|
-
body: JSON.stringify({ projectA, projectB })
|
|
311
|
-
});
|
|
312
|
-
}
|
|
313
|
-
async getStats() {
|
|
314
|
-
return this.request("/projects/stats");
|
|
315
|
-
}
|
|
316
|
-
// Find project by path
|
|
317
|
-
async findProjectByPath(path16) {
|
|
318
|
-
const projects = await this.getProjects();
|
|
319
|
-
return projects.find((p) => p.path === path16) || null;
|
|
320
|
-
}
|
|
321
|
-
// ============================================
|
|
322
|
-
// Secrets Vault Endpoints
|
|
323
|
-
// ============================================
|
|
324
|
-
/**
|
|
325
|
-
* List all secrets (metadata only, no values)
|
|
326
|
-
*/
|
|
327
|
-
async listSecrets(projectId) {
|
|
328
|
-
const params = projectId ? `?projectId=${projectId}` : "";
|
|
329
|
-
return this.request(`/secrets${params}`);
|
|
330
|
-
}
|
|
331
|
-
/**
|
|
332
|
-
* Add a new secret
|
|
333
|
-
*/
|
|
334
|
-
async addSecret(data) {
|
|
335
|
-
return this.request("/secrets", {
|
|
336
|
-
method: "POST",
|
|
337
|
-
body: JSON.stringify(data)
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
/**
|
|
341
|
-
* Get a secret value (decrypted)
|
|
342
|
-
*/
|
|
343
|
-
async getSecret(key, projectId) {
|
|
344
|
-
const params = projectId ? `?projectId=${projectId}` : "";
|
|
345
|
-
return this.request(`/secrets/${encodeURIComponent(key)}${params}`);
|
|
346
|
-
}
|
|
347
|
-
/**
|
|
348
|
-
* Delete a secret
|
|
349
|
-
*/
|
|
350
|
-
async deleteSecret(key, projectId) {
|
|
351
|
-
const params = projectId ? `?projectId=${projectId}` : "";
|
|
352
|
-
return this.request(`/secrets/${encodeURIComponent(key)}${params}`, {
|
|
353
|
-
method: "DELETE"
|
|
354
|
-
});
|
|
355
|
-
}
|
|
356
|
-
/**
|
|
357
|
-
* Get all secrets for injection (decrypted values)
|
|
358
|
-
* Used by session start hook
|
|
359
|
-
*/
|
|
360
|
-
async getSecretsForInjection(projectId) {
|
|
361
|
-
const params = projectId ? `?projectId=${projectId}` : "";
|
|
362
|
-
return this.request(`/secrets/inject${params}`);
|
|
363
|
-
}
|
|
364
|
-
// ============================================
|
|
365
|
-
// Settings Sync Endpoints (Phase 10)
|
|
366
|
-
// Pfad: /api/settings (nicht /api/user/settings)
|
|
367
|
-
// ============================================
|
|
368
|
-
/**
|
|
369
|
-
* Get current user settings from cloud
|
|
370
|
-
*/
|
|
371
|
-
async getUserSettings() {
|
|
372
|
-
return this.request("/settings");
|
|
373
|
-
}
|
|
374
|
-
/**
|
|
375
|
-
* Update user settings in cloud
|
|
376
|
-
*/
|
|
377
|
-
async updateUserSettings(data) {
|
|
378
|
-
return this.request("/settings", {
|
|
379
|
-
method: "PUT",
|
|
380
|
-
body: JSON.stringify(data)
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
|
-
/**
|
|
384
|
-
* Sync settings with conflict detection
|
|
385
|
-
*/
|
|
386
|
-
async syncUserSettings(data) {
|
|
387
|
-
return this.request("/settings/sync", {
|
|
388
|
-
method: "POST",
|
|
389
|
-
body: JSON.stringify(data)
|
|
390
|
-
});
|
|
391
|
-
}
|
|
392
|
-
/**
|
|
393
|
-
* Get settings change history
|
|
394
|
-
*/
|
|
395
|
-
async getSettingsHistory() {
|
|
396
|
-
return this.request("/settings/history");
|
|
397
|
-
}
|
|
398
|
-
/**
|
|
399
|
-
* Export settings
|
|
400
|
-
*/
|
|
401
|
-
async exportSettings() {
|
|
402
|
-
return this.request("/settings/export");
|
|
403
|
-
}
|
|
404
|
-
/**
|
|
405
|
-
* Import settings
|
|
406
|
-
*/
|
|
407
|
-
async importSettings(data) {
|
|
408
|
-
return this.request("/settings/import", {
|
|
409
|
-
method: "POST",
|
|
410
|
-
body: JSON.stringify(data)
|
|
411
|
-
});
|
|
412
|
-
}
|
|
413
|
-
// ============================================
|
|
414
|
-
// Dashboard/Analytics Endpoints (Phase 12)
|
|
415
|
-
// Pfad: /api/analytics (nicht /api/dashboard)
|
|
416
|
-
// ============================================
|
|
417
|
-
/**
|
|
418
|
-
* Get dashboard overview data (Pro Feature)
|
|
419
|
-
*/
|
|
420
|
-
async getDashboardOverview() {
|
|
421
|
-
return this.request("/analytics/overview");
|
|
422
|
-
}
|
|
423
|
-
/**
|
|
424
|
-
* Get usage statistics (Pro Feature)
|
|
425
|
-
*/
|
|
426
|
-
async getUsageStats() {
|
|
427
|
-
return this.request("/analytics/usage");
|
|
428
|
-
}
|
|
429
|
-
/**
|
|
430
|
-
* Get project analytics (Pro Feature)
|
|
431
|
-
*/
|
|
432
|
-
async getProjectAnalytics() {
|
|
433
|
-
return this.request("/analytics/projects");
|
|
434
|
-
}
|
|
435
|
-
/**
|
|
436
|
-
* Get activity feed (Pro Feature)
|
|
437
|
-
*/
|
|
438
|
-
async getActivityFeed() {
|
|
439
|
-
return this.request("/analytics/activity");
|
|
440
|
-
}
|
|
441
|
-
// Legacy aliases for backwards compatibility
|
|
442
|
-
async getDashboardProjects() {
|
|
443
|
-
return this.getProjectAnalytics();
|
|
444
|
-
}
|
|
445
|
-
async getDashboardAnalytics(days) {
|
|
446
|
-
return this.getUsageStats();
|
|
447
|
-
}
|
|
448
|
-
// ============================================
|
|
449
|
-
// Sessions Endpoints (Cloud-synced sessions)
|
|
450
|
-
// ============================================
|
|
451
|
-
/**
|
|
452
|
-
* Get all sessions from cloud
|
|
453
|
-
*/
|
|
454
|
-
async getSessions() {
|
|
455
|
-
return this.request("/sessions");
|
|
456
|
-
}
|
|
457
|
-
/**
|
|
458
|
-
* Sync a session to cloud
|
|
459
|
-
*/
|
|
460
|
-
async syncSession(data) {
|
|
461
|
-
return this.request("/sessions", {
|
|
462
|
-
method: "POST",
|
|
463
|
-
body: JSON.stringify(data)
|
|
464
|
-
});
|
|
465
|
-
}
|
|
466
|
-
/**
|
|
467
|
-
* Get a specific session from cloud
|
|
468
|
-
*/
|
|
469
|
-
async getSession(sessionId) {
|
|
470
|
-
return this.request(`/sessions/${sessionId}`);
|
|
471
|
-
}
|
|
472
|
-
/**
|
|
473
|
-
* Delete a session from cloud
|
|
474
|
-
*/
|
|
475
|
-
async deleteSession(sessionId) {
|
|
476
|
-
return this.request(`/sessions/${sessionId}`, {
|
|
477
|
-
method: "DELETE"
|
|
478
|
-
});
|
|
479
|
-
}
|
|
480
|
-
// ============================================
|
|
481
|
-
// Memories Endpoints (standalone)
|
|
482
|
-
// ============================================
|
|
483
|
-
/**
|
|
484
|
-
* Get all memories across projects
|
|
485
|
-
*/
|
|
486
|
-
async getAllMemories() {
|
|
487
|
-
return this.request("/memories");
|
|
488
|
-
}
|
|
489
|
-
/**
|
|
490
|
-
* Search memories
|
|
491
|
-
*/
|
|
492
|
-
async searchMemories(query) {
|
|
493
|
-
return this.request(`/memories/search?q=${encodeURIComponent(query)}`);
|
|
494
|
-
}
|
|
495
|
-
// ============================================
|
|
496
|
-
// Hooks Endpoints (Cloud-managed hooks)
|
|
497
|
-
// ============================================
|
|
498
|
-
/**
|
|
499
|
-
* Get hook configuration from cloud
|
|
500
|
-
*/
|
|
501
|
-
async getHooks() {
|
|
502
|
-
return this.request("/hooks");
|
|
503
|
-
}
|
|
504
|
-
/**
|
|
505
|
-
* Update hook configuration
|
|
506
|
-
*/
|
|
507
|
-
async updateHooks(hooks) {
|
|
508
|
-
return this.request("/hooks", {
|
|
509
|
-
method: "PUT",
|
|
510
|
-
body: JSON.stringify({ hooks })
|
|
511
|
-
});
|
|
512
|
-
}
|
|
513
|
-
// ============================================
|
|
514
|
-
// Two-Factor Authentication Endpoints (Phase 15)
|
|
515
|
-
// ============================================
|
|
516
|
-
/**
|
|
517
|
-
* Initialize 2FA setup
|
|
518
|
-
*/
|
|
519
|
-
async setup2FA() {
|
|
520
|
-
return this.request("/auth/2fa/setup", {
|
|
521
|
-
method: "POST"
|
|
522
|
-
});
|
|
523
|
-
}
|
|
524
|
-
/**
|
|
525
|
-
* Verify 2FA setup with code
|
|
526
|
-
*/
|
|
527
|
-
async verify2FA(code) {
|
|
528
|
-
return this.request("/auth/2fa/verify", {
|
|
529
|
-
method: "POST",
|
|
530
|
-
body: JSON.stringify({ code })
|
|
531
|
-
});
|
|
532
|
-
}
|
|
533
|
-
/**
|
|
534
|
-
* Verify 2FA code during login
|
|
535
|
-
*/
|
|
536
|
-
async verify2FACode(code) {
|
|
537
|
-
return this.request("/auth/2fa/check", {
|
|
538
|
-
method: "POST",
|
|
539
|
-
body: JSON.stringify({ code })
|
|
540
|
-
});
|
|
541
|
-
}
|
|
542
|
-
/**
|
|
543
|
-
* Verify backup code
|
|
544
|
-
*/
|
|
545
|
-
async verifyBackupCode(code) {
|
|
546
|
-
return this.request("/auth/2fa/backup", {
|
|
547
|
-
method: "POST",
|
|
548
|
-
body: JSON.stringify({ code })
|
|
549
|
-
});
|
|
550
|
-
}
|
|
551
|
-
/**
|
|
552
|
-
* Get 2FA status
|
|
553
|
-
*/
|
|
554
|
-
async get2FAStatus() {
|
|
555
|
-
return this.request("/auth/2fa/status");
|
|
556
|
-
}
|
|
557
|
-
/**
|
|
558
|
-
* Disable 2FA
|
|
559
|
-
*/
|
|
560
|
-
async disable2FA(code) {
|
|
561
|
-
return this.request("/auth/2fa", {
|
|
562
|
-
method: "DELETE",
|
|
563
|
-
body: JSON.stringify({ code })
|
|
564
|
-
});
|
|
565
|
-
}
|
|
566
|
-
/**
|
|
567
|
-
* Regenerate backup codes
|
|
568
|
-
*/
|
|
569
|
-
async regenerateBackupCodes() {
|
|
570
|
-
return this.request("/auth/2fa/backup-codes", {
|
|
571
|
-
method: "POST"
|
|
572
|
-
});
|
|
573
|
-
}
|
|
574
|
-
// ============================================
|
|
575
|
-
// Trusted Devices Endpoints (Phase 15)
|
|
576
|
-
// ============================================
|
|
577
|
-
/**
|
|
578
|
-
* Get all trusted devices
|
|
579
|
-
*/
|
|
580
|
-
async getDevices() {
|
|
581
|
-
return this.request("/auth/devices");
|
|
582
|
-
}
|
|
583
|
-
/**
|
|
584
|
-
* Trust a device
|
|
585
|
-
*/
|
|
586
|
-
async trustDevice(data) {
|
|
587
|
-
return this.request("/auth/devices", {
|
|
588
|
-
method: "POST",
|
|
589
|
-
body: JSON.stringify(data)
|
|
590
|
-
});
|
|
591
|
-
}
|
|
592
|
-
/**
|
|
593
|
-
* Revoke a device
|
|
594
|
-
*/
|
|
595
|
-
async revokeDevice(deviceId) {
|
|
596
|
-
return this.request(`/auth/devices/${deviceId}`, {
|
|
597
|
-
method: "DELETE"
|
|
598
|
-
});
|
|
599
|
-
}
|
|
600
|
-
/**
|
|
601
|
-
* Revoke all devices
|
|
602
|
-
*/
|
|
603
|
-
async revokeAllDevices() {
|
|
604
|
-
return this.request("/auth/devices/all", {
|
|
605
|
-
method: "DELETE"
|
|
606
|
-
});
|
|
607
|
-
}
|
|
608
|
-
// ============================================
|
|
609
|
-
// Project Security Endpoints (Phase 15)
|
|
610
|
-
// ============================================
|
|
611
|
-
/**
|
|
612
|
-
* Get project security config
|
|
613
|
-
*/
|
|
614
|
-
async getProjectSecurity(projectId) {
|
|
615
|
-
return this.request(`/projects/${projectId}/security`);
|
|
616
|
-
}
|
|
617
|
-
/**
|
|
618
|
-
* Update project security config
|
|
619
|
-
*/
|
|
620
|
-
async updateProjectSecurity(projectId, security) {
|
|
621
|
-
return this.request(`/projects/${projectId}/security`, {
|
|
622
|
-
method: "PUT",
|
|
623
|
-
body: JSON.stringify({ security })
|
|
624
|
-
});
|
|
625
|
-
}
|
|
626
|
-
// ============================================
|
|
627
|
-
// Project Team/Collaborators Endpoints (Phase 15)
|
|
628
|
-
// ============================================
|
|
629
|
-
/**
|
|
630
|
-
* Get project team
|
|
631
|
-
*/
|
|
632
|
-
async getProjectTeam(projectId) {
|
|
633
|
-
return this.request(`/projects/${projectId}/team`);
|
|
634
|
-
}
|
|
635
|
-
/**
|
|
636
|
-
* Add collaborator
|
|
637
|
-
*/
|
|
638
|
-
async addCollaborator(projectId, email, role) {
|
|
639
|
-
return this.request(`/projects/${projectId}/team`, {
|
|
640
|
-
method: "POST",
|
|
641
|
-
body: JSON.stringify({ email, role })
|
|
642
|
-
});
|
|
643
|
-
}
|
|
644
|
-
/**
|
|
645
|
-
* Remove collaborator
|
|
646
|
-
*/
|
|
647
|
-
async removeCollaborator(projectId, userId) {
|
|
648
|
-
return this.request(`/projects/${projectId}/team/${userId}`, {
|
|
649
|
-
method: "DELETE"
|
|
650
|
-
});
|
|
651
|
-
}
|
|
652
|
-
/**
|
|
653
|
-
* Update collaborator role
|
|
654
|
-
*/
|
|
655
|
-
async updateCollaboratorRole(projectId, userId, role) {
|
|
656
|
-
return this.request(`/projects/${projectId}/team/${userId}`, {
|
|
657
|
-
method: "PATCH",
|
|
658
|
-
body: JSON.stringify({ role })
|
|
659
|
-
});
|
|
660
|
-
}
|
|
661
|
-
/**
|
|
662
|
-
* Send project invitation
|
|
663
|
-
*/
|
|
664
|
-
async sendProjectInvite(projectId, email, role) {
|
|
665
|
-
return this.request(`/projects/${projectId}/invite`, {
|
|
666
|
-
method: "POST",
|
|
667
|
-
body: JSON.stringify({ email, role })
|
|
668
|
-
});
|
|
669
|
-
}
|
|
670
|
-
/**
|
|
671
|
-
* Transfer project ownership
|
|
672
|
-
*/
|
|
673
|
-
async transferProjectOwnership(projectId, newOwnerEmail) {
|
|
674
|
-
return this.request(`/projects/${projectId}/transfer`, {
|
|
675
|
-
method: "POST",
|
|
676
|
-
body: JSON.stringify({ email: newOwnerEmail })
|
|
677
|
-
});
|
|
678
|
-
}
|
|
679
|
-
};
|
|
680
|
-
var api = new ApiClient();
|
|
681
|
-
|
|
682
113
|
// src/utils/logger.ts
|
|
683
114
|
import chalk from "chalk";
|
|
684
115
|
var log = {
|
|
@@ -893,21 +324,21 @@ function generateBackupCodes(count = 10) {
|
|
|
893
324
|
return codes;
|
|
894
325
|
}
|
|
895
326
|
function generateDeviceFingerprint() {
|
|
896
|
-
const
|
|
327
|
+
const os7 = __require("os");
|
|
897
328
|
const components = [
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
329
|
+
os7.hostname(),
|
|
330
|
+
os7.platform(),
|
|
331
|
+
os7.arch(),
|
|
332
|
+
os7.cpus()[0]?.model || "unknown",
|
|
333
|
+
os7.userInfo().username
|
|
903
334
|
];
|
|
904
335
|
const fingerprint = crypto.createHash("sha256").update(components.join("|")).digest("hex").slice(0, 32);
|
|
905
336
|
return fingerprint;
|
|
906
337
|
}
|
|
907
338
|
function getDeviceName() {
|
|
908
|
-
const
|
|
909
|
-
const hostname =
|
|
910
|
-
const platform =
|
|
339
|
+
const os7 = __require("os");
|
|
340
|
+
const hostname = os7.hostname();
|
|
341
|
+
const platform = os7.platform();
|
|
911
342
|
const platformNames = {
|
|
912
343
|
darwin: "macOS",
|
|
913
344
|
linux: "Linux",
|
|
@@ -1457,11 +888,11 @@ function startCallbackServer(port) {
|
|
|
1457
888
|
});
|
|
1458
889
|
}
|
|
1459
890
|
async function loginWithBrowser() {
|
|
1460
|
-
const
|
|
891
|
+
const config = getConfig();
|
|
1461
892
|
try {
|
|
1462
893
|
const port = await findAvailablePort();
|
|
1463
894
|
const callbackUrl = `http://127.0.0.1:${port}/callback`;
|
|
1464
|
-
const baseUrl =
|
|
895
|
+
const baseUrl = config.apiEndpoint.replace("/api", "");
|
|
1465
896
|
const loginUrl = `${baseUrl}/auth/cli-login?callback=${encodeURIComponent(callbackUrl)}`;
|
|
1466
897
|
const serverPromise = startCallbackServer(port);
|
|
1467
898
|
log.newline();
|
|
@@ -1519,7 +950,7 @@ async function loginWithBrowser() {
|
|
|
1519
950
|
log.error(`Login fehlgeschlagen: ${message}`);
|
|
1520
951
|
log.newline();
|
|
1521
952
|
log.info("Fallback: Manueller Token-Eintrag");
|
|
1522
|
-
const loginUrl = `${
|
|
953
|
+
const loginUrl = `${config.apiEndpoint.replace("/api", "")}/auth/cli-login`;
|
|
1523
954
|
log.dim(`URL: ${loginUrl}`);
|
|
1524
955
|
log.newline();
|
|
1525
956
|
const { useManual } = await inquirer.prompt([{
|
|
@@ -1615,8 +1046,8 @@ async function prompt2FAVerification() {
|
|
|
1615
1046
|
// src/commands/auth/login.ts
|
|
1616
1047
|
var loginCommand = new Command("login").description("Mit shiva.li anmelden").option("-e, --email <email>", "Email-Adresse f\xFCr OTP-Login").option("--otp", "OTP-Login statt Browser verwenden").action(async (options) => {
|
|
1617
1048
|
if (isAuthenticated()) {
|
|
1618
|
-
const
|
|
1619
|
-
log.info(`Bereits angemeldet als ${
|
|
1049
|
+
const config = getConfig();
|
|
1050
|
+
log.info(`Bereits angemeldet als ${config.email}`);
|
|
1620
1051
|
const { relogin } = await inquirer2.prompt([
|
|
1621
1052
|
{
|
|
1622
1053
|
type: "confirm",
|
|
@@ -2292,10 +1723,10 @@ var statusCommand = new Command4("status").description("Status des aktuellen Pro
|
|
|
2292
1723
|
}
|
|
2293
1724
|
log.newline();
|
|
2294
1725
|
const stats = await api.getStats();
|
|
2295
|
-
const
|
|
1726
|
+
const config = getConfig();
|
|
2296
1727
|
log.keyValue(
|
|
2297
1728
|
"Tier",
|
|
2298
|
-
`${
|
|
1729
|
+
`${config.tier?.toUpperCase() || "FREE"} (${stats.projects.total}/${stats.projects.limit} Projekte)`
|
|
2299
1730
|
);
|
|
2300
1731
|
} catch (error) {
|
|
2301
1732
|
process.stdout.write("\x1B[1A\x1B[2K");
|
|
@@ -2405,9 +1836,9 @@ var Errors = {
|
|
|
2405
1836
|
"Bitte sp\xE4ter erneut versuchen"
|
|
2406
1837
|
),
|
|
2407
1838
|
// File/Path errors
|
|
2408
|
-
PATH_NOT_FOUND: (
|
|
1839
|
+
PATH_NOT_FOUND: (path15) => new ShivaError(
|
|
2409
1840
|
"PATH_404",
|
|
2410
|
-
|
|
1841
|
+
path15 ? `Pfad nicht gefunden: ${path15}` : "Pfad nicht gefunden",
|
|
2411
1842
|
"Pfad \xFCberpr\xFCfen und erneut versuchen"
|
|
2412
1843
|
),
|
|
2413
1844
|
FILE_NOT_FOUND: (file) => new ShivaError(
|
|
@@ -2415,9 +1846,9 @@ var Errors = {
|
|
|
2415
1846
|
file ? `Datei nicht gefunden: ${file}` : "Datei nicht gefunden",
|
|
2416
1847
|
void 0
|
|
2417
1848
|
),
|
|
2418
|
-
PERMISSION_DENIED: (
|
|
1849
|
+
PERMISSION_DENIED: (path15) => new ShivaError(
|
|
2419
1850
|
"PERMISSION_DENIED",
|
|
2420
|
-
|
|
1851
|
+
path15 ? `Keine Berechtigung: ${path15}` : "Keine Berechtigung",
|
|
2421
1852
|
"Berechtigungen pr\xFCfen oder mit sudo ausf\xFChren"
|
|
2422
1853
|
),
|
|
2423
1854
|
// Package errors
|
|
@@ -2684,8 +2115,8 @@ import ora3 from "ora";
|
|
|
2684
2115
|
|
|
2685
2116
|
// src/services/data/settings-sync.ts
|
|
2686
2117
|
import * as crypto2 from "crypto";
|
|
2687
|
-
import
|
|
2688
|
-
var settingsStore = new
|
|
2118
|
+
import Conf from "conf";
|
|
2119
|
+
var settingsStore = new Conf({
|
|
2689
2120
|
projectName: "shiva-code-settings",
|
|
2690
2121
|
defaults: {
|
|
2691
2122
|
syncableSettings: {
|
|
@@ -3092,7 +2523,7 @@ var configCommand = new Command6("config").description("Konfiguration anzeigen o
|
|
|
3092
2523
|
log.success("Konfiguration zur\xFCckgesetzt");
|
|
3093
2524
|
return;
|
|
3094
2525
|
}
|
|
3095
|
-
const
|
|
2526
|
+
const config = getConfig();
|
|
3096
2527
|
if (options.list || !key && !value) {
|
|
3097
2528
|
log.brand();
|
|
3098
2529
|
log.header("Konfiguration");
|
|
@@ -3100,9 +2531,9 @@ var configCommand = new Command6("config").description("Konfiguration anzeigen o
|
|
|
3100
2531
|
log.keyValue("Config Pfad", CONFIG_PATH);
|
|
3101
2532
|
log.newline();
|
|
3102
2533
|
console.log(colors.dim("Cloud:"));
|
|
3103
|
-
log.keyValue(" API Endpoint",
|
|
3104
|
-
log.keyValue(" User",
|
|
3105
|
-
log.keyValue(" Tier",
|
|
2534
|
+
log.keyValue(" API Endpoint", config.apiEndpoint || "https://shiva-ai-api.slither-mutiplayer.workers.dev");
|
|
2535
|
+
log.keyValue(" User", config.email || colors.dim("nicht angemeldet"));
|
|
2536
|
+
log.keyValue(" Tier", config.tier?.toUpperCase() || "FREE");
|
|
3106
2537
|
const token = getToken();
|
|
3107
2538
|
if (token) {
|
|
3108
2539
|
const masked = token.slice(0, 8) + "..." + token.slice(-4);
|
|
@@ -3129,7 +2560,7 @@ var configCommand = new Command6("config").description("Konfiguration anzeigen o
|
|
|
3129
2560
|
log.info(`G\xFCltige Schl\xFCssel: ${validKeys.join(", ")}`);
|
|
3130
2561
|
return;
|
|
3131
2562
|
}
|
|
3132
|
-
const configValue = key === "token" ? getToken() :
|
|
2563
|
+
const configValue = key === "token" ? getToken() : config[key];
|
|
3133
2564
|
if (configValue) {
|
|
3134
2565
|
if (key === "token") {
|
|
3135
2566
|
const masked = String(configValue).slice(0, 8) + "..." + String(configValue).slice(-4);
|
|
@@ -3164,13 +2595,13 @@ var configCommand = new Command6("config").description("Konfiguration anzeigen o
|
|
|
3164
2595
|
}
|
|
3165
2596
|
});
|
|
3166
2597
|
configCommand.command("get <key>").description("Konfigurationswert anzeigen").action((key) => {
|
|
3167
|
-
const
|
|
2598
|
+
const config = getConfig();
|
|
3168
2599
|
const validKeys = ["apiEndpoint", "email", "userId", "tier"];
|
|
3169
2600
|
if (!validKeys.includes(key)) {
|
|
3170
2601
|
log.error(`Unbekannter Schl\xFCssel: ${key}`);
|
|
3171
2602
|
return;
|
|
3172
2603
|
}
|
|
3173
|
-
const value =
|
|
2604
|
+
const value = config[key];
|
|
3174
2605
|
if (value) {
|
|
3175
2606
|
console.log(value);
|
|
3176
2607
|
} else {
|
|
@@ -3640,11 +3071,11 @@ var projectsCommand = new Command8("projects").description("Alle Projekte auflis
|
|
|
3640
3071
|
}
|
|
3641
3072
|
}
|
|
3642
3073
|
log.newline();
|
|
3643
|
-
const
|
|
3074
|
+
const config = getConfig();
|
|
3644
3075
|
const usagePercent = stats.projects.total / stats.projects.limit * 100;
|
|
3645
3076
|
if (usagePercent >= 80) {
|
|
3646
3077
|
log.warn(`Du nutzt ${Math.round(usagePercent)}% deines Projekt-Limits.`);
|
|
3647
|
-
if (
|
|
3078
|
+
if (config.tier === "free") {
|
|
3648
3079
|
log.info("Upgrade auf Pro f\xFCr mehr Projekte: https://shiva.li/pricing");
|
|
3649
3080
|
}
|
|
3650
3081
|
}
|
|
@@ -3688,45 +3119,45 @@ function getCurrentTimeInMinutes(timezone) {
|
|
|
3688
3119
|
const timeStr = now.toLocaleTimeString("de-DE", options);
|
|
3689
3120
|
return parseTime(timeStr);
|
|
3690
3121
|
}
|
|
3691
|
-
function checkTimeRestrictions(
|
|
3692
|
-
if (!
|
|
3122
|
+
function checkTimeRestrictions(config) {
|
|
3123
|
+
if (!config.enabled) {
|
|
3693
3124
|
return { allowed: true };
|
|
3694
3125
|
}
|
|
3695
|
-
const currentDay = getCurrentDayOfWeek(
|
|
3696
|
-
const currentMinutes = getCurrentTimeInMinutes(
|
|
3697
|
-
if (!
|
|
3126
|
+
const currentDay = getCurrentDayOfWeek(config.timezone);
|
|
3127
|
+
const currentMinutes = getCurrentTimeInMinutes(config.timezone);
|
|
3128
|
+
if (!config.allowedDays.includes(currentDay)) {
|
|
3698
3129
|
const dayNames = ["", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"];
|
|
3699
|
-
const allowedDayNames =
|
|
3130
|
+
const allowedDayNames = config.allowedDays.map((d) => dayNames[d]).join(", ");
|
|
3700
3131
|
return {
|
|
3701
3132
|
allowed: false,
|
|
3702
3133
|
reason: `Sessions sind nur an folgenden Tagen erlaubt: ${allowedDayNames}`,
|
|
3703
|
-
nextAllowedTime: `${dayNames[
|
|
3134
|
+
nextAllowedTime: `${dayNames[config.allowedDays[0]]} ${config.allowedHours.start}`
|
|
3704
3135
|
};
|
|
3705
3136
|
}
|
|
3706
|
-
const startMinutes = parseTime(
|
|
3707
|
-
const endMinutes = parseTime(
|
|
3137
|
+
const startMinutes = parseTime(config.allowedHours.start);
|
|
3138
|
+
const endMinutes = parseTime(config.allowedHours.end);
|
|
3708
3139
|
if (currentMinutes < startMinutes) {
|
|
3709
3140
|
return {
|
|
3710
3141
|
allowed: false,
|
|
3711
|
-
reason: `Sessions sind erst ab ${
|
|
3712
|
-
nextAllowedTime:
|
|
3142
|
+
reason: `Sessions sind erst ab ${config.allowedHours.start} erlaubt`,
|
|
3143
|
+
nextAllowedTime: config.allowedHours.start
|
|
3713
3144
|
};
|
|
3714
3145
|
}
|
|
3715
3146
|
if (currentMinutes >= endMinutes) {
|
|
3716
3147
|
return {
|
|
3717
3148
|
allowed: false,
|
|
3718
|
-
reason: `Sessions sind nur bis ${
|
|
3719
|
-
nextAllowedTime: `Morgen ${
|
|
3149
|
+
reason: `Sessions sind nur bis ${config.allowedHours.end} erlaubt`,
|
|
3150
|
+
nextAllowedTime: `Morgen ${config.allowedHours.start}`
|
|
3720
3151
|
};
|
|
3721
3152
|
}
|
|
3722
3153
|
return { allowed: true };
|
|
3723
3154
|
}
|
|
3724
|
-
function getRemainingSessionTime(
|
|
3725
|
-
if (!
|
|
3155
|
+
function getRemainingSessionTime(config) {
|
|
3156
|
+
if (!config.enabled) {
|
|
3726
3157
|
return null;
|
|
3727
3158
|
}
|
|
3728
|
-
const currentMinutes = getCurrentTimeInMinutes(
|
|
3729
|
-
const endMinutes = parseTime(
|
|
3159
|
+
const currentMinutes = getCurrentTimeInMinutes(config.timezone);
|
|
3160
|
+
const endMinutes = parseTime(config.allowedHours.end);
|
|
3730
3161
|
if (currentMinutes >= endMinutes) {
|
|
3731
3162
|
return 0;
|
|
3732
3163
|
}
|
|
@@ -3857,9 +3288,9 @@ function checkSessionLimits(limits, currentDuration = 0, currentTokens = 0) {
|
|
|
3857
3288
|
var SessionController = class {
|
|
3858
3289
|
projectPath;
|
|
3859
3290
|
config;
|
|
3860
|
-
constructor(projectPath,
|
|
3291
|
+
constructor(projectPath, config) {
|
|
3861
3292
|
this.projectPath = projectPath;
|
|
3862
|
-
this.config =
|
|
3293
|
+
this.config = config;
|
|
3863
3294
|
}
|
|
3864
3295
|
/**
|
|
3865
3296
|
* Check all session restrictions before starting
|
|
@@ -3965,8 +3396,8 @@ var SessionController = class {
|
|
|
3965
3396
|
return lines;
|
|
3966
3397
|
}
|
|
3967
3398
|
};
|
|
3968
|
-
function createSessionController(projectPath,
|
|
3969
|
-
return new SessionController(projectPath,
|
|
3399
|
+
function createSessionController(projectPath, config) {
|
|
3400
|
+
return new SessionController(projectPath, config);
|
|
3970
3401
|
}
|
|
3971
3402
|
function parseHoursString(hoursStr) {
|
|
3972
3403
|
const match = hoursStr.match(/^(\d{2}:\d{2})-(\d{2}:\d{2})$/);
|
|
@@ -4012,9 +3443,9 @@ var timeCommand = new Command9("time").description("Session-Zeitfenster konfigur
|
|
|
4012
3443
|
if (!hasShivaDir(projectPath)) {
|
|
4013
3444
|
initShivaDir(projectPath);
|
|
4014
3445
|
}
|
|
4015
|
-
const
|
|
3446
|
+
const config = getSessionConfig(projectPath);
|
|
4016
3447
|
if (options.status || Object.keys(options).length === 0) {
|
|
4017
|
-
displayTimeStatus(
|
|
3448
|
+
displayTimeStatus(config.timeControl);
|
|
4018
3449
|
return;
|
|
4019
3450
|
}
|
|
4020
3451
|
if (options.enable) {
|
|
@@ -4052,17 +3483,17 @@ var timeCommand = new Command9("time").description("Session-Zeitfenster konfigur
|
|
|
4052
3483
|
const updated = getSessionConfig(projectPath);
|
|
4053
3484
|
displayTimeStatus(updated.timeControl);
|
|
4054
3485
|
});
|
|
4055
|
-
function displayTimeStatus(
|
|
3486
|
+
function displayTimeStatus(config) {
|
|
4056
3487
|
log.newline();
|
|
4057
3488
|
console.log(colors.orange.bold("Session-Zeitkontrolle"));
|
|
4058
3489
|
console.log(colors.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
4059
3490
|
log.newline();
|
|
4060
|
-
log.keyValue("Status",
|
|
4061
|
-
log.keyValue("Arbeitszeiten", `${
|
|
3491
|
+
log.keyValue("Status", config.enabled ? colors.green("Aktiv") : colors.dim("Inaktiv"));
|
|
3492
|
+
log.keyValue("Arbeitszeiten", `${config.allowedHours.start} - ${config.allowedHours.end}`);
|
|
4062
3493
|
const dayNames = ["", "Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"];
|
|
4063
|
-
const days =
|
|
3494
|
+
const days = config.allowedDays.map((d) => dayNames[d]).join(", ");
|
|
4064
3495
|
log.keyValue("Erlaubte Tage", days);
|
|
4065
|
-
log.keyValue("Zeitzone",
|
|
3496
|
+
log.keyValue("Zeitzone", config.timezone);
|
|
4066
3497
|
log.newline();
|
|
4067
3498
|
}
|
|
4068
3499
|
projectCommand.addCommand(timeCommand);
|
|
@@ -4071,9 +3502,9 @@ var limitsCommand = new Command9("limits").description("Session-Limits konfiguri
|
|
|
4071
3502
|
if (!hasShivaDir(projectPath)) {
|
|
4072
3503
|
initShivaDir(projectPath);
|
|
4073
3504
|
}
|
|
4074
|
-
const
|
|
3505
|
+
const config = getSessionConfig(projectPath);
|
|
4075
3506
|
if (options.status || Object.keys(options).length === 0) {
|
|
4076
|
-
displayLimitsStatus(
|
|
3507
|
+
displayLimitsStatus(config.limits);
|
|
4077
3508
|
return;
|
|
4078
3509
|
}
|
|
4079
3510
|
if (options.reset) {
|
|
@@ -4115,14 +3546,14 @@ var limitsCommand = new Command9("limits").description("Session-Limits konfiguri
|
|
|
4115
3546
|
}
|
|
4116
3547
|
displayLimitsStatus(getSessionConfig(projectPath).limits);
|
|
4117
3548
|
});
|
|
4118
|
-
function displayLimitsStatus(
|
|
3549
|
+
function displayLimitsStatus(config) {
|
|
4119
3550
|
log.newline();
|
|
4120
3551
|
console.log(colors.orange.bold("Session-Limits"));
|
|
4121
3552
|
console.log(colors.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
4122
3553
|
log.newline();
|
|
4123
|
-
log.keyValue("Max. Dauer",
|
|
4124
|
-
log.keyValue("Max. Tokens",
|
|
4125
|
-
log.keyValue("Warnschwelle", `${(
|
|
3554
|
+
log.keyValue("Max. Dauer", config.maxDurationMinutes ? `${config.maxDurationMinutes} Minuten` : colors.dim("Unbegrenzt"));
|
|
3555
|
+
log.keyValue("Max. Tokens", config.maxTokens ? formatTokens(config.maxTokens) : colors.dim("Unbegrenzt"));
|
|
3556
|
+
log.keyValue("Warnschwelle", `${(config.warningThreshold * 100).toFixed(0)}%`);
|
|
4126
3557
|
log.newline();
|
|
4127
3558
|
}
|
|
4128
3559
|
projectCommand.addCommand(limitsCommand);
|
|
@@ -4131,9 +3562,9 @@ var budgetCommand = new Command9("budget").description("Token-Budget verwalten")
|
|
|
4131
3562
|
if (!hasShivaDir(projectPath)) {
|
|
4132
3563
|
initShivaDir(projectPath);
|
|
4133
3564
|
}
|
|
4134
|
-
const
|
|
3565
|
+
const config = getSessionConfig(projectPath);
|
|
4135
3566
|
if (options.status || Object.keys(options).length === 0) {
|
|
4136
|
-
displayBudgetStatus(
|
|
3567
|
+
displayBudgetStatus(config.budget);
|
|
4137
3568
|
return;
|
|
4138
3569
|
}
|
|
4139
3570
|
if (options.reset) {
|
|
@@ -4181,31 +3612,31 @@ var budgetCommand = new Command9("budget").description("Token-Budget verwalten")
|
|
|
4181
3612
|
}
|
|
4182
3613
|
displayBudgetStatus(getSessionConfig(projectPath).budget);
|
|
4183
3614
|
});
|
|
4184
|
-
function displayBudgetStatus(
|
|
3615
|
+
function displayBudgetStatus(config) {
|
|
4185
3616
|
log.newline();
|
|
4186
3617
|
console.log(colors.orange.bold("Token-Budget"));
|
|
4187
3618
|
console.log(colors.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
4188
3619
|
log.newline();
|
|
4189
|
-
if (
|
|
4190
|
-
const pct = (
|
|
4191
|
-
const bar = createProgressBar(
|
|
4192
|
-
log.keyValue("T\xE4glich", `${formatTokens(
|
|
3620
|
+
if (config.dailyTokenLimit) {
|
|
3621
|
+
const pct = (config.currentUsage.daily / config.dailyTokenLimit * 100).toFixed(0);
|
|
3622
|
+
const bar = createProgressBar(config.currentUsage.daily, config.dailyTokenLimit);
|
|
3623
|
+
log.keyValue("T\xE4glich", `${formatTokens(config.currentUsage.daily)}/${formatTokens(config.dailyTokenLimit)} (${pct}%)`);
|
|
4193
3624
|
console.log(` ${bar}`);
|
|
4194
3625
|
} else {
|
|
4195
3626
|
log.keyValue("T\xE4glich", colors.dim("Kein Limit"));
|
|
4196
3627
|
}
|
|
4197
|
-
if (
|
|
4198
|
-
const pct = (
|
|
4199
|
-
const bar = createProgressBar(
|
|
4200
|
-
log.keyValue("W\xF6chentl.", `${formatTokens(
|
|
3628
|
+
if (config.weeklyTokenLimit) {
|
|
3629
|
+
const pct = (config.currentUsage.weekly / config.weeklyTokenLimit * 100).toFixed(0);
|
|
3630
|
+
const bar = createProgressBar(config.currentUsage.weekly, config.weeklyTokenLimit);
|
|
3631
|
+
log.keyValue("W\xF6chentl.", `${formatTokens(config.currentUsage.weekly)}/${formatTokens(config.weeklyTokenLimit)} (${pct}%)`);
|
|
4201
3632
|
console.log(` ${bar}`);
|
|
4202
3633
|
} else {
|
|
4203
3634
|
log.keyValue("W\xF6chentl.", colors.dim("Kein Limit"));
|
|
4204
3635
|
}
|
|
4205
|
-
if (
|
|
4206
|
-
const pct = (
|
|
4207
|
-
const bar = createProgressBar(
|
|
4208
|
-
log.keyValue("Monatl.", `${formatTokens(
|
|
3636
|
+
if (config.monthlyTokenLimit) {
|
|
3637
|
+
const pct = (config.currentUsage.monthly / config.monthlyTokenLimit * 100).toFixed(0);
|
|
3638
|
+
const bar = createProgressBar(config.currentUsage.monthly, config.monthlyTokenLimit);
|
|
3639
|
+
log.keyValue("Monatl.", `${formatTokens(config.currentUsage.monthly)}/${formatTokens(config.monthlyTokenLimit)} (${pct}%)`);
|
|
4209
3640
|
console.log(` ${bar}`);
|
|
4210
3641
|
} else {
|
|
4211
3642
|
log.keyValue("Monatl.", colors.dim("Kein Limit"));
|
|
@@ -4225,9 +3656,9 @@ var dockerSubCommand = new Command9("docker").description("Projekt-spezifische D
|
|
|
4225
3656
|
if (!hasShivaDir(projectPath)) {
|
|
4226
3657
|
initShivaDir(projectPath);
|
|
4227
3658
|
}
|
|
4228
|
-
const
|
|
3659
|
+
const config = getProjectConfigV2(projectPath);
|
|
4229
3660
|
if (options.status || Object.keys(options).length === 0) {
|
|
4230
|
-
displayDockerStatus(
|
|
3661
|
+
displayDockerStatus(config.docker);
|
|
4231
3662
|
return;
|
|
4232
3663
|
}
|
|
4233
3664
|
if (options.enable) {
|
|
@@ -4256,11 +3687,11 @@ var dockerSubCommand = new Command9("docker").description("Projekt-spezifische D
|
|
|
4256
3687
|
log.success(`Netzwerk-Modus: ${options.network}`);
|
|
4257
3688
|
}
|
|
4258
3689
|
if (options.cpu) {
|
|
4259
|
-
updateProjectDockerConfig(projectPath, { resources: { cpuLimit: options.cpu, memoryLimit:
|
|
3690
|
+
updateProjectDockerConfig(projectPath, { resources: { cpuLimit: options.cpu, memoryLimit: config.docker.resources.memoryLimit } });
|
|
4260
3691
|
log.success(`CPU-Limit: ${options.cpu}`);
|
|
4261
3692
|
}
|
|
4262
3693
|
if (options.memory) {
|
|
4263
|
-
updateProjectDockerConfig(projectPath, { resources: { cpuLimit:
|
|
3694
|
+
updateProjectDockerConfig(projectPath, { resources: { cpuLimit: config.docker.resources.cpuLimit, memoryLimit: options.memory } });
|
|
4264
3695
|
log.success(`Memory-Limit: ${options.memory}`);
|
|
4265
3696
|
}
|
|
4266
3697
|
if (options.mount) {
|
|
@@ -4283,22 +3714,22 @@ var dockerSubCommand = new Command9("docker").description("Projekt-spezifische D
|
|
|
4283
3714
|
}
|
|
4284
3715
|
displayDockerStatus(getProjectConfigV2(projectPath).docker);
|
|
4285
3716
|
});
|
|
4286
|
-
function displayDockerStatus(
|
|
3717
|
+
function displayDockerStatus(config) {
|
|
4287
3718
|
log.newline();
|
|
4288
3719
|
console.log(colors.orange.bold("Docker-Konfiguration (Projekt)"));
|
|
4289
3720
|
console.log(colors.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
4290
3721
|
log.newline();
|
|
4291
|
-
const enabled =
|
|
3722
|
+
const enabled = config.enabled === "inherit" ? colors.dim("(erbt von global)") : config.enabled ? colors.green("Aktiviert") : colors.dim("Deaktiviert");
|
|
4292
3723
|
log.keyValue("Status", enabled);
|
|
4293
|
-
log.keyValue("Image",
|
|
4294
|
-
log.keyValue("Netzwerk",
|
|
4295
|
-
if (
|
|
4296
|
-
log.keyValue("Ressourcen", `CPU: ${
|
|
3724
|
+
log.keyValue("Image", config.image === "default" ? colors.dim("(Standard)") : config.image);
|
|
3725
|
+
log.keyValue("Netzwerk", config.network);
|
|
3726
|
+
if (config.resources.cpuLimit || config.resources.memoryLimit) {
|
|
3727
|
+
log.keyValue("Ressourcen", `CPU: ${config.resources.cpuLimit || "-"}, Memory: ${config.resources.memoryLimit || "-"}`);
|
|
4297
3728
|
}
|
|
4298
|
-
if (
|
|
3729
|
+
if (config.mounts.length > 0) {
|
|
4299
3730
|
log.newline();
|
|
4300
3731
|
log.plain("Mounts:");
|
|
4301
|
-
for (const mount of
|
|
3732
|
+
for (const mount of config.mounts) {
|
|
4302
3733
|
log.plain(` ${mount.host} -> ${mount.container} (${mount.mode})`);
|
|
4303
3734
|
}
|
|
4304
3735
|
}
|
|
@@ -4310,9 +3741,9 @@ var analyticsCommand = new Command9("analytics").description("Projekt-Analytics
|
|
|
4310
3741
|
if (!hasShivaDir(projectPath)) {
|
|
4311
3742
|
initShivaDir(projectPath);
|
|
4312
3743
|
}
|
|
4313
|
-
const
|
|
3744
|
+
const config = getAnalyticsConfig(projectPath);
|
|
4314
3745
|
if (options.status || Object.keys(options).length === 0) {
|
|
4315
|
-
displayAnalyticsStatus(
|
|
3746
|
+
displayAnalyticsStatus(config);
|
|
4316
3747
|
return;
|
|
4317
3748
|
}
|
|
4318
3749
|
if (options.enable) {
|
|
@@ -4342,15 +3773,15 @@ var analyticsCommand = new Command9("analytics").description("Projekt-Analytics
|
|
|
4342
3773
|
}
|
|
4343
3774
|
displayAnalyticsStatus(getAnalyticsConfig(projectPath));
|
|
4344
3775
|
});
|
|
4345
|
-
function displayAnalyticsStatus(
|
|
3776
|
+
function displayAnalyticsStatus(config) {
|
|
4346
3777
|
log.newline();
|
|
4347
3778
|
console.log(colors.orange.bold("Analytics-Konfiguration"));
|
|
4348
3779
|
console.log(colors.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
4349
3780
|
log.newline();
|
|
4350
|
-
log.keyValue("Status",
|
|
4351
|
-
log.keyValue("Token-Tracking",
|
|
4352
|
-
log.keyValue("Session-Historie",
|
|
4353
|
-
log.keyValue("Aufbewahrung", `${
|
|
3781
|
+
log.keyValue("Status", config.enabled ? colors.green("Aktiviert") : colors.dim("Deaktiviert"));
|
|
3782
|
+
log.keyValue("Token-Tracking", config.collectTokenUsage ? "Ja" : "Nein");
|
|
3783
|
+
log.keyValue("Session-Historie", config.collectSessionHistory ? "Ja" : "Nein");
|
|
3784
|
+
log.keyValue("Aufbewahrung", `${config.retentionDays} Tage`);
|
|
4354
3785
|
log.newline();
|
|
4355
3786
|
}
|
|
4356
3787
|
projectCommand.addCommand(analyticsCommand);
|
|
@@ -4371,15 +3802,15 @@ projectCommand.command("status").description("Projekt-Status anzeigen").action(a
|
|
|
4371
3802
|
log.info("Initialisiere mit: shiva project time --enable");
|
|
4372
3803
|
return;
|
|
4373
3804
|
}
|
|
4374
|
-
const
|
|
4375
|
-
const controller = createSessionController(projectPath,
|
|
3805
|
+
const config = getProjectConfigV2(projectPath);
|
|
3806
|
+
const controller = createSessionController(projectPath, config.session);
|
|
4376
3807
|
log.newline();
|
|
4377
3808
|
console.log(colors.orange.bold("SHIVA Projekt-Status"));
|
|
4378
3809
|
console.log(colors.dim("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"));
|
|
4379
3810
|
log.newline();
|
|
4380
3811
|
log.keyValue("Pfad", projectPath);
|
|
4381
|
-
log.keyValue("Config-Version", String(
|
|
4382
|
-
log.keyValue("Security-Tier",
|
|
3812
|
+
log.keyValue("Config-Version", String(config.version));
|
|
3813
|
+
log.keyValue("Security-Tier", config.security.tier);
|
|
4383
3814
|
log.newline();
|
|
4384
3815
|
const guard = controller.checkSessionStart();
|
|
4385
3816
|
if (guard.allowed) {
|
|
@@ -4405,19 +3836,19 @@ projectCommand.command("status").description("Projekt-Status anzeigen").action(a
|
|
|
4405
3836
|
// src/commands/session/start.ts
|
|
4406
3837
|
import { Command as Command10 } from "commander";
|
|
4407
3838
|
import * as fs from "fs";
|
|
4408
|
-
import * as
|
|
3839
|
+
import * as path3 from "path";
|
|
4409
3840
|
import ora6 from "ora";
|
|
4410
3841
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
4411
3842
|
|
|
4412
3843
|
// src/services/infrastructure/terminal.ts
|
|
4413
3844
|
import { spawn as spawn2, spawnSync as spawnSync2 } from "child_process";
|
|
4414
|
-
import * as
|
|
4415
|
-
import * as
|
|
3845
|
+
import * as path2 from "path";
|
|
3846
|
+
import * as os2 from "os";
|
|
4416
3847
|
|
|
4417
3848
|
// src/services/infrastructure/docker.ts
|
|
4418
3849
|
import { spawn, spawnSync } from "child_process";
|
|
4419
|
-
import * as
|
|
4420
|
-
import * as
|
|
3850
|
+
import * as path from "path";
|
|
3851
|
+
import * as os from "os";
|
|
4421
3852
|
var DockerService = class {
|
|
4422
3853
|
cachedInfo = null;
|
|
4423
3854
|
/**
|
|
@@ -4482,7 +3913,7 @@ var DockerService = class {
|
|
|
4482
3913
|
findDockerSocket(runtime) {
|
|
4483
3914
|
const possiblePaths = runtime === "docker" ? [
|
|
4484
3915
|
"/var/run/docker.sock",
|
|
4485
|
-
`${
|
|
3916
|
+
`${os.homedir()}/.docker/run/docker.sock`
|
|
4486
3917
|
] : [
|
|
4487
3918
|
`${process.env.XDG_RUNTIME_DIR || `/run/user/${process.getuid?.() || 1e3}`}/podman/podman.sock`,
|
|
4488
3919
|
"/var/run/podman/podman.sock"
|
|
@@ -4614,35 +4045,35 @@ var DockerService = class {
|
|
|
4614
4045
|
* Create a new container
|
|
4615
4046
|
* SECURITY: Uses spawnSync with array args, validates all inputs
|
|
4616
4047
|
*/
|
|
4617
|
-
async createContainer(
|
|
4048
|
+
async createContainer(config) {
|
|
4618
4049
|
const cmd = this.getCommand();
|
|
4619
4050
|
const args = ["create"];
|
|
4620
|
-
if (
|
|
4621
|
-
if (!this.isValidContainerNameInternal(
|
|
4622
|
-
throw new Error(`Invalid container name: ${sanitizeForLog(
|
|
4051
|
+
if (config.name) {
|
|
4052
|
+
if (!this.isValidContainerNameInternal(config.name)) {
|
|
4053
|
+
throw new Error(`Invalid container name: ${sanitizeForLog(config.name)}`);
|
|
4623
4054
|
}
|
|
4624
|
-
args.push("--name",
|
|
4055
|
+
args.push("--name", config.name);
|
|
4625
4056
|
}
|
|
4626
|
-
if (!isValidProjectPath(
|
|
4627
|
-
throw new Error(`Invalid workdir: ${sanitizeForLog(
|
|
4057
|
+
if (!isValidProjectPath(config.workdir)) {
|
|
4058
|
+
throw new Error(`Invalid workdir: ${sanitizeForLog(config.workdir)}`);
|
|
4628
4059
|
}
|
|
4629
|
-
args.push("--workdir",
|
|
4630
|
-
for (const mount of
|
|
4060
|
+
args.push("--workdir", config.workdir);
|
|
4061
|
+
for (const mount of config.mounts) {
|
|
4631
4062
|
if (!isValidProjectPath(mount.host)) {
|
|
4632
4063
|
log.warn(`Skipping invalid mount path: ${sanitizeForLog(mount.host)}`);
|
|
4633
4064
|
continue;
|
|
4634
4065
|
}
|
|
4635
4066
|
args.push("-v", `${mount.host}:${mount.container}:${mount.mode}`);
|
|
4636
4067
|
}
|
|
4637
|
-
for (const [key, value] of Object.entries(
|
|
4068
|
+
for (const [key, value] of Object.entries(config.env)) {
|
|
4638
4069
|
if (!/^[A-Z_][A-Z0-9_]*$/i.test(key)) {
|
|
4639
4070
|
log.warn(`Skipping invalid env var name: ${sanitizeForLog(key)}`);
|
|
4640
4071
|
continue;
|
|
4641
4072
|
}
|
|
4642
4073
|
args.push("-e", `${key}=${value}`);
|
|
4643
4074
|
}
|
|
4644
|
-
if (
|
|
4645
|
-
for (const [host, container] of Object.entries(
|
|
4075
|
+
if (config.ports) {
|
|
4076
|
+
for (const [host, container] of Object.entries(config.ports)) {
|
|
4646
4077
|
if (!/^\d+$/.test(String(host)) || !/^\d+$/.test(String(container))) {
|
|
4647
4078
|
log.warn(`Skipping invalid port mapping: ${host}:${container}`);
|
|
4648
4079
|
continue;
|
|
@@ -4650,16 +4081,16 @@ var DockerService = class {
|
|
|
4650
4081
|
args.push("-p", `${host}:${container}`);
|
|
4651
4082
|
}
|
|
4652
4083
|
}
|
|
4653
|
-
if (
|
|
4084
|
+
if (config.interactive) {
|
|
4654
4085
|
args.push("-it");
|
|
4655
4086
|
}
|
|
4656
|
-
if (
|
|
4087
|
+
if (config.autoRemove) {
|
|
4657
4088
|
args.push("--rm");
|
|
4658
4089
|
}
|
|
4659
|
-
if (!this.isValidImage(
|
|
4660
|
-
throw new Error(`Invalid image: ${sanitizeForLog(
|
|
4090
|
+
if (!this.isValidImage(config.image)) {
|
|
4091
|
+
throw new Error(`Invalid image: ${sanitizeForLog(config.image)}`);
|
|
4661
4092
|
}
|
|
4662
|
-
args.push(
|
|
4093
|
+
args.push(config.image);
|
|
4663
4094
|
try {
|
|
4664
4095
|
const result = spawnSync(cmd, args, {
|
|
4665
4096
|
encoding: "utf8",
|
|
@@ -4805,10 +4236,10 @@ var DockerService = class {
|
|
|
4805
4236
|
`${launch.projectPath}:/workspace:rw`,
|
|
4806
4237
|
// Mount Claude config
|
|
4807
4238
|
"-v",
|
|
4808
|
-
`${
|
|
4239
|
+
`${path.join(os.homedir(), ".claude")}:/root/.claude:rw`,
|
|
4809
4240
|
// Mount SHIVA config
|
|
4810
4241
|
"-v",
|
|
4811
|
-
`${
|
|
4242
|
+
`${path.join(os.homedir(), ".config", "shiva-code")}:/root/.config/shiva-code:rw`
|
|
4812
4243
|
];
|
|
4813
4244
|
for (const [host, container] of Object.entries(settings.volumeMounts || {})) {
|
|
4814
4245
|
if (isValidProjectPath(host)) {
|
|
@@ -4916,8 +4347,8 @@ var DockerService = class {
|
|
|
4916
4347
|
const settings = settingsSync.getDockerSettings();
|
|
4917
4348
|
return {
|
|
4918
4349
|
[projectPath]: "/workspace",
|
|
4919
|
-
[
|
|
4920
|
-
[
|
|
4350
|
+
[path.join(os.homedir(), ".claude")]: "/root/.claude",
|
|
4351
|
+
[path.join(os.homedir(), ".config", "shiva-code")]: "/root/.config/shiva-code",
|
|
4921
4352
|
...settings.volumeMounts
|
|
4922
4353
|
};
|
|
4923
4354
|
}
|
|
@@ -5132,8 +4563,8 @@ var DockerService = class {
|
|
|
5132
4563
|
}
|
|
5133
4564
|
}
|
|
5134
4565
|
args.push("-v", `${launch.projectPath}:/workspace:rw`);
|
|
5135
|
-
args.push("-v", `${
|
|
5136
|
-
args.push("-v", `${
|
|
4566
|
+
args.push("-v", `${path.join(os.homedir(), ".claude")}:/root/.claude:rw`);
|
|
4567
|
+
args.push("-v", `${path.join(os.homedir(), ".config", "shiva-code")}:/root/.config/shiva-code:rw`);
|
|
5137
4568
|
for (const mount of effectiveConfig.mounts) {
|
|
5138
4569
|
if (isValidProjectPath(mount.host)) {
|
|
5139
4570
|
args.push("-v", `${mount.host}:${mount.container}:${mount.mode}`);
|
|
@@ -5488,7 +4919,7 @@ Attaching to: ${sanitizeForLog(firstProject.projectName)}`);
|
|
|
5488
4919
|
}
|
|
5489
4920
|
function buildSecureDockerArgs(project, settings, containerName) {
|
|
5490
4921
|
const cmd = dockerService.getDockerInfo().runtime === "podman" ? "podman" : "docker";
|
|
5491
|
-
const homeDir =
|
|
4922
|
+
const homeDir = os2.homedir();
|
|
5492
4923
|
const args = [
|
|
5493
4924
|
cmd,
|
|
5494
4925
|
"run",
|
|
@@ -5501,9 +4932,9 @@ function buildSecureDockerArgs(project, settings, containerName) {
|
|
|
5501
4932
|
"-v",
|
|
5502
4933
|
`${project.projectPath}:/workspace:rw`,
|
|
5503
4934
|
"-v",
|
|
5504
|
-
`${
|
|
4935
|
+
`${path2.join(homeDir, ".claude")}:/root/.claude:rw`,
|
|
5505
4936
|
"-v",
|
|
5506
|
-
`${
|
|
4937
|
+
`${path2.join(homeDir, ".config", "shiva-code")}:/root/.config/shiva-code:rw`
|
|
5507
4938
|
];
|
|
5508
4939
|
for (const [hostPath, containerPath] of Object.entries(settings.volumeMounts || {})) {
|
|
5509
4940
|
if (isValidProjectPath(hostPath)) {
|
|
@@ -5572,9 +5003,9 @@ function getTerminalName(terminal) {
|
|
|
5572
5003
|
// src/services/sandbox/sandbox.ts
|
|
5573
5004
|
import { execSync } from "child_process";
|
|
5574
5005
|
import { existsSync as existsSync6, mkdirSync, rmSync, readdirSync as readdirSync2, copyFileSync, readFileSync as readFileSync2 } from "fs";
|
|
5575
|
-
import { join as
|
|
5006
|
+
import { join as join3, dirname } from "path";
|
|
5576
5007
|
import { randomUUID } from "crypto";
|
|
5577
|
-
import
|
|
5008
|
+
import Conf2 from "conf";
|
|
5578
5009
|
var DEFAULT_SANDBOX_CONFIG = {
|
|
5579
5010
|
enabled: false,
|
|
5580
5011
|
defaultMode: "worktree",
|
|
@@ -5597,7 +5028,7 @@ var DEFAULT_SANDBOX_CONFIG = {
|
|
|
5597
5028
|
],
|
|
5598
5029
|
maxSandboxes: 5
|
|
5599
5030
|
};
|
|
5600
|
-
var store = new
|
|
5031
|
+
var store = new Conf2({
|
|
5601
5032
|
projectName: "shiva-code",
|
|
5602
5033
|
defaults: {
|
|
5603
5034
|
sandboxConfig: DEFAULT_SANDBOX_CONFIG,
|
|
@@ -5611,10 +5042,10 @@ var SandboxService = class {
|
|
|
5611
5042
|
/**
|
|
5612
5043
|
* Check if a path is a git repository
|
|
5613
5044
|
*/
|
|
5614
|
-
isGitRepo(
|
|
5045
|
+
isGitRepo(path15) {
|
|
5615
5046
|
try {
|
|
5616
5047
|
execSync("git rev-parse --git-dir", {
|
|
5617
|
-
cwd:
|
|
5048
|
+
cwd: path15,
|
|
5618
5049
|
stdio: "pipe"
|
|
5619
5050
|
});
|
|
5620
5051
|
return true;
|
|
@@ -5654,7 +5085,7 @@ var SandboxService = class {
|
|
|
5654
5085
|
* Get the .shiva/sandbox directory path
|
|
5655
5086
|
*/
|
|
5656
5087
|
getSandboxDir(projectPath) {
|
|
5657
|
-
return
|
|
5088
|
+
return join3(projectPath, ".shiva", "sandbox");
|
|
5658
5089
|
}
|
|
5659
5090
|
/**
|
|
5660
5091
|
* Generate a unique session ID
|
|
@@ -5669,13 +5100,13 @@ var SandboxService = class {
|
|
|
5669
5100
|
* Create a new sandbox session
|
|
5670
5101
|
*/
|
|
5671
5102
|
async createSandbox(projectPath, mode) {
|
|
5672
|
-
const
|
|
5673
|
-
const actualMode = mode ||
|
|
5103
|
+
const config = this.getConfig();
|
|
5104
|
+
const actualMode = mode || config.defaultMode;
|
|
5674
5105
|
const sessionId = this.generateSessionId();
|
|
5675
5106
|
const existingSandboxes = this.listSandboxes(projectPath);
|
|
5676
|
-
if (existingSandboxes.length >=
|
|
5107
|
+
if (existingSandboxes.length >= config.maxSandboxes) {
|
|
5677
5108
|
throw new Error(
|
|
5678
|
-
`Maximum sandbox limit (${
|
|
5109
|
+
`Maximum sandbox limit (${config.maxSandboxes}) reached. Clean up old sandboxes first.`
|
|
5679
5110
|
);
|
|
5680
5111
|
}
|
|
5681
5112
|
let sandboxPath;
|
|
@@ -5687,7 +5118,7 @@ var SandboxService = class {
|
|
|
5687
5118
|
sandboxPath = await this.createWorktreeSandbox(projectPath, sessionId);
|
|
5688
5119
|
break;
|
|
5689
5120
|
case "copy":
|
|
5690
|
-
sandboxPath = await this.createCopySandbox(projectPath, sessionId,
|
|
5121
|
+
sandboxPath = await this.createCopySandbox(projectPath, sessionId, config.excludePaths);
|
|
5691
5122
|
break;
|
|
5692
5123
|
case "docker-overlay":
|
|
5693
5124
|
if (!this.isDockerAvailable()) {
|
|
@@ -5716,7 +5147,7 @@ var SandboxService = class {
|
|
|
5716
5147
|
*/
|
|
5717
5148
|
async createWorktreeSandbox(projectPath, sessionId) {
|
|
5718
5149
|
const sandboxDir = this.getSandboxDir(projectPath);
|
|
5719
|
-
const sandboxPath =
|
|
5150
|
+
const sandboxPath = join3(sandboxDir, `session-${sessionId}`);
|
|
5720
5151
|
mkdirSync(dirname(sandboxPath), { recursive: true });
|
|
5721
5152
|
const currentRef = execSync("git rev-parse HEAD", {
|
|
5722
5153
|
cwd: projectPath,
|
|
@@ -5740,11 +5171,11 @@ var SandboxService = class {
|
|
|
5740
5171
|
});
|
|
5741
5172
|
const untrackedFiles = untrackedOutput.split("\n").filter((f) => f.trim().length > 0);
|
|
5742
5173
|
for (const file of untrackedFiles) {
|
|
5743
|
-
const srcPath =
|
|
5744
|
-
const destPath =
|
|
5174
|
+
const srcPath = join3(projectPath, file);
|
|
5175
|
+
const destPath = join3(sandboxPath, file);
|
|
5745
5176
|
if (!existsSync6(srcPath)) continue;
|
|
5746
|
-
const
|
|
5747
|
-
if (
|
|
5177
|
+
const config = this.getConfig();
|
|
5178
|
+
if (config.excludePaths.some((excluded) => file.startsWith(excluded))) {
|
|
5748
5179
|
continue;
|
|
5749
5180
|
}
|
|
5750
5181
|
const destDir = dirname(destPath);
|
|
@@ -5761,7 +5192,7 @@ var SandboxService = class {
|
|
|
5761
5192
|
*/
|
|
5762
5193
|
async createCopySandbox(projectPath, sessionId, excludePaths) {
|
|
5763
5194
|
const sandboxDir = this.getSandboxDir(projectPath);
|
|
5764
|
-
const sandboxPath =
|
|
5195
|
+
const sandboxPath = join3(sandboxDir, `session-${sessionId}`);
|
|
5765
5196
|
mkdirSync(sandboxPath, { recursive: true });
|
|
5766
5197
|
this.copyDirectory(projectPath, sandboxPath, excludePaths);
|
|
5767
5198
|
return sandboxPath;
|
|
@@ -5772,8 +5203,8 @@ var SandboxService = class {
|
|
|
5772
5203
|
copyDirectory(src, dest, excludePaths) {
|
|
5773
5204
|
const entries = readdirSync2(src, { withFileTypes: true });
|
|
5774
5205
|
for (const entry of entries) {
|
|
5775
|
-
const srcPath =
|
|
5776
|
-
const destPath =
|
|
5206
|
+
const srcPath = join3(src, entry.name);
|
|
5207
|
+
const destPath = join3(dest, entry.name);
|
|
5777
5208
|
if (excludePaths.includes(entry.name)) {
|
|
5778
5209
|
continue;
|
|
5779
5210
|
}
|
|
@@ -5793,14 +5224,14 @@ var SandboxService = class {
|
|
|
5793
5224
|
*/
|
|
5794
5225
|
async createDockerOverlaySandbox(projectPath, sessionId) {
|
|
5795
5226
|
const sandboxDir = this.getSandboxDir(projectPath);
|
|
5796
|
-
const sandboxPath =
|
|
5797
|
-
const upperDir =
|
|
5798
|
-
const workDir =
|
|
5227
|
+
const sandboxPath = join3(sandboxDir, `session-${sessionId}`);
|
|
5228
|
+
const upperDir = join3(sandboxDir, `upper-${sessionId}`);
|
|
5229
|
+
const workDir = join3(sandboxDir, `work-${sessionId}`);
|
|
5799
5230
|
mkdirSync(sandboxPath, { recursive: true });
|
|
5800
5231
|
mkdirSync(upperDir, { recursive: true });
|
|
5801
5232
|
mkdirSync(workDir, { recursive: true });
|
|
5802
|
-
const
|
|
5803
|
-
this.copyDirectory(projectPath, sandboxPath,
|
|
5233
|
+
const config = this.getConfig();
|
|
5234
|
+
this.copyDirectory(projectPath, sandboxPath, config.excludePaths);
|
|
5804
5235
|
return sandboxPath;
|
|
5805
5236
|
}
|
|
5806
5237
|
/**
|
|
@@ -5923,7 +5354,7 @@ var SandboxService = class {
|
|
|
5923
5354
|
}
|
|
5924
5355
|
const untrackedFiles = untrackedOutput.split("\n").filter((f) => f.trim().length > 0);
|
|
5925
5356
|
for (const file of untrackedFiles) {
|
|
5926
|
-
const filePath =
|
|
5357
|
+
const filePath = join3(session.sandboxPath, file);
|
|
5927
5358
|
if (existsSync6(filePath)) {
|
|
5928
5359
|
const content = readFileSync2(filePath, "utf-8");
|
|
5929
5360
|
const lineCount = content.split("\n").length;
|
|
@@ -5956,19 +5387,19 @@ var SandboxService = class {
|
|
|
5956
5387
|
* Compare two directories and find changes
|
|
5957
5388
|
*/
|
|
5958
5389
|
async compareDirectories(originalPath, sandboxPath, relativePath, changes) {
|
|
5959
|
-
const
|
|
5390
|
+
const config = this.getConfig();
|
|
5960
5391
|
const sandboxEntries = /* @__PURE__ */ new Set();
|
|
5961
|
-
const sandboxFullPath =
|
|
5392
|
+
const sandboxFullPath = join3(sandboxPath, relativePath);
|
|
5962
5393
|
if (existsSync6(sandboxFullPath)) {
|
|
5963
5394
|
const entries = readdirSync2(sandboxFullPath, { withFileTypes: true });
|
|
5964
5395
|
for (const entry of entries) {
|
|
5965
|
-
if (
|
|
5396
|
+
if (config.excludePaths.includes(entry.name) || entry.name === ".shiva") {
|
|
5966
5397
|
continue;
|
|
5967
5398
|
}
|
|
5968
5399
|
sandboxEntries.add(entry.name);
|
|
5969
|
-
const entryRelPath = relativePath ?
|
|
5970
|
-
const originalEntryPath =
|
|
5971
|
-
const sandboxEntryPath =
|
|
5400
|
+
const entryRelPath = relativePath ? join3(relativePath, entry.name) : entry.name;
|
|
5401
|
+
const originalEntryPath = join3(originalPath, entryRelPath);
|
|
5402
|
+
const sandboxEntryPath = join3(sandboxPath, entryRelPath);
|
|
5972
5403
|
if (entry.isDirectory()) {
|
|
5973
5404
|
if (!existsSync6(originalEntryPath)) {
|
|
5974
5405
|
await this.countNewDirectoryChanges(sandboxEntryPath, entryRelPath, changes);
|
|
@@ -6002,16 +5433,16 @@ var SandboxService = class {
|
|
|
6002
5433
|
}
|
|
6003
5434
|
}
|
|
6004
5435
|
}
|
|
6005
|
-
const originalFullPath =
|
|
5436
|
+
const originalFullPath = join3(originalPath, relativePath);
|
|
6006
5437
|
if (existsSync6(originalFullPath)) {
|
|
6007
5438
|
const entries = readdirSync2(originalFullPath, { withFileTypes: true });
|
|
6008
5439
|
for (const entry of entries) {
|
|
6009
|
-
if (
|
|
5440
|
+
if (config.excludePaths.includes(entry.name) || entry.name === ".shiva") {
|
|
6010
5441
|
continue;
|
|
6011
5442
|
}
|
|
6012
5443
|
if (!sandboxEntries.has(entry.name)) {
|
|
6013
|
-
const entryRelPath = relativePath ?
|
|
6014
|
-
const originalEntryPath =
|
|
5444
|
+
const entryRelPath = relativePath ? join3(relativePath, entry.name) : entry.name;
|
|
5445
|
+
const originalEntryPath = join3(originalPath, entryRelPath);
|
|
6015
5446
|
if (entry.isDirectory()) {
|
|
6016
5447
|
await this.countDeletedDirectoryChanges(originalEntryPath, entryRelPath, changes);
|
|
6017
5448
|
} else {
|
|
@@ -6051,11 +5482,11 @@ var SandboxService = class {
|
|
|
6051
5482
|
*/
|
|
6052
5483
|
async countNewDirectoryChanges(dirPath, relativePath, changes) {
|
|
6053
5484
|
const entries = readdirSync2(dirPath, { withFileTypes: true });
|
|
6054
|
-
const
|
|
5485
|
+
const config = this.getConfig();
|
|
6055
5486
|
for (const entry of entries) {
|
|
6056
|
-
if (
|
|
6057
|
-
const entryRelPath =
|
|
6058
|
-
const entryPath =
|
|
5487
|
+
if (config.excludePaths.includes(entry.name)) continue;
|
|
5488
|
+
const entryRelPath = join3(relativePath, entry.name);
|
|
5489
|
+
const entryPath = join3(dirPath, entry.name);
|
|
6059
5490
|
if (entry.isDirectory()) {
|
|
6060
5491
|
await this.countNewDirectoryChanges(entryPath, entryRelPath, changes);
|
|
6061
5492
|
} else {
|
|
@@ -6075,11 +5506,11 @@ var SandboxService = class {
|
|
|
6075
5506
|
*/
|
|
6076
5507
|
async countDeletedDirectoryChanges(dirPath, relativePath, changes) {
|
|
6077
5508
|
const entries = readdirSync2(dirPath, { withFileTypes: true });
|
|
6078
|
-
const
|
|
5509
|
+
const config = this.getConfig();
|
|
6079
5510
|
for (const entry of entries) {
|
|
6080
|
-
if (
|
|
6081
|
-
const entryRelPath =
|
|
6082
|
-
const entryPath =
|
|
5511
|
+
if (config.excludePaths.includes(entry.name)) continue;
|
|
5512
|
+
const entryRelPath = join3(relativePath, entry.name);
|
|
5513
|
+
const entryPath = join3(dirPath, entry.name);
|
|
6083
5514
|
if (entry.isDirectory()) {
|
|
6084
5515
|
await this.countDeletedDirectoryChanges(entryPath, entryRelPath, changes);
|
|
6085
5516
|
} else {
|
|
@@ -6110,7 +5541,7 @@ var SandboxService = class {
|
|
|
6110
5541
|
});
|
|
6111
5542
|
return diff || "(no changes)";
|
|
6112
5543
|
} catch {
|
|
6113
|
-
const sandboxFilePath2 =
|
|
5544
|
+
const sandboxFilePath2 = join3(session.sandboxPath, filePath);
|
|
6114
5545
|
if (existsSync6(sandboxFilePath2)) {
|
|
6115
5546
|
const content = readFileSync2(sandboxFilePath2, "utf-8");
|
|
6116
5547
|
return `+++ ${filePath} (new file)
|
|
@@ -6119,8 +5550,8 @@ ${content.split("\n").map((l) => `+ ${l}`).join("\n")}`;
|
|
|
6119
5550
|
return "(file not found)";
|
|
6120
5551
|
}
|
|
6121
5552
|
}
|
|
6122
|
-
const originalPath =
|
|
6123
|
-
const sandboxFilePath =
|
|
5553
|
+
const originalPath = join3(session.projectPath, filePath);
|
|
5554
|
+
const sandboxFilePath = join3(session.sandboxPath, filePath);
|
|
6124
5555
|
const originalExists = existsSync6(originalPath);
|
|
6125
5556
|
const sandboxExists = existsSync6(sandboxFilePath);
|
|
6126
5557
|
if (!originalExists && sandboxExists) {
|
|
@@ -6178,8 +5609,8 @@ ${content.split("\n").map((l) => `- ${l}`).join("\n")}`;
|
|
|
6178
5609
|
for (const filePath of pathsToApply) {
|
|
6179
5610
|
const change = diff.changes.find((c) => c.path === filePath);
|
|
6180
5611
|
if (!change) continue;
|
|
6181
|
-
const srcPath =
|
|
6182
|
-
const destPath =
|
|
5612
|
+
const srcPath = join3(session.sandboxPath, filePath);
|
|
5613
|
+
const destPath = join3(session.projectPath, filePath);
|
|
6183
5614
|
if (change.type === "deleted") {
|
|
6184
5615
|
if (existsSync6(destPath)) {
|
|
6185
5616
|
rmSync(destPath, { force: true });
|
|
@@ -6195,8 +5626,8 @@ ${content.split("\n").map((l) => `- ${l}`).join("\n")}`;
|
|
|
6195
5626
|
}
|
|
6196
5627
|
}
|
|
6197
5628
|
this.updateSandboxStatus(sessionId, "applied");
|
|
6198
|
-
const
|
|
6199
|
-
if (
|
|
5629
|
+
const config = this.getConfig();
|
|
5630
|
+
if (config.autoCleanup) {
|
|
6200
5631
|
await this.deleteSandbox(sessionId);
|
|
6201
5632
|
}
|
|
6202
5633
|
}
|
|
@@ -6216,8 +5647,8 @@ ${content.split("\n").map((l) => `- ${l}`).join("\n")}`;
|
|
|
6216
5647
|
throw new Error(`Sandbox ${sessionId} not found`);
|
|
6217
5648
|
}
|
|
6218
5649
|
for (const filePath of filePaths) {
|
|
6219
|
-
const sandboxFilePath =
|
|
6220
|
-
const originalPath =
|
|
5650
|
+
const sandboxFilePath = join3(session.sandboxPath, filePath);
|
|
5651
|
+
const originalPath = join3(session.projectPath, filePath);
|
|
6221
5652
|
if (existsSync6(originalPath)) {
|
|
6222
5653
|
copyFileSync(originalPath, sandboxFilePath);
|
|
6223
5654
|
} else {
|
|
@@ -6234,8 +5665,8 @@ ${content.split("\n").map((l) => `- ${l}`).join("\n")}`;
|
|
|
6234
5665
|
* Clean up old sandboxes
|
|
6235
5666
|
*/
|
|
6236
5667
|
async cleanupOldSandboxes(maxAgeDays) {
|
|
6237
|
-
const
|
|
6238
|
-
const maxAge = maxAgeDays ||
|
|
5668
|
+
const config = this.getConfig();
|
|
5669
|
+
const maxAge = maxAgeDays || config.keepDays;
|
|
6239
5670
|
const cutoffDate = /* @__PURE__ */ new Date();
|
|
6240
5671
|
cutoffDate.setDate(cutoffDate.getDate() - maxAge);
|
|
6241
5672
|
const sessions = store.get("sessions");
|
|
@@ -6279,9 +5710,9 @@ ${content.split("\n").map((l) => `- ${l}`).join("\n")}`;
|
|
|
6279
5710
|
/**
|
|
6280
5711
|
* Update configuration
|
|
6281
5712
|
*/
|
|
6282
|
-
updateConfig(
|
|
5713
|
+
updateConfig(config) {
|
|
6283
5714
|
const current = this.getConfig();
|
|
6284
|
-
store.set("sandboxConfig", { ...current, ...
|
|
5715
|
+
store.set("sandboxConfig", { ...current, ...config });
|
|
6285
5716
|
}
|
|
6286
5717
|
/**
|
|
6287
5718
|
* Reset configuration to defaults
|
|
@@ -6314,7 +5745,7 @@ var startCommand = new Command10("start").description("Projekte starten (mit Git
|
|
|
6314
5745
|
const allProjects = await getAllClaudeProjects();
|
|
6315
5746
|
const launches = [];
|
|
6316
5747
|
for (const projektArg of projekte) {
|
|
6317
|
-
const absolutePath =
|
|
5748
|
+
const absolutePath = path3.resolve(projektArg);
|
|
6318
5749
|
if (fs.existsSync(absolutePath) && fs.statSync(absolutePath).isDirectory()) {
|
|
6319
5750
|
const project = findProjectFromArray(allProjects, absolutePath);
|
|
6320
5751
|
const latestSession = project?.latestSession;
|
|
@@ -7064,10 +6495,10 @@ import ora9 from "ora";
|
|
|
7064
6495
|
|
|
7065
6496
|
// src/services/data/tags.ts
|
|
7066
6497
|
import * as fs4 from "fs";
|
|
7067
|
-
import * as
|
|
7068
|
-
import * as
|
|
6498
|
+
import * as path4 from "path";
|
|
6499
|
+
import * as os3 from "os";
|
|
7069
6500
|
function getTagsPath() {
|
|
7070
|
-
return
|
|
6501
|
+
return path4.join(os3.homedir(), ".shiva", "tags.json");
|
|
7071
6502
|
}
|
|
7072
6503
|
function loadTagsData() {
|
|
7073
6504
|
const filepath = getTagsPath();
|
|
@@ -7083,7 +6514,7 @@ function loadTagsData() {
|
|
|
7083
6514
|
}
|
|
7084
6515
|
function saveTagsData(data) {
|
|
7085
6516
|
const filepath = getTagsPath();
|
|
7086
|
-
const dir =
|
|
6517
|
+
const dir = path4.dirname(filepath);
|
|
7087
6518
|
if (!fs4.existsSync(dir)) {
|
|
7088
6519
|
fs4.mkdirSync(dir, { recursive: true });
|
|
7089
6520
|
}
|
|
@@ -7335,10 +6766,10 @@ var sessionsCommand = new Command13("sessions").description("Alle Claude Code Se
|
|
|
7335
6766
|
log.dim(`Total: ${stats.activeProjects} Projekte, ${stats.totalSessions} Sessions`);
|
|
7336
6767
|
log.newline();
|
|
7337
6768
|
}));
|
|
7338
|
-
async function checkProjectExists(
|
|
6769
|
+
async function checkProjectExists(path15) {
|
|
7339
6770
|
try {
|
|
7340
6771
|
const fs15 = await import("fs");
|
|
7341
|
-
return fs15.existsSync(
|
|
6772
|
+
return fs15.existsSync(path15);
|
|
7342
6773
|
} catch {
|
|
7343
6774
|
return false;
|
|
7344
6775
|
}
|
|
@@ -7599,10 +7030,10 @@ sessionCommand.command("apply").description("Sandbox-\xC4nderungen \xFCbernehmen
|
|
|
7599
7030
|
log.header("Folgende \xC4nderungen werden \xFCbernommen:");
|
|
7600
7031
|
log.newline();
|
|
7601
7032
|
const pathsToApply = selectedPaths || diff.changes.map((c) => c.path);
|
|
7602
|
-
for (const
|
|
7603
|
-
const change = diff.changes.find((c) => c.path ===
|
|
7033
|
+
for (const path15 of pathsToApply) {
|
|
7034
|
+
const change = diff.changes.find((c) => c.path === path15);
|
|
7604
7035
|
if (change) {
|
|
7605
|
-
console.log(` ${formatChangeType(change.type)} ${
|
|
7036
|
+
console.log(` ${formatChangeType(change.type)} ${path15}`);
|
|
7606
7037
|
}
|
|
7607
7038
|
}
|
|
7608
7039
|
log.newline();
|
|
@@ -7759,18 +7190,18 @@ sessionCommand.command("config").description("Sandbox-Konfiguration verwalten").
|
|
|
7759
7190
|
log.success("Konfiguration zur\xFCckgesetzt");
|
|
7760
7191
|
return;
|
|
7761
7192
|
}
|
|
7762
|
-
const
|
|
7193
|
+
const config = sandboxService.getConfig();
|
|
7763
7194
|
if (options.show || Object.keys(options).length === 0) {
|
|
7764
7195
|
log.newline();
|
|
7765
7196
|
log.header("Sandbox Configuration");
|
|
7766
7197
|
log.newline();
|
|
7767
|
-
log.keyValue("Enabled",
|
|
7768
|
-
log.keyValue("Default Mode",
|
|
7769
|
-
log.keyValue("Auto Cleanup",
|
|
7770
|
-
log.keyValue("Keep Days", String(
|
|
7771
|
-
log.keyValue("Max Sandboxes", String(
|
|
7198
|
+
log.keyValue("Enabled", config.enabled ? colors.green("Yes") : colors.red("No"));
|
|
7199
|
+
log.keyValue("Default Mode", config.defaultMode);
|
|
7200
|
+
log.keyValue("Auto Cleanup", config.autoCleanup ? "Yes" : "No");
|
|
7201
|
+
log.keyValue("Keep Days", String(config.keepDays));
|
|
7202
|
+
log.keyValue("Max Sandboxes", String(config.maxSandboxes));
|
|
7772
7203
|
log.newline();
|
|
7773
|
-
log.keyValue("Exclude Paths",
|
|
7204
|
+
log.keyValue("Exclude Paths", config.excludePaths.join(", "));
|
|
7774
7205
|
return;
|
|
7775
7206
|
}
|
|
7776
7207
|
const updates = {};
|
|
@@ -7797,7 +7228,7 @@ sessionCommand.command("config").description("Sandbox-Konfiguration verwalten").
|
|
|
7797
7228
|
import { Command as Command15 } from "commander";
|
|
7798
7229
|
import { spawn as spawn5, spawnSync as spawnSync5 } from "child_process";
|
|
7799
7230
|
import * as fs5 from "fs";
|
|
7800
|
-
import * as
|
|
7231
|
+
import * as path5 from "path";
|
|
7801
7232
|
import inquirer6 from "inquirer";
|
|
7802
7233
|
var githubCommand = new Command15("github").description("GitHub Integration verwalten").action(() => {
|
|
7803
7234
|
showStatus();
|
|
@@ -7861,9 +7292,9 @@ function showStatus() {
|
|
|
7861
7292
|
console.log(colors.dim("SHIVA Integration:"));
|
|
7862
7293
|
if (hasShivaDir(cwd)) {
|
|
7863
7294
|
log.success(".shiva/ Ordner existiert");
|
|
7864
|
-
const
|
|
7865
|
-
log.keyValue(" Context Injection",
|
|
7866
|
-
log.keyValue(" Branch Sessions", String(Object.keys(
|
|
7295
|
+
const config = getProjectConfig(cwd);
|
|
7296
|
+
log.keyValue(" Context Injection", config.autoInjectContext ? "aktiviert" : "deaktiviert");
|
|
7297
|
+
log.keyValue(" Branch Sessions", String(Object.keys(config.branchSessions).length));
|
|
7867
7298
|
} else {
|
|
7868
7299
|
log.warn(".shiva/ nicht initialisiert");
|
|
7869
7300
|
log.info("Initialisieren mit: shiva github init");
|
|
@@ -7902,9 +7333,9 @@ function initProject(projectPath, skipGitignore) {
|
|
|
7902
7333
|
}
|
|
7903
7334
|
if (hasShivaDir(projectPath)) {
|
|
7904
7335
|
log.warn(".shiva/ existiert bereits");
|
|
7905
|
-
const
|
|
7906
|
-
log.keyValue("Version", String(
|
|
7907
|
-
log.keyValue("Branch Sessions", String(Object.keys(
|
|
7336
|
+
const config = getProjectConfig(projectPath);
|
|
7337
|
+
log.keyValue("Version", String(config.version));
|
|
7338
|
+
log.keyValue("Branch Sessions", String(Object.keys(config.branchSessions).length));
|
|
7908
7339
|
log.newline();
|
|
7909
7340
|
log.info('Nutze "shiva github status" f\xFCr Details');
|
|
7910
7341
|
return;
|
|
@@ -8219,9 +7650,9 @@ githubCommand.command("git-hook").description("Git Hooks f\xFCr Branch-Session I
|
|
|
8219
7650
|
log.error("Kein Git Repository");
|
|
8220
7651
|
return;
|
|
8221
7652
|
}
|
|
8222
|
-
const gitDir =
|
|
8223
|
-
const hooksDir =
|
|
8224
|
-
const hookFile =
|
|
7653
|
+
const gitDir = path5.join(cwd, ".git");
|
|
7654
|
+
const hooksDir = path5.join(gitDir, "hooks");
|
|
7655
|
+
const hookFile = path5.join(hooksDir, "post-checkout");
|
|
8225
7656
|
if (options.uninstall) {
|
|
8226
7657
|
if (fs5.existsSync(hookFile)) {
|
|
8227
7658
|
const content = fs5.readFileSync(hookFile, "utf-8");
|
|
@@ -8610,10 +8041,10 @@ var prsCommand = new Command17("prs").description("GitHub Pull Requests \xFCber
|
|
|
8610
8041
|
import { Command as Command18 } from "commander";
|
|
8611
8042
|
import { readFile } from "fs/promises";
|
|
8612
8043
|
import { existsSync as existsSync12 } from "fs";
|
|
8613
|
-
import { join as
|
|
8044
|
+
import { join as join6, resolve as resolve7 } from "path";
|
|
8614
8045
|
|
|
8615
8046
|
// src/services/security/package-scanner.ts
|
|
8616
|
-
import
|
|
8047
|
+
import Conf3 from "conf";
|
|
8617
8048
|
|
|
8618
8049
|
// src/types/package.ts
|
|
8619
8050
|
var DEFAULT_PACKAGE_SCAN_CONFIG = {
|
|
@@ -8900,7 +8331,7 @@ var KNOWN_MALICIOUS_PACKAGES = [
|
|
|
8900
8331
|
// src/services/security/package-scanner.ts
|
|
8901
8332
|
var CACHE_TTL = 60 * 60 * 1e3;
|
|
8902
8333
|
var packageInfoCache = /* @__PURE__ */ new Map();
|
|
8903
|
-
var configStore = new
|
|
8334
|
+
var configStore = new Conf3({
|
|
8904
8335
|
projectName: "shiva-code",
|
|
8905
8336
|
defaults: {
|
|
8906
8337
|
packageSecurity: DEFAULT_PACKAGE_SCAN_CONFIG
|
|
@@ -9171,8 +8602,8 @@ var PackageScannerService = class {
|
|
|
9171
8602
|
* Check download count
|
|
9172
8603
|
*/
|
|
9173
8604
|
checkDownloadCount(weeklyDownloads, manager) {
|
|
9174
|
-
const
|
|
9175
|
-
const minDownloads =
|
|
8605
|
+
const config = this.getConfig();
|
|
8606
|
+
const minDownloads = config.minDownloads;
|
|
9176
8607
|
if (weeklyDownloads < 10) {
|
|
9177
8608
|
return {
|
|
9178
8609
|
name: "Downloads",
|
|
@@ -9208,7 +8639,7 @@ var PackageScannerService = class {
|
|
|
9208
8639
|
* Check package age
|
|
9209
8640
|
*/
|
|
9210
8641
|
checkPublishAge(publishedAt) {
|
|
9211
|
-
const
|
|
8642
|
+
const config = this.getConfig();
|
|
9212
8643
|
const publishDate = new Date(publishedAt);
|
|
9213
8644
|
const now = /* @__PURE__ */ new Date();
|
|
9214
8645
|
const ageInDays = Math.floor((now.getTime() - publishDate.getTime()) / (1e3 * 60 * 60 * 24));
|
|
@@ -9220,11 +8651,11 @@ var PackageScannerService = class {
|
|
|
9220
8651
|
severity: "critical"
|
|
9221
8652
|
};
|
|
9222
8653
|
}
|
|
9223
|
-
if (ageInDays <
|
|
8654
|
+
if (ageInDays < config.maxAgeDays) {
|
|
9224
8655
|
return {
|
|
9225
8656
|
name: "Age",
|
|
9226
8657
|
status: "fail",
|
|
9227
|
-
message: `${ageInDays} days old (< ${
|
|
8658
|
+
message: `${ageInDays} days old (< ${config.maxAgeDays} days)`,
|
|
9228
8659
|
severity: "high"
|
|
9229
8660
|
};
|
|
9230
8661
|
}
|
|
@@ -9257,8 +8688,8 @@ var PackageScannerService = class {
|
|
|
9257
8688
|
* Check for typosquatting
|
|
9258
8689
|
*/
|
|
9259
8690
|
checkTyposquatting(name, manager) {
|
|
9260
|
-
const
|
|
9261
|
-
if (!
|
|
8691
|
+
const config = this.getConfig();
|
|
8692
|
+
if (!config.checkTyposquatting) {
|
|
9262
8693
|
return {
|
|
9263
8694
|
name: "Typosquatting",
|
|
9264
8695
|
status: "pass",
|
|
@@ -9286,8 +8717,8 @@ var PackageScannerService = class {
|
|
|
9286
8717
|
* Check install scripts for suspicious patterns
|
|
9287
8718
|
*/
|
|
9288
8719
|
checkScripts(scripts) {
|
|
9289
|
-
const
|
|
9290
|
-
if (!
|
|
8720
|
+
const config = this.getConfig();
|
|
8721
|
+
if (!config.checkScripts || !scripts) {
|
|
9291
8722
|
return {
|
|
9292
8723
|
name: "Scripts",
|
|
9293
8724
|
status: "pass",
|
|
@@ -9388,8 +8819,8 @@ var PackageScannerService = class {
|
|
|
9388
8819
|
* Check blocklist
|
|
9389
8820
|
*/
|
|
9390
8821
|
checkBlocklist(name, manager) {
|
|
9391
|
-
const
|
|
9392
|
-
const blocked =
|
|
8822
|
+
const config = this.getConfig();
|
|
8823
|
+
const blocked = config.blocklist.find((entry) => entry.package === name && entry.manager === manager);
|
|
9393
8824
|
if (blocked) {
|
|
9394
8825
|
return {
|
|
9395
8826
|
name: "Blocklist",
|
|
@@ -9420,8 +8851,8 @@ var PackageScannerService = class {
|
|
|
9420
8851
|
* Check allowlist
|
|
9421
8852
|
*/
|
|
9422
8853
|
isAllowlisted(name) {
|
|
9423
|
-
const
|
|
9424
|
-
return
|
|
8854
|
+
const config = this.getConfig();
|
|
8855
|
+
return config.allowlist.includes(name);
|
|
9425
8856
|
}
|
|
9426
8857
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
9427
8858
|
// Typosquatting Detection
|
|
@@ -9733,7 +9164,7 @@ var PackageScannerService = class {
|
|
|
9733
9164
|
* Generate hook output for Claude Code
|
|
9734
9165
|
*/
|
|
9735
9166
|
generateHookOutput(results) {
|
|
9736
|
-
const
|
|
9167
|
+
const config = this.getConfig();
|
|
9737
9168
|
const blockedPackages = results.filter((r) => r.recommendation === "block");
|
|
9738
9169
|
const warnPackages = results.filter((r) => r.recommendation === "warn");
|
|
9739
9170
|
if (blockedPackages.length > 0) {
|
|
@@ -9750,7 +9181,7 @@ var PackageScannerService = class {
|
|
|
9750
9181
|
|
|
9751
9182
|
Did you mean: ${pkg.suggestion}?`;
|
|
9752
9183
|
}
|
|
9753
|
-
if (
|
|
9184
|
+
if (config.autoBlock) {
|
|
9754
9185
|
return {
|
|
9755
9186
|
decision: "block",
|
|
9756
9187
|
reason
|
|
@@ -9790,64 +9221,64 @@ Continue with caution.`
|
|
|
9790
9221
|
* Add a package to the blocklist
|
|
9791
9222
|
*/
|
|
9792
9223
|
addToBlocklist(entry) {
|
|
9793
|
-
const
|
|
9794
|
-
const existing =
|
|
9224
|
+
const config = this.getConfig();
|
|
9225
|
+
const existing = config.blocklist.find(
|
|
9795
9226
|
(e) => e.package === entry.package && e.manager === entry.manager
|
|
9796
9227
|
);
|
|
9797
9228
|
if (existing) {
|
|
9798
9229
|
existing.reason = entry.reason;
|
|
9799
9230
|
existing.source = entry.source;
|
|
9800
9231
|
} else {
|
|
9801
|
-
|
|
9232
|
+
config.blocklist.push({
|
|
9802
9233
|
...entry,
|
|
9803
9234
|
addedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
9804
9235
|
});
|
|
9805
9236
|
}
|
|
9806
|
-
this.updateConfig(
|
|
9237
|
+
this.updateConfig(config);
|
|
9807
9238
|
}
|
|
9808
9239
|
/**
|
|
9809
9240
|
* Remove a package from the blocklist
|
|
9810
9241
|
*/
|
|
9811
9242
|
removeFromBlocklist(packageName, manager) {
|
|
9812
|
-
const
|
|
9813
|
-
const index =
|
|
9243
|
+
const config = this.getConfig();
|
|
9244
|
+
const index = config.blocklist.findIndex(
|
|
9814
9245
|
(e) => e.package === packageName && e.manager === manager
|
|
9815
9246
|
);
|
|
9816
9247
|
if (index === -1) {
|
|
9817
9248
|
return false;
|
|
9818
9249
|
}
|
|
9819
|
-
|
|
9820
|
-
this.updateConfig(
|
|
9250
|
+
config.blocklist.splice(index, 1);
|
|
9251
|
+
this.updateConfig(config);
|
|
9821
9252
|
return true;
|
|
9822
9253
|
}
|
|
9823
9254
|
/**
|
|
9824
9255
|
* Check if a package is blocked
|
|
9825
9256
|
*/
|
|
9826
9257
|
isBlocked(name, manager) {
|
|
9827
|
-
const
|
|
9828
|
-
return
|
|
9258
|
+
const config = this.getConfig();
|
|
9259
|
+
return config.blocklist.some((e) => e.package === name && e.manager === manager) || KNOWN_MALICIOUS_PACKAGES.some((e) => e.package === name && e.manager === manager);
|
|
9829
9260
|
}
|
|
9830
9261
|
/**
|
|
9831
9262
|
* Add a package to the allowlist
|
|
9832
9263
|
*/
|
|
9833
9264
|
addToAllowlist(packageName) {
|
|
9834
|
-
const
|
|
9835
|
-
if (!
|
|
9836
|
-
|
|
9837
|
-
this.updateConfig(
|
|
9265
|
+
const config = this.getConfig();
|
|
9266
|
+
if (!config.allowlist.includes(packageName)) {
|
|
9267
|
+
config.allowlist.push(packageName);
|
|
9268
|
+
this.updateConfig(config);
|
|
9838
9269
|
}
|
|
9839
9270
|
}
|
|
9840
9271
|
/**
|
|
9841
9272
|
* Remove a package from the allowlist
|
|
9842
9273
|
*/
|
|
9843
9274
|
removeFromAllowlist(packageName) {
|
|
9844
|
-
const
|
|
9845
|
-
const index =
|
|
9275
|
+
const config = this.getConfig();
|
|
9276
|
+
const index = config.allowlist.indexOf(packageName);
|
|
9846
9277
|
if (index === -1) {
|
|
9847
9278
|
return false;
|
|
9848
9279
|
}
|
|
9849
|
-
|
|
9850
|
-
this.updateConfig(
|
|
9280
|
+
config.allowlist.splice(index, 1);
|
|
9281
|
+
this.updateConfig(config);
|
|
9851
9282
|
return true;
|
|
9852
9283
|
}
|
|
9853
9284
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -9862,9 +9293,9 @@ Continue with caution.`
|
|
|
9862
9293
|
/**
|
|
9863
9294
|
* Update configuration
|
|
9864
9295
|
*/
|
|
9865
|
-
updateConfig(
|
|
9296
|
+
updateConfig(config) {
|
|
9866
9297
|
const current = this.getConfig();
|
|
9867
|
-
configStore.set("packageSecurity", { ...current, ...
|
|
9298
|
+
configStore.set("packageSecurity", { ...current, ...config });
|
|
9868
9299
|
}
|
|
9869
9300
|
/**
|
|
9870
9301
|
* Reset configuration to defaults
|
|
@@ -9963,9 +9394,9 @@ async function parsePackageJson(filePath) {
|
|
|
9963
9394
|
}
|
|
9964
9395
|
const dir = resolve7(filePath, "..");
|
|
9965
9396
|
let manager = "npm";
|
|
9966
|
-
if (existsSync12(
|
|
9397
|
+
if (existsSync12(join6(dir, "pnpm-lock.yaml"))) {
|
|
9967
9398
|
manager = "pnpm";
|
|
9968
|
-
} else if (existsSync12(
|
|
9399
|
+
} else if (existsSync12(join6(dir, "yarn.lock"))) {
|
|
9969
9400
|
manager = "yarn";
|
|
9970
9401
|
}
|
|
9971
9402
|
return { packages, manager };
|
|
@@ -10006,22 +9437,22 @@ async function parseCargoToml(filePath) {
|
|
|
10006
9437
|
}
|
|
10007
9438
|
return packages;
|
|
10008
9439
|
}
|
|
10009
|
-
function displayConfig(
|
|
9440
|
+
function displayConfig(config) {
|
|
10010
9441
|
log.header("Package Security Config");
|
|
10011
9442
|
log.newline();
|
|
10012
|
-
log.keyValue("Enabled",
|
|
10013
|
-
log.keyValue("Auto-block",
|
|
10014
|
-
log.keyValue("Min downloads", `${
|
|
10015
|
-
log.keyValue("Max age", `${
|
|
10016
|
-
log.keyValue("Typosquatting check",
|
|
10017
|
-
log.keyValue("Script check",
|
|
9443
|
+
log.keyValue("Enabled", config.enabled ? colors.green("Yes") : colors.red("No"));
|
|
9444
|
+
log.keyValue("Auto-block", config.autoBlock ? colors.red("Yes") : colors.green("No"));
|
|
9445
|
+
log.keyValue("Min downloads", `${config.minDownloads}/week`);
|
|
9446
|
+
log.keyValue("Max age", `${config.maxAgeDays} days`);
|
|
9447
|
+
log.keyValue("Typosquatting check", config.checkTyposquatting ? "Yes" : "No");
|
|
9448
|
+
log.keyValue("Script check", config.checkScripts ? "Yes" : "No");
|
|
10018
9449
|
log.newline();
|
|
10019
|
-
log.keyValue("Blocklist entries", `${
|
|
10020
|
-
log.keyValue("Allowlist entries", `${
|
|
9450
|
+
log.keyValue("Blocklist entries", `${config.blocklist.length}`);
|
|
9451
|
+
log.keyValue("Allowlist entries", `${config.allowlist.length}`);
|
|
10021
9452
|
}
|
|
10022
9453
|
var scanCommand = new Command18("scan").description("Scanne Packages auf Sicherheitsrisiken").argument("[packages...]", "Package names to scan").option("-m, --manager <manager>", "Package manager (npm, pip, cargo)", "npm").option("-f, --file <file>", "Scan dependencies from file (package.json, requirements.txt, Cargo.toml)").option("-c, --command <command>", "Scan packages from install command").option("--project", "Scan all dependencies in current project").option("--hook-mode", "Output in hook format (JSON)").option("-j, --json", "Output as JSON").option("-v, --verbose", "Show detailed output").action(async (packages, options) => {
|
|
10023
|
-
const
|
|
10024
|
-
if (!
|
|
9454
|
+
const config = packageScanner.getConfig();
|
|
9455
|
+
if (!config.enabled && !options.hookMode) {
|
|
10025
9456
|
log.warn("Package scanning is disabled. Enable it with: shiva scan config --enable");
|
|
10026
9457
|
return;
|
|
10027
9458
|
}
|
|
@@ -10066,15 +9497,15 @@ var scanCommand = new Command18("scan").description("Scanne Packages auf Sicherh
|
|
|
10066
9497
|
}
|
|
10067
9498
|
if (options.project) {
|
|
10068
9499
|
const cwd = process.cwd();
|
|
10069
|
-
if (existsSync12(
|
|
10070
|
-
const parsed = await parsePackageJson(
|
|
9500
|
+
if (existsSync12(join6(cwd, "package.json"))) {
|
|
9501
|
+
const parsed = await parsePackageJson(join6(cwd, "package.json"));
|
|
10071
9502
|
packagesToScan = parsed.packages;
|
|
10072
9503
|
manager = parsed.manager;
|
|
10073
|
-
} else if (existsSync12(
|
|
10074
|
-
packagesToScan = await parseRequirementsTxt(
|
|
9504
|
+
} else if (existsSync12(join6(cwd, "requirements.txt"))) {
|
|
9505
|
+
packagesToScan = await parseRequirementsTxt(join6(cwd, "requirements.txt"));
|
|
10075
9506
|
manager = "pip";
|
|
10076
|
-
} else if (existsSync12(
|
|
10077
|
-
packagesToScan = await parseCargoToml(
|
|
9507
|
+
} else if (existsSync12(join6(cwd, "Cargo.toml"))) {
|
|
9508
|
+
packagesToScan = await parseCargoToml(join6(cwd, "Cargo.toml"));
|
|
10078
9509
|
manager = "cargo";
|
|
10079
9510
|
} else {
|
|
10080
9511
|
log.error("No dependency file found in current directory");
|
|
@@ -10138,14 +9569,14 @@ var blocklistCommand = new Command18("blocklist").description("Verwalte Package-
|
|
|
10138
9569
|
}
|
|
10139
9570
|
return;
|
|
10140
9571
|
}
|
|
10141
|
-
const
|
|
10142
|
-
if (
|
|
9572
|
+
const config = packageScanner.getConfig();
|
|
9573
|
+
if (config.blocklist.length === 0) {
|
|
10143
9574
|
log.info("Blocklist is empty");
|
|
10144
9575
|
return;
|
|
10145
9576
|
}
|
|
10146
9577
|
log.header("Blocked Packages");
|
|
10147
9578
|
log.newline();
|
|
10148
|
-
for (const entry of
|
|
9579
|
+
for (const entry of config.blocklist) {
|
|
10149
9580
|
log.plain(`${colors.red("\u2717")} ${entry.package} (${entry.manager})`);
|
|
10150
9581
|
log.plain(colors.dim(` Reason: ${entry.reason}`));
|
|
10151
9582
|
log.plain(colors.dim(` Added: ${entry.addedAt} (${entry.source})`));
|
|
@@ -10166,14 +9597,14 @@ var allowlistCommand = new Command18("allowlist").description("Verwalte Package-
|
|
|
10166
9597
|
}
|
|
10167
9598
|
return;
|
|
10168
9599
|
}
|
|
10169
|
-
const
|
|
10170
|
-
if (
|
|
9600
|
+
const config = packageScanner.getConfig();
|
|
9601
|
+
if (config.allowlist.length === 0) {
|
|
10171
9602
|
log.info("Allowlist is empty");
|
|
10172
9603
|
return;
|
|
10173
9604
|
}
|
|
10174
9605
|
log.header("Allowed Packages");
|
|
10175
9606
|
log.newline();
|
|
10176
|
-
for (const pkg of
|
|
9607
|
+
for (const pkg of config.allowlist) {
|
|
10177
9608
|
log.plain(`${colors.green("\u2713")} ${pkg}`);
|
|
10178
9609
|
}
|
|
10179
9610
|
});
|
|
@@ -10230,9 +9661,9 @@ var permissionsCommand = new Command19("permissions").description("Permission-By
|
|
|
10230
9661
|
if (!hasShivaDir(projectPath)) {
|
|
10231
9662
|
initShivaDir(projectPath);
|
|
10232
9663
|
}
|
|
10233
|
-
const
|
|
9664
|
+
const config = getSecurityConfig(projectPath);
|
|
10234
9665
|
if (options.status || Object.keys(options).filter((k) => k !== "noSkip").length === 0) {
|
|
10235
|
-
displayPermissionsStatus(
|
|
9666
|
+
displayPermissionsStatus(config.permissions);
|
|
10236
9667
|
return;
|
|
10237
9668
|
}
|
|
10238
9669
|
if (options.skip) {
|
|
@@ -10248,7 +9679,7 @@ var permissionsCommand = new Command19("permissions").description("Permission-By
|
|
|
10248
9679
|
log.success("Permissions werden von global geerbt");
|
|
10249
9680
|
}
|
|
10250
9681
|
if (options.blockTool) {
|
|
10251
|
-
const current =
|
|
9682
|
+
const current = config.permissions.blockedTools;
|
|
10252
9683
|
if (!current.includes(options.blockTool)) {
|
|
10253
9684
|
updatePermissions(projectPath, { blockedTools: [...current, options.blockTool] });
|
|
10254
9685
|
log.success(`Tool blockiert: ${options.blockTool}`);
|
|
@@ -10257,21 +9688,21 @@ var permissionsCommand = new Command19("permissions").description("Permission-By
|
|
|
10257
9688
|
}
|
|
10258
9689
|
}
|
|
10259
9690
|
if (options.unblockTool) {
|
|
10260
|
-
const current =
|
|
9691
|
+
const current = config.permissions.blockedTools;
|
|
10261
9692
|
updatePermissions(projectPath, {
|
|
10262
9693
|
blockedTools: current.filter((t) => t !== options.unblockTool)
|
|
10263
9694
|
});
|
|
10264
9695
|
log.success(`Tool-Block aufgehoben: ${options.unblockTool}`);
|
|
10265
9696
|
}
|
|
10266
9697
|
if (options.allowPath) {
|
|
10267
|
-
const current =
|
|
9698
|
+
const current = config.permissions.allowedPaths;
|
|
10268
9699
|
if (!current.includes(options.allowPath)) {
|
|
10269
9700
|
updatePermissions(projectPath, { allowedPaths: [...current, options.allowPath] });
|
|
10270
9701
|
log.success(`Pfad erlaubt: ${options.allowPath}`);
|
|
10271
9702
|
}
|
|
10272
9703
|
}
|
|
10273
9704
|
if (options.blockPath) {
|
|
10274
|
-
const current =
|
|
9705
|
+
const current = config.permissions.blockedPaths;
|
|
10275
9706
|
if (!current.includes(options.blockPath)) {
|
|
10276
9707
|
updatePermissions(projectPath, { blockedPaths: [...current, options.blockPath] });
|
|
10277
9708
|
log.success(`Pfad blockiert: ${options.blockPath}`);
|
|
@@ -10279,7 +9710,7 @@ var permissionsCommand = new Command19("permissions").description("Permission-By
|
|
|
10279
9710
|
}
|
|
10280
9711
|
displayPermissionsStatus(getSecurityConfig(projectPath).permissions);
|
|
10281
9712
|
});
|
|
10282
|
-
function displayPermissionsStatus(
|
|
9713
|
+
function displayPermissionsStatus(config) {
|
|
10283
9714
|
log.newline();
|
|
10284
9715
|
console.log(colors.orange.bold("Permission-Einstellungen"));
|
|
10285
9716
|
console.log(colors.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
@@ -10289,11 +9720,11 @@ function displayPermissionsStatus(config2) {
|
|
|
10289
9720
|
"no-skip": colors.green("Aktiv (Permission-Prompts)"),
|
|
10290
9721
|
"inherit": colors.dim("(erbt von global)")
|
|
10291
9722
|
};
|
|
10292
|
-
log.keyValue("Modus", modeDisplay[
|
|
10293
|
-
log.keyValue("Erlaubte Tools",
|
|
10294
|
-
log.keyValue("Blockierte Tools",
|
|
10295
|
-
log.keyValue("Erlaubte Pfade",
|
|
10296
|
-
log.keyValue("Blockierte Pfade",
|
|
9723
|
+
log.keyValue("Modus", modeDisplay[config.skipPermissions]);
|
|
9724
|
+
log.keyValue("Erlaubte Tools", config.allowedTools === "all" ? "Alle" : config.allowedTools.join(", ") || "Keine");
|
|
9725
|
+
log.keyValue("Blockierte Tools", config.blockedTools.length > 0 ? config.blockedTools.join(", ") : colors.dim("Keine"));
|
|
9726
|
+
log.keyValue("Erlaubte Pfade", config.allowedPaths.length > 0 ? config.allowedPaths.join(", ") : colors.dim("Alle"));
|
|
9727
|
+
log.keyValue("Blockierte Pfade", config.blockedPaths.length > 0 ? config.blockedPaths.join(", ") : colors.dim("Keine"));
|
|
10297
9728
|
log.newline();
|
|
10298
9729
|
}
|
|
10299
9730
|
securityCommand.addCommand(permissionsCommand);
|
|
@@ -10302,9 +9733,9 @@ var approvalCommand = new Command19("approval").description("Plan-Approval-Strat
|
|
|
10302
9733
|
if (!hasShivaDir(projectPath)) {
|
|
10303
9734
|
initShivaDir(projectPath);
|
|
10304
9735
|
}
|
|
10305
|
-
const
|
|
9736
|
+
const config = getSecurityConfig(projectPath);
|
|
10306
9737
|
if (options.status || !strategy && Object.keys(options).length === 0) {
|
|
10307
|
-
displayApprovalStatus(
|
|
9738
|
+
displayApprovalStatus(config.approval);
|
|
10308
9739
|
return;
|
|
10309
9740
|
}
|
|
10310
9741
|
if (strategy) {
|
|
@@ -10323,7 +9754,7 @@ var approvalCommand = new Command19("approval").description("Plan-Approval-Strat
|
|
|
10323
9754
|
log.error("Ung\xFCltige Zahl");
|
|
10324
9755
|
return;
|
|
10325
9756
|
}
|
|
10326
|
-
updateApproval(projectPath, { thresholds: { ...
|
|
9757
|
+
updateApproval(projectPath, { thresholds: { ...config.approval.thresholds, autoApproveMaxFiles: n } });
|
|
10327
9758
|
log.success(`Max. Dateien f\xFCr Auto-Approval: ${n}`);
|
|
10328
9759
|
}
|
|
10329
9760
|
if (options.maxLines) {
|
|
@@ -10332,15 +9763,15 @@ var approvalCommand = new Command19("approval").description("Plan-Approval-Strat
|
|
|
10332
9763
|
log.error("Ung\xFCltige Zahl");
|
|
10333
9764
|
return;
|
|
10334
9765
|
}
|
|
10335
|
-
updateApproval(projectPath, { thresholds: { ...
|
|
9766
|
+
updateApproval(projectPath, { thresholds: { ...config.approval.thresholds, autoApproveMaxLines: n } });
|
|
10336
9767
|
log.success(`Max. Zeilen f\xFCr Auto-Approval: ${n}`);
|
|
10337
9768
|
}
|
|
10338
9769
|
if (options.require) {
|
|
10339
|
-
const current =
|
|
9770
|
+
const current = config.approval.thresholds.requireApprovalPatterns;
|
|
10340
9771
|
if (!current.includes(options.require)) {
|
|
10341
9772
|
updateApproval(projectPath, {
|
|
10342
9773
|
thresholds: {
|
|
10343
|
-
...
|
|
9774
|
+
...config.approval.thresholds,
|
|
10344
9775
|
requireApprovalPatterns: [...current, options.require]
|
|
10345
9776
|
}
|
|
10346
9777
|
});
|
|
@@ -10348,11 +9779,11 @@ var approvalCommand = new Command19("approval").description("Plan-Approval-Strat
|
|
|
10348
9779
|
}
|
|
10349
9780
|
}
|
|
10350
9781
|
if (options.skip) {
|
|
10351
|
-
const current =
|
|
9782
|
+
const current = config.approval.thresholds.skipApprovalPatterns;
|
|
10352
9783
|
if (!current.includes(options.skip)) {
|
|
10353
9784
|
updateApproval(projectPath, {
|
|
10354
9785
|
thresholds: {
|
|
10355
|
-
...
|
|
9786
|
+
...config.approval.thresholds,
|
|
10356
9787
|
skipApprovalPatterns: [...current, options.skip]
|
|
10357
9788
|
}
|
|
10358
9789
|
});
|
|
@@ -10360,20 +9791,20 @@ var approvalCommand = new Command19("approval").description("Plan-Approval-Strat
|
|
|
10360
9791
|
}
|
|
10361
9792
|
}
|
|
10362
9793
|
if (options.removeRequire) {
|
|
10363
|
-
const current =
|
|
9794
|
+
const current = config.approval.thresholds.requireApprovalPatterns;
|
|
10364
9795
|
updateApproval(projectPath, {
|
|
10365
9796
|
thresholds: {
|
|
10366
|
-
...
|
|
9797
|
+
...config.approval.thresholds,
|
|
10367
9798
|
requireApprovalPatterns: current.filter((p) => p !== options.removeRequire)
|
|
10368
9799
|
}
|
|
10369
9800
|
});
|
|
10370
9801
|
log.success(`Require-Pattern entfernt: ${options.removeRequire}`);
|
|
10371
9802
|
}
|
|
10372
9803
|
if (options.removeSkip) {
|
|
10373
|
-
const current =
|
|
9804
|
+
const current = config.approval.thresholds.skipApprovalPatterns;
|
|
10374
9805
|
updateApproval(projectPath, {
|
|
10375
9806
|
thresholds: {
|
|
10376
|
-
...
|
|
9807
|
+
...config.approval.thresholds,
|
|
10377
9808
|
skipApprovalPatterns: current.filter((p) => p !== options.removeSkip)
|
|
10378
9809
|
}
|
|
10379
9810
|
});
|
|
@@ -10381,7 +9812,7 @@ var approvalCommand = new Command19("approval").description("Plan-Approval-Strat
|
|
|
10381
9812
|
}
|
|
10382
9813
|
displayApprovalStatus(getSecurityConfig(projectPath).approval);
|
|
10383
9814
|
});
|
|
10384
|
-
function displayApprovalStatus(
|
|
9815
|
+
function displayApprovalStatus(config) {
|
|
10385
9816
|
log.newline();
|
|
10386
9817
|
console.log(colors.orange.bold("Approval-Einstellungen"));
|
|
10387
9818
|
console.log(colors.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
@@ -10391,12 +9822,12 @@ function displayApprovalStatus(config2) {
|
|
|
10391
9822
|
"manual": colors.green("Manuell"),
|
|
10392
9823
|
"hybrid": colors.cyan("Hybrid")
|
|
10393
9824
|
};
|
|
10394
|
-
log.keyValue("Strategie", strategyDisplay[
|
|
10395
|
-
if (
|
|
10396
|
-
log.keyValue("Max. Dateien", String(
|
|
10397
|
-
log.keyValue("Max. Zeilen", String(
|
|
10398
|
-
log.keyValue("Require-Patterns",
|
|
10399
|
-
log.keyValue("Skip-Patterns",
|
|
9825
|
+
log.keyValue("Strategie", strategyDisplay[config.strategy]);
|
|
9826
|
+
if (config.strategy === "hybrid") {
|
|
9827
|
+
log.keyValue("Max. Dateien", String(config.thresholds.autoApproveMaxFiles));
|
|
9828
|
+
log.keyValue("Max. Zeilen", String(config.thresholds.autoApproveMaxLines));
|
|
9829
|
+
log.keyValue("Require-Patterns", config.thresholds.requireApprovalPatterns.join(", ") || colors.dim("Keine"));
|
|
9830
|
+
log.keyValue("Skip-Patterns", config.thresholds.skipApprovalPatterns.join(", ") || colors.dim("Keine"));
|
|
10400
9831
|
}
|
|
10401
9832
|
log.newline();
|
|
10402
9833
|
}
|
|
@@ -10430,16 +9861,16 @@ securityCommand.command("set-tier <tier>").description("Security-Tier setzen (be
|
|
|
10430
9861
|
log.newline();
|
|
10431
9862
|
displayTierInfo(tier, preset);
|
|
10432
9863
|
});
|
|
10433
|
-
function displayTierInfo(tier,
|
|
9864
|
+
function displayTierInfo(tier, config) {
|
|
10434
9865
|
console.log(colors.orange.bold(`Tier: ${tier}`));
|
|
10435
9866
|
console.log(colors.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
10436
9867
|
log.newline();
|
|
10437
9868
|
const check = (value) => value ? colors.green("\u2713") : colors.dim("\u2717");
|
|
10438
|
-
log.plain(` ${check(
|
|
10439
|
-
log.plain(` ${check(
|
|
10440
|
-
log.plain(` ${check(
|
|
10441
|
-
log.plain(` ${check(
|
|
10442
|
-
log.plain(` Approval: ${
|
|
9869
|
+
log.plain(` ${check(config.skipPermissions)} Skip Permissions`);
|
|
9870
|
+
log.plain(` ${check(config.dockerIsolation)} Docker Isolation`);
|
|
9871
|
+
log.plain(` ${check(config.require2FA)} 2FA erforderlich`);
|
|
9872
|
+
log.plain(` ${check(config.timeRestrictions)} Zeit-Einschr\xE4nkungen`);
|
|
9873
|
+
log.plain(` Approval: ${config.approvalStrategy}`);
|
|
10443
9874
|
log.newline();
|
|
10444
9875
|
}
|
|
10445
9876
|
securityCommand.command("audit").description("Sicherheits-Audit durchf\xFChren").action(async () => {
|
|
@@ -10449,15 +9880,15 @@ securityCommand.command("audit").description("Sicherheits-Audit durchf\xFChren")
|
|
|
10449
9880
|
log.info("Initialisiere mit: shiva project time --enable");
|
|
10450
9881
|
return;
|
|
10451
9882
|
}
|
|
10452
|
-
const
|
|
10453
|
-
const audit = performSecurityAudit(
|
|
9883
|
+
const config = getProjectConfigV2(projectPath);
|
|
9884
|
+
const audit = performSecurityAudit(config);
|
|
10454
9885
|
displaySecurityAudit(audit);
|
|
10455
9886
|
});
|
|
10456
|
-
function performSecurityAudit(
|
|
9887
|
+
function performSecurityAudit(config) {
|
|
10457
9888
|
const checks = [];
|
|
10458
9889
|
const recommendations = [];
|
|
10459
9890
|
let score = 10;
|
|
10460
|
-
if (
|
|
9891
|
+
if (config.security.permissions.skipPermissions === "skip") {
|
|
10461
9892
|
checks.push({
|
|
10462
9893
|
name: "Permissions",
|
|
10463
9894
|
status: "warn",
|
|
@@ -10465,7 +9896,7 @@ function performSecurityAudit(config2) {
|
|
|
10465
9896
|
});
|
|
10466
9897
|
recommendations.push("Deaktiviere Skip-Permissions f\xFCr erh\xF6hte Sicherheit");
|
|
10467
9898
|
score -= 2;
|
|
10468
|
-
} else if (
|
|
9899
|
+
} else if (config.security.permissions.skipPermissions === "no-skip") {
|
|
10469
9900
|
checks.push({
|
|
10470
9901
|
name: "Permissions",
|
|
10471
9902
|
status: "pass",
|
|
@@ -10478,11 +9909,11 @@ function performSecurityAudit(config2) {
|
|
|
10478
9909
|
message: "Erbt von global"
|
|
10479
9910
|
});
|
|
10480
9911
|
}
|
|
10481
|
-
if (
|
|
9912
|
+
if (config.security.permissions.blockedPaths.length > 0) {
|
|
10482
9913
|
checks.push({
|
|
10483
9914
|
name: "Pfad-Blocking",
|
|
10484
9915
|
status: "pass",
|
|
10485
|
-
message: `${
|
|
9916
|
+
message: `${config.security.permissions.blockedPaths.length} Pfade blockiert`
|
|
10486
9917
|
});
|
|
10487
9918
|
} else {
|
|
10488
9919
|
checks.push({
|
|
@@ -10493,13 +9924,13 @@ function performSecurityAudit(config2) {
|
|
|
10493
9924
|
recommendations.push("Blockiere sensible Pfade wie .env oder secrets/");
|
|
10494
9925
|
score -= 1;
|
|
10495
9926
|
}
|
|
10496
|
-
if (
|
|
9927
|
+
if (config.security.approval.strategy === "manual") {
|
|
10497
9928
|
checks.push({
|
|
10498
9929
|
name: "Approval",
|
|
10499
9930
|
status: "pass",
|
|
10500
9931
|
message: "Manuelle Genehmigung"
|
|
10501
9932
|
});
|
|
10502
|
-
} else if (
|
|
9933
|
+
} else if (config.security.approval.strategy === "hybrid") {
|
|
10503
9934
|
checks.push({
|
|
10504
9935
|
name: "Approval",
|
|
10505
9936
|
status: "pass",
|
|
@@ -10514,7 +9945,7 @@ function performSecurityAudit(config2) {
|
|
|
10514
9945
|
recommendations.push("Wechsle zu hybrid oder manual Approval");
|
|
10515
9946
|
score -= 1;
|
|
10516
9947
|
}
|
|
10517
|
-
if (
|
|
9948
|
+
if (config.docker.enabled === true) {
|
|
10518
9949
|
checks.push({
|
|
10519
9950
|
name: "Docker",
|
|
10520
9951
|
status: "pass",
|
|
@@ -10529,24 +9960,24 @@ function performSecurityAudit(config2) {
|
|
|
10529
9960
|
recommendations.push("Aktiviere Docker f\xFCr isolierte Ausf\xFChrung");
|
|
10530
9961
|
score -= 1;
|
|
10531
9962
|
}
|
|
10532
|
-
if (
|
|
9963
|
+
if (config.docker.enabled && config.docker.network === "none") {
|
|
10533
9964
|
checks.push({
|
|
10534
9965
|
name: "Netzwerk",
|
|
10535
9966
|
status: "pass",
|
|
10536
9967
|
message: "Netzwerk-Isolation aktiv"
|
|
10537
9968
|
});
|
|
10538
|
-
} else if (
|
|
9969
|
+
} else if (config.docker.enabled && config.docker.network === "bridge") {
|
|
10539
9970
|
checks.push({
|
|
10540
9971
|
name: "Netzwerk",
|
|
10541
9972
|
status: "warn",
|
|
10542
9973
|
message: "Bridge-Netzwerk"
|
|
10543
9974
|
});
|
|
10544
9975
|
}
|
|
10545
|
-
if (
|
|
9976
|
+
if (config.session.timeControl.enabled) {
|
|
10546
9977
|
checks.push({
|
|
10547
9978
|
name: "Zeitkontrolle",
|
|
10548
9979
|
status: "pass",
|
|
10549
|
-
message: `${
|
|
9980
|
+
message: `${config.session.timeControl.allowedHours.start}-${config.session.timeControl.allowedHours.end}`
|
|
10550
9981
|
});
|
|
10551
9982
|
} else {
|
|
10552
9983
|
checks.push({
|
|
@@ -10556,7 +9987,7 @@ function performSecurityAudit(config2) {
|
|
|
10556
9987
|
});
|
|
10557
9988
|
score -= 0.5;
|
|
10558
9989
|
}
|
|
10559
|
-
const hasBudget =
|
|
9990
|
+
const hasBudget = config.session.budget.dailyTokenLimit || config.session.budget.weeklyTokenLimit || config.session.budget.monthlyTokenLimit;
|
|
10560
9991
|
if (hasBudget) {
|
|
10561
9992
|
checks.push({
|
|
10562
9993
|
name: "Token-Budget",
|
|
@@ -10571,7 +10002,7 @@ function performSecurityAudit(config2) {
|
|
|
10571
10002
|
});
|
|
10572
10003
|
score -= 0.5;
|
|
10573
10004
|
}
|
|
10574
|
-
if (
|
|
10005
|
+
if (config.security.require2FA) {
|
|
10575
10006
|
checks.push({
|
|
10576
10007
|
name: "2FA",
|
|
10577
10008
|
status: "pass",
|
|
@@ -10587,7 +10018,7 @@ function performSecurityAudit(config2) {
|
|
|
10587
10018
|
score -= 1;
|
|
10588
10019
|
}
|
|
10589
10020
|
return {
|
|
10590
|
-
tier:
|
|
10021
|
+
tier: config.security.tier,
|
|
10591
10022
|
checks,
|
|
10592
10023
|
recommendations,
|
|
10593
10024
|
score: Math.max(0, Math.round(score))
|
|
@@ -10623,23 +10054,23 @@ securityCommand.command("status").description("Sicherheitsstatus anzeigen").acti
|
|
|
10623
10054
|
log.info("Initialisiere mit: shiva project time --enable");
|
|
10624
10055
|
return;
|
|
10625
10056
|
}
|
|
10626
|
-
const
|
|
10057
|
+
const config = getProjectConfigV2(projectPath);
|
|
10627
10058
|
log.newline();
|
|
10628
10059
|
console.log(colors.orange.bold("SHIVA Security Status"));
|
|
10629
10060
|
console.log(colors.dim("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"));
|
|
10630
10061
|
log.newline();
|
|
10631
|
-
log.keyValue("Security-Tier",
|
|
10632
|
-
log.keyValue("2FA erforderlich",
|
|
10062
|
+
log.keyValue("Security-Tier", config.security.tier);
|
|
10063
|
+
log.keyValue("2FA erforderlich", config.security.require2FA ? "Ja" : "Nein");
|
|
10633
10064
|
log.newline();
|
|
10634
|
-
displayPermissionsStatus(
|
|
10635
|
-
displayApprovalStatus(
|
|
10065
|
+
displayPermissionsStatus(config.security.permissions);
|
|
10066
|
+
displayApprovalStatus(config.security.approval);
|
|
10636
10067
|
});
|
|
10637
10068
|
var tfaCommand = new Command19("2fa").description("Zwei-Faktor-Authentifizierung").option("--enable", "2FA aktivieren").option("--disable", "2FA deaktivieren").option("--status", "Status anzeigen").option("--backup", "Neue Backup-Codes generieren").action(async (options) => {
|
|
10638
10069
|
if (!isAuthenticated()) {
|
|
10639
10070
|
log.error("Nicht angemeldet. Verwende: shiva login");
|
|
10640
10071
|
return;
|
|
10641
10072
|
}
|
|
10642
|
-
const
|
|
10073
|
+
const config = getConfig();
|
|
10643
10074
|
if (options.status || Object.keys(options).length === 0) {
|
|
10644
10075
|
try {
|
|
10645
10076
|
const status = await twoFactorService.getStatus();
|
|
@@ -10661,7 +10092,7 @@ var tfaCommand = new Command19("2fa").description("Zwei-Faktor-Authentifizierung
|
|
|
10661
10092
|
if (options.enable) {
|
|
10662
10093
|
try {
|
|
10663
10094
|
log.info("Initialisiere 2FA-Setup...");
|
|
10664
|
-
const setup = await twoFactorService.startSetup(
|
|
10095
|
+
const setup = await twoFactorService.startSetup(config.email || "");
|
|
10665
10096
|
displayQRCode(setup.qrCodeDataUrl);
|
|
10666
10097
|
log.plain(`Oder manuell eingeben: ${colors.cyan(setup.secret)}`);
|
|
10667
10098
|
log.newline();
|
|
@@ -10778,7 +10209,7 @@ import { Command as Command20 } from "commander";
|
|
|
10778
10209
|
import inquirer8 from "inquirer";
|
|
10779
10210
|
import ora13 from "ora";
|
|
10780
10211
|
import * as fs6 from "fs";
|
|
10781
|
-
import * as
|
|
10212
|
+
import * as path6 from "path";
|
|
10782
10213
|
|
|
10783
10214
|
// src/utils/clipboard.ts
|
|
10784
10215
|
import { execSync as execSync2, spawnSync as spawnSync6 } from "child_process";
|
|
@@ -11103,7 +10534,7 @@ secretsCommand.command("import").description(".env Datei in Vault importieren").
|
|
|
11103
10534
|
log.errorWithSuggestion(Errors.NOT_AUTHENTICATED());
|
|
11104
10535
|
return;
|
|
11105
10536
|
}
|
|
11106
|
-
const filePath =
|
|
10537
|
+
const filePath = path6.resolve(file);
|
|
11107
10538
|
if (!fs6.existsSync(filePath)) {
|
|
11108
10539
|
log.errorWithSuggestion(Errors.FILE_NOT_FOUND(file));
|
|
11109
10540
|
return;
|
|
@@ -11136,7 +10567,7 @@ secretsCommand.command("import").description(".env Datei in Vault importieren").
|
|
|
11136
10567
|
log.listItem(`${secret.key} = ${preview}`);
|
|
11137
10568
|
}
|
|
11138
10569
|
log.newline();
|
|
11139
|
-
log.dim(`${secrets.length} Secret(s) aus ${
|
|
10570
|
+
log.dim(`${secrets.length} Secret(s) aus ${path6.basename(file)}`);
|
|
11140
10571
|
log.newline();
|
|
11141
10572
|
if (options.dryRun) {
|
|
11142
10573
|
log.info("Dry-run: Keine \xC4nderungen vorgenommen");
|
|
@@ -11233,22 +10664,22 @@ import ora14 from "ora";
|
|
|
11233
10664
|
|
|
11234
10665
|
// src/services/data/memory.ts
|
|
11235
10666
|
import * as fs7 from "fs";
|
|
11236
|
-
import * as
|
|
11237
|
-
import * as
|
|
10667
|
+
import * as path7 from "path";
|
|
10668
|
+
import * as os4 from "os";
|
|
11238
10669
|
function findAllClaudeMdFiles() {
|
|
11239
10670
|
const results = [];
|
|
11240
|
-
const sessionsPath =
|
|
10671
|
+
const sessionsPath = path7.join(os4.homedir(), ".claude", "projects");
|
|
11241
10672
|
if (fs7.existsSync(sessionsPath)) {
|
|
11242
10673
|
const dirs = fs7.readdirSync(sessionsPath);
|
|
11243
10674
|
for (const dir of dirs) {
|
|
11244
10675
|
const projectPath = decodeProjectPath(dir);
|
|
11245
10676
|
if (projectPath && fs7.existsSync(projectPath)) {
|
|
11246
|
-
const claudeMdPath =
|
|
10677
|
+
const claudeMdPath = path7.join(projectPath, "CLAUDE.md");
|
|
11247
10678
|
if (fs7.existsSync(claudeMdPath)) {
|
|
11248
10679
|
results.push({
|
|
11249
10680
|
path: claudeMdPath,
|
|
11250
10681
|
projectPath,
|
|
11251
|
-
projectName:
|
|
10682
|
+
projectName: path7.basename(projectPath)
|
|
11252
10683
|
});
|
|
11253
10684
|
}
|
|
11254
10685
|
}
|
|
@@ -11326,7 +10757,6 @@ async function getAllMemories() {
|
|
|
11326
10757
|
return Array.from(memoryMap.values());
|
|
11327
10758
|
}
|
|
11328
10759
|
async function searchMemories(query, options = {}) {
|
|
11329
|
-
const allMemories = await getAllMemories();
|
|
11330
10760
|
const {
|
|
11331
10761
|
caseSensitive = false,
|
|
11332
10762
|
category,
|
|
@@ -11335,24 +10765,57 @@ async function searchMemories(query, options = {}) {
|
|
|
11335
10765
|
limit = 100
|
|
11336
10766
|
} = options;
|
|
11337
10767
|
const searchQuery = caseSensitive ? query : query.toLowerCase();
|
|
11338
|
-
|
|
11339
|
-
|
|
11340
|
-
|
|
10768
|
+
let allMemories = [];
|
|
10769
|
+
if (source === "local" || source === "all") {
|
|
10770
|
+
const localMemories = getLocalMemories();
|
|
10771
|
+
allMemories.push(...localMemories);
|
|
10772
|
+
}
|
|
10773
|
+
if ((source === "cloud" || source === "all") && isAuthenticated()) {
|
|
10774
|
+
try {
|
|
10775
|
+
const cloudResults = await api.searchMemories(query);
|
|
10776
|
+
const cloudMemories = cloudResults.map((m) => ({
|
|
10777
|
+
key: m.key,
|
|
10778
|
+
value: m.value,
|
|
10779
|
+
category: m.category,
|
|
10780
|
+
source: "cloud",
|
|
10781
|
+
projectName: m.projectName,
|
|
10782
|
+
projectPath: "",
|
|
10783
|
+
// Not returned by search API
|
|
10784
|
+
projectId: m.projectId,
|
|
10785
|
+
memoryId: m.id
|
|
10786
|
+
}));
|
|
10787
|
+
allMemories.push(...cloudMemories);
|
|
10788
|
+
} catch {
|
|
10789
|
+
const cloudMemories = await getCloudMemories();
|
|
10790
|
+
allMemories.push(...cloudMemories);
|
|
10791
|
+
}
|
|
10792
|
+
}
|
|
10793
|
+
const memoryMap = /* @__PURE__ */ new Map();
|
|
10794
|
+
for (const memory of allMemories) {
|
|
10795
|
+
const key = `${memory.projectName}:${memory.key}`;
|
|
10796
|
+
if (!memoryMap.has(key) || memory.source === "cloud") {
|
|
10797
|
+
memoryMap.set(key, memory);
|
|
11341
10798
|
}
|
|
10799
|
+
}
|
|
10800
|
+
allMemories = Array.from(memoryMap.values());
|
|
10801
|
+
const filtered = allMemories.filter((memory) => {
|
|
11342
10802
|
if (category && memory.category !== category) {
|
|
11343
10803
|
return false;
|
|
11344
10804
|
}
|
|
11345
10805
|
if (project) {
|
|
11346
|
-
const projectMatch = caseSensitive ? memory.projectName.includes(project)
|
|
10806
|
+
const projectMatch = caseSensitive ? memory.projectName.includes(project) : memory.projectName.toLowerCase().includes(project.toLowerCase());
|
|
11347
10807
|
if (!projectMatch) {
|
|
11348
10808
|
return false;
|
|
11349
10809
|
}
|
|
11350
10810
|
}
|
|
11351
|
-
|
|
11352
|
-
|
|
11353
|
-
|
|
10811
|
+
if (memory.source === "local") {
|
|
10812
|
+
const searchFields = [memory.key, memory.value, memory.category];
|
|
10813
|
+
const haystack = caseSensitive ? searchFields.join(" ") : searchFields.join(" ").toLowerCase();
|
|
10814
|
+
return haystack.includes(searchQuery);
|
|
10815
|
+
}
|
|
10816
|
+
return true;
|
|
11354
10817
|
});
|
|
11355
|
-
const projectSet = new Set(filtered.map((m) => m.
|
|
10818
|
+
const projectSet = new Set(filtered.map((m) => m.projectName));
|
|
11356
10819
|
return {
|
|
11357
10820
|
memories: filtered.slice(0, limit),
|
|
11358
10821
|
totalCount: filtered.length,
|
|
@@ -11360,7 +10823,7 @@ async function searchMemories(query, options = {}) {
|
|
|
11360
10823
|
};
|
|
11361
10824
|
}
|
|
11362
10825
|
function deleteLocalMemory(projectPath, key) {
|
|
11363
|
-
const claudeMdPath =
|
|
10826
|
+
const claudeMdPath = path7.join(projectPath, "CLAUDE.md");
|
|
11364
10827
|
if (!fs7.existsSync(claudeMdPath)) {
|
|
11365
10828
|
return false;
|
|
11366
10829
|
}
|
|
@@ -11410,7 +10873,7 @@ async function deleteMemory(projectPath, key, options = {}) {
|
|
|
11410
10873
|
}
|
|
11411
10874
|
async function deleteAllProjectMemories(projectPath) {
|
|
11412
10875
|
const result = { local: 0, cloud: 0 };
|
|
11413
|
-
const claudeMdPath =
|
|
10876
|
+
const claudeMdPath = path7.join(projectPath, "CLAUDE.md");
|
|
11414
10877
|
if (fs7.existsSync(claudeMdPath)) {
|
|
11415
10878
|
try {
|
|
11416
10879
|
let content = fs7.readFileSync(claudeMdPath, "utf-8");
|
|
@@ -11439,8 +10902,8 @@ async function deleteAllProjectMemories(projectPath) {
|
|
|
11439
10902
|
return result;
|
|
11440
10903
|
}
|
|
11441
10904
|
async function getContextPreview(projectPath) {
|
|
11442
|
-
const projectName =
|
|
11443
|
-
const claudeMdPath =
|
|
10905
|
+
const projectName = path7.basename(projectPath);
|
|
10906
|
+
const claudeMdPath = path7.join(projectPath, "CLAUDE.md");
|
|
11444
10907
|
const preview = {
|
|
11445
10908
|
projectName,
|
|
11446
10909
|
projectPath,
|
|
@@ -11462,8 +10925,8 @@ async function getContextPreview(projectPath) {
|
|
|
11462
10925
|
projectPath
|
|
11463
10926
|
}));
|
|
11464
10927
|
}
|
|
11465
|
-
const shivaDir =
|
|
11466
|
-
const contextPath =
|
|
10928
|
+
const shivaDir = path7.join(projectPath, ".shiva");
|
|
10929
|
+
const contextPath = path7.join(shivaDir, "github-context.md");
|
|
11467
10930
|
if (fs7.existsSync(contextPath)) {
|
|
11468
10931
|
const content = fs7.readFileSync(contextPath, "utf-8");
|
|
11469
10932
|
preview.githubContext = content;
|
|
@@ -11557,7 +11020,7 @@ function escapeRegex2(str) {
|
|
|
11557
11020
|
|
|
11558
11021
|
// src/commands/memory/forget.ts
|
|
11559
11022
|
import { Command as Command22 } from "commander";
|
|
11560
|
-
import * as
|
|
11023
|
+
import * as path8 from "path";
|
|
11561
11024
|
import inquirer9 from "inquirer";
|
|
11562
11025
|
import ora15 from "ora";
|
|
11563
11026
|
var forgetCommand = new Command22("forget").description("Memories l\xF6schen (GDPR)").argument("[key]", "Memory-Key zum L\xF6schen").option("-p, --project <path>", "Projekt-Pfad").option("--all", "Alle Memories eines Projekts l\xF6schen").option("--search <query>", "Memories nach Suchbegriff l\xF6schen").option("--local-only", "Nur lokal l\xF6schen").option("--cloud-only", "Nur aus Cloud l\xF6schen").option("-f, --force", "Ohne Best\xE4tigung l\xF6schen").option("--dry-run", "Nur anzeigen, was gel\xF6scht w\xFCrde").action(async (key, options) => {
|
|
@@ -11565,7 +11028,7 @@ var forgetCommand = new Command22("forget").description("Memories l\xF6schen (GD
|
|
|
11565
11028
|
console.log(colors.orange.bold("SHIVA Code - Forget"));
|
|
11566
11029
|
console.log(colors.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
11567
11030
|
log.newline();
|
|
11568
|
-
const projectPath = options.project ?
|
|
11031
|
+
const projectPath = options.project ? path8.resolve(options.project) : process.cwd();
|
|
11569
11032
|
if (options.all) {
|
|
11570
11033
|
await handleDeleteAll(projectPath, options);
|
|
11571
11034
|
return;
|
|
@@ -11581,7 +11044,7 @@ var forgetCommand = new Command22("forget").description("Memories l\xF6schen (GD
|
|
|
11581
11044
|
await handleInteractiveDelete(projectPath, options);
|
|
11582
11045
|
});
|
|
11583
11046
|
async function handleDeleteAll(projectPath, options) {
|
|
11584
|
-
const projectName =
|
|
11047
|
+
const projectName = path8.basename(projectPath);
|
|
11585
11048
|
console.log(colors.red.bold("\u26A0\uFE0F WARNUNG: Alle Memories l\xF6schen"));
|
|
11586
11049
|
console.log(colors.dim(`Projekt: ${projectName}`));
|
|
11587
11050
|
console.log(colors.dim(`Pfad: ${projectPath}`));
|
|
@@ -11687,7 +11150,7 @@ async function handleDeleteBySearch(query, projectPath, options) {
|
|
|
11687
11150
|
}
|
|
11688
11151
|
async function handleDeleteKey(key, projectPath, options) {
|
|
11689
11152
|
console.log(colors.bold(`Memory l\xF6schen: ${key}`));
|
|
11690
|
-
console.log(colors.dim(`Projekt: ${
|
|
11153
|
+
console.log(colors.dim(`Projekt: ${path8.basename(projectPath)}`));
|
|
11691
11154
|
log.newline();
|
|
11692
11155
|
if (options.dryRun) {
|
|
11693
11156
|
log.info("Dry-run: Keine \xC4nderungen werden vorgenommen");
|
|
@@ -11802,12 +11265,12 @@ function truncate(str, maxLen) {
|
|
|
11802
11265
|
|
|
11803
11266
|
// src/commands/memory/context.ts
|
|
11804
11267
|
import { Command as Command23 } from "commander";
|
|
11805
|
-
import * as
|
|
11268
|
+
import * as path9 from "path";
|
|
11806
11269
|
import * as fs8 from "fs";
|
|
11807
11270
|
import ora16 from "ora";
|
|
11808
11271
|
var contextCommand = new Command23("context").description("Zeigt was in Claude injected w\xFCrde").option("-d, --dir <path>", "Projektverzeichnis").option("--github", "GitHub Context einschlie\xDFen").option("--secrets", "Secret-Keys anzeigen").option("--raw", "Rohe CLAUDE.md Ausgabe").option("--json", "JSON Ausgabe").option("-s, --size", "Nur Gr\xF6\xDFe anzeigen").action(async (options) => {
|
|
11809
|
-
const projectPath = options.dir ?
|
|
11810
|
-
const projectName =
|
|
11272
|
+
const projectPath = options.dir ? path9.resolve(options.dir) : process.cwd();
|
|
11273
|
+
const projectName = path9.basename(projectPath);
|
|
11811
11274
|
if (!fs8.existsSync(projectPath)) {
|
|
11812
11275
|
log.error(`Verzeichnis nicht gefunden: ${projectPath}`);
|
|
11813
11276
|
return;
|
|
@@ -12191,14 +11654,14 @@ async function resolveSessionId(input) {
|
|
|
12191
11654
|
|
|
12192
11655
|
// src/commands/memory/export.ts
|
|
12193
11656
|
import { Command as Command25 } from "commander";
|
|
12194
|
-
import * as
|
|
11657
|
+
import * as path11 from "path";
|
|
12195
11658
|
import * as fs10 from "fs";
|
|
12196
11659
|
import ora17 from "ora";
|
|
12197
11660
|
import inquirer11 from "inquirer";
|
|
12198
11661
|
|
|
12199
11662
|
// src/services/session/export.ts
|
|
12200
11663
|
import * as fs9 from "fs";
|
|
12201
|
-
import * as
|
|
11664
|
+
import * as path10 from "path";
|
|
12202
11665
|
import { execSync as execSync3 } from "child_process";
|
|
12203
11666
|
async function exportSession(sessionId, options = {}) {
|
|
12204
11667
|
const projects = await getAllClaudeProjects();
|
|
@@ -12214,7 +11677,7 @@ async function exportSession(sessionId, options = {}) {
|
|
|
12214
11677
|
tags: getSessionTags(sessionId)
|
|
12215
11678
|
};
|
|
12216
11679
|
if (options.includeTranscript) {
|
|
12217
|
-
const transcriptPath =
|
|
11680
|
+
const transcriptPath = path10.join(
|
|
12218
11681
|
getClaudeProjectsPath(),
|
|
12219
11682
|
encodeProjectPath(project.absolutePath),
|
|
12220
11683
|
session.sessionId + ".jsonl"
|
|
@@ -12224,7 +11687,7 @@ async function exportSession(sessionId, options = {}) {
|
|
|
12224
11687
|
}
|
|
12225
11688
|
}
|
|
12226
11689
|
if (options.includeConversation && options.includeTranscript) {
|
|
12227
|
-
const transcriptPath =
|
|
11690
|
+
const transcriptPath = path10.join(
|
|
12228
11691
|
getClaudeProjectsPath(),
|
|
12229
11692
|
encodeProjectPath(project.absolutePath),
|
|
12230
11693
|
session.sessionId + ".jsonl"
|
|
@@ -12265,7 +11728,7 @@ async function exportSessions(sessionIds, outputDir, options = {}) {
|
|
|
12265
11728
|
const exported = await exportSession(sessionId, options);
|
|
12266
11729
|
if (exported) {
|
|
12267
11730
|
const filename = `${exported.projectName}-${sessionId.slice(0, 8)}.json`;
|
|
12268
|
-
const filepath =
|
|
11731
|
+
const filepath = path10.join(outputDir, filename);
|
|
12269
11732
|
fs9.writeFileSync(filepath, JSON.stringify(exported, null, 2));
|
|
12270
11733
|
success++;
|
|
12271
11734
|
} else {
|
|
@@ -12295,7 +11758,7 @@ function createBackupArchive(outputPath, projectPaths) {
|
|
|
12295
11758
|
if (projectPaths && projectPaths.length > 0) {
|
|
12296
11759
|
for (const p of projectPaths) {
|
|
12297
11760
|
const encoded = encodeProjectPath(p);
|
|
12298
|
-
const fullPath =
|
|
11761
|
+
const fullPath = path10.join(claudeDir, encoded);
|
|
12299
11762
|
if (fs9.existsSync(fullPath)) {
|
|
12300
11763
|
includePaths.push(encoded);
|
|
12301
11764
|
}
|
|
@@ -12303,7 +11766,7 @@ function createBackupArchive(outputPath, projectPaths) {
|
|
|
12303
11766
|
} else {
|
|
12304
11767
|
const entries = fs9.readdirSync(claudeDir);
|
|
12305
11768
|
includePaths = entries.filter((e) => {
|
|
12306
|
-
const stat = fs9.statSync(
|
|
11769
|
+
const stat = fs9.statSync(path10.join(claudeDir, e));
|
|
12307
11770
|
return stat.isDirectory();
|
|
12308
11771
|
});
|
|
12309
11772
|
}
|
|
@@ -12323,11 +11786,11 @@ async function importSession(data, targetProjectPath) {
|
|
|
12323
11786
|
try {
|
|
12324
11787
|
const projectPath = targetProjectPath || data.projectPath;
|
|
12325
11788
|
const encodedPath = encodeProjectPath(projectPath);
|
|
12326
|
-
const sessionDir =
|
|
11789
|
+
const sessionDir = path10.join(getClaudeProjectsPath(), encodedPath);
|
|
12327
11790
|
if (!fs9.existsSync(sessionDir)) {
|
|
12328
11791
|
fs9.mkdirSync(sessionDir, { recursive: true });
|
|
12329
11792
|
}
|
|
12330
|
-
const sessionFile =
|
|
11793
|
+
const sessionFile = path10.join(sessionDir, data.session.sessionId + ".jsonl");
|
|
12331
11794
|
if (fs9.existsSync(sessionFile)) {
|
|
12332
11795
|
return {
|
|
12333
11796
|
success: false,
|
|
@@ -12399,7 +11862,7 @@ async function importSessionsFromDirectory(dirPath, targetProjectPath) {
|
|
|
12399
11862
|
let success = 0;
|
|
12400
11863
|
let failed = 0;
|
|
12401
11864
|
for (const file of files) {
|
|
12402
|
-
const filepath =
|
|
11865
|
+
const filepath = path10.join(dirPath, file);
|
|
12403
11866
|
const result = await importSessionFromFile(filepath, targetProjectPath);
|
|
12404
11867
|
results.push(result);
|
|
12405
11868
|
if (result.success) {
|
|
@@ -12477,7 +11940,7 @@ var importCommand = new Command25("import").description("Sessions importieren").
|
|
|
12477
11940
|
console.log(colors.orange.bold("SHIVA Code - Import"));
|
|
12478
11941
|
console.log(colors.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
12479
11942
|
log.newline();
|
|
12480
|
-
const absolutePath =
|
|
11943
|
+
const absolutePath = path11.resolve(inputPath);
|
|
12481
11944
|
if (!fs10.existsSync(absolutePath)) {
|
|
12482
11945
|
log.error(`Datei nicht gefunden: ${absolutePath}`);
|
|
12483
11946
|
return;
|
|
@@ -12500,7 +11963,7 @@ var importCommand = new Command25("import").description("Sessions importieren").
|
|
|
12500
11963
|
async function handleBackup(outputPath) {
|
|
12501
11964
|
const spinner = ora17("Erstelle Backup...").start();
|
|
12502
11965
|
const filename = `shiva-backup-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.tar.gz`;
|
|
12503
|
-
const output = outputPath ||
|
|
11966
|
+
const output = outputPath || path11.join(process.cwd(), filename);
|
|
12504
11967
|
const success = createBackupArchive(output);
|
|
12505
11968
|
if (success) {
|
|
12506
11969
|
spinner.succeed(`Backup erstellt: ${output}`);
|
|
@@ -12519,7 +11982,7 @@ async function handleExportAll(outputDir, options = {}) {
|
|
|
12519
11982
|
return;
|
|
12520
11983
|
}
|
|
12521
11984
|
spinner.text = `Exportiere ${allSessionIds.length} Sessions...`;
|
|
12522
|
-
const output = outputDir ||
|
|
11985
|
+
const output = outputDir || path11.join(process.cwd(), "shiva-export");
|
|
12523
11986
|
const result = await exportSessions(allSessionIds, output, options);
|
|
12524
11987
|
spinner.succeed(`Export abgeschlossen`);
|
|
12525
11988
|
log.info(`${result.success} Sessions exportiert`);
|
|
@@ -12543,7 +12006,7 @@ async function handleExportProject(projectName, outputDir, options = {}) {
|
|
|
12543
12006
|
return;
|
|
12544
12007
|
}
|
|
12545
12008
|
spinner.text = `Exportiere ${project.sessions.length} Sessions aus ${project.projectName}...`;
|
|
12546
|
-
const output = outputDir ||
|
|
12009
|
+
const output = outputDir || path11.join(process.cwd(), `${project.projectName}-export`);
|
|
12547
12010
|
const result = await exportProjectSessions(project.absolutePath, output, options);
|
|
12548
12011
|
spinner.succeed(`Export abgeschlossen`);
|
|
12549
12012
|
log.info(`${result.success} Sessions exportiert`);
|
|
@@ -12672,15 +12135,15 @@ var rememberCommand = new Command26("remember").description("Memory in der Cloud
|
|
|
12672
12135
|
return;
|
|
12673
12136
|
}
|
|
12674
12137
|
const projectPath = process.cwd();
|
|
12675
|
-
const
|
|
12676
|
-
if (!
|
|
12138
|
+
const config = getProjectConfig(projectPath);
|
|
12139
|
+
if (!config.projectId) {
|
|
12677
12140
|
log.error("Projekt nicht mit Cloud verbunden");
|
|
12678
12141
|
log.info("Verbinden mit: shiva init && shiva sync");
|
|
12679
12142
|
return;
|
|
12680
12143
|
}
|
|
12681
12144
|
const key = options.key || text.substring(0, 50).replace(/[^a-zA-Z0-9]/g, "_");
|
|
12682
12145
|
try {
|
|
12683
|
-
const result = await api.addMemory(
|
|
12146
|
+
const result = await api.addMemory(config.projectId, {
|
|
12684
12147
|
key,
|
|
12685
12148
|
value: text,
|
|
12686
12149
|
category: options.category
|
|
@@ -12700,8 +12163,8 @@ var rememberCommand = new Command26("remember").description("Memory in der Cloud
|
|
|
12700
12163
|
import { Command as Command27 } from "commander";
|
|
12701
12164
|
import { execSync as execSync4 } from "child_process";
|
|
12702
12165
|
import * as fs11 from "fs";
|
|
12703
|
-
import * as
|
|
12704
|
-
import * as
|
|
12166
|
+
import * as path12 from "path";
|
|
12167
|
+
import * as os5 from "os";
|
|
12705
12168
|
function tryExec(command) {
|
|
12706
12169
|
try {
|
|
12707
12170
|
return execSync4(command, { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
@@ -12862,8 +12325,8 @@ function checkNpm() {
|
|
|
12862
12325
|
};
|
|
12863
12326
|
}
|
|
12864
12327
|
function checkShivaConfig() {
|
|
12865
|
-
const configDir =
|
|
12866
|
-
const configFile =
|
|
12328
|
+
const configDir = path12.join(os5.homedir(), ".config", "shiva-code");
|
|
12329
|
+
const configFile = path12.join(configDir, "config.json");
|
|
12867
12330
|
if (!fs11.existsSync(configDir)) {
|
|
12868
12331
|
return {
|
|
12869
12332
|
name: "SHIVA Config",
|
|
@@ -12887,7 +12350,7 @@ function checkShivaConfig() {
|
|
|
12887
12350
|
};
|
|
12888
12351
|
}
|
|
12889
12352
|
function checkClaudeProjects() {
|
|
12890
|
-
const claudeDir =
|
|
12353
|
+
const claudeDir = path12.join(os5.homedir(), ".claude", "projects");
|
|
12891
12354
|
if (!fs11.existsSync(claudeDir)) {
|
|
12892
12355
|
return {
|
|
12893
12356
|
name: "Claude Projects",
|
|
@@ -12898,7 +12361,7 @@ function checkClaudeProjects() {
|
|
|
12898
12361
|
}
|
|
12899
12362
|
try {
|
|
12900
12363
|
const projects = fs11.readdirSync(claudeDir).filter(
|
|
12901
|
-
(f) => fs11.statSync(
|
|
12364
|
+
(f) => fs11.statSync(path12.join(claudeDir, f)).isDirectory()
|
|
12902
12365
|
);
|
|
12903
12366
|
return {
|
|
12904
12367
|
name: "Claude Projects",
|
|
@@ -12931,11 +12394,11 @@ function checkTmux() {
|
|
|
12931
12394
|
};
|
|
12932
12395
|
}
|
|
12933
12396
|
function getSystemInfo() {
|
|
12934
|
-
const totalMem =
|
|
12397
|
+
const totalMem = os5.totalmem();
|
|
12935
12398
|
const memGB = (totalMem / (1024 * 1024 * 1024)).toFixed(1);
|
|
12936
12399
|
return {
|
|
12937
|
-
os: `${
|
|
12938
|
-
arch:
|
|
12400
|
+
os: `${os5.type()} ${os5.release()}`,
|
|
12401
|
+
arch: os5.arch(),
|
|
12939
12402
|
memory: `${memGB} GB`
|
|
12940
12403
|
};
|
|
12941
12404
|
}
|
|
@@ -13027,14 +12490,14 @@ var doctorCommand = new Command27("doctor").description("System-Check f\xFCr SHI
|
|
|
13027
12490
|
import { Command as Command28 } from "commander";
|
|
13028
12491
|
import { execSync as execSync5, spawn as spawn6 } from "child_process";
|
|
13029
12492
|
import * as fs12 from "fs";
|
|
13030
|
-
import * as
|
|
12493
|
+
import * as path13 from "path";
|
|
13031
12494
|
import { fileURLToPath } from "url";
|
|
13032
12495
|
var __filename = fileURLToPath(import.meta.url);
|
|
13033
|
-
var __dirname =
|
|
12496
|
+
var __dirname = path13.dirname(__filename);
|
|
13034
12497
|
var PACKAGE_NAME = "shiva-code";
|
|
13035
12498
|
function getCurrentVersion() {
|
|
13036
12499
|
try {
|
|
13037
|
-
const packageJsonPath =
|
|
12500
|
+
const packageJsonPath = path13.resolve(__dirname, "../../package.json");
|
|
13038
12501
|
if (fs12.existsSync(packageJsonPath)) {
|
|
13039
12502
|
const packageJson = JSON.parse(fs12.readFileSync(packageJsonPath, "utf-8"));
|
|
13040
12503
|
return packageJson.version || "0.0.0";
|
|
@@ -13179,8 +12642,8 @@ var selfUpdateCommand = new Command28("self-update").description('Alias f\xFCr "
|
|
|
13179
12642
|
|
|
13180
12643
|
// src/commands/system/telemetry.ts
|
|
13181
12644
|
import { Command as Command29 } from "commander";
|
|
13182
|
-
import
|
|
13183
|
-
var telemetryConfig = new
|
|
12645
|
+
import Conf4 from "conf";
|
|
12646
|
+
var telemetryConfig = new Conf4({
|
|
13184
12647
|
projectName: "shiva-code",
|
|
13185
12648
|
projectSuffix: "",
|
|
13186
12649
|
configName: "telemetry",
|
|
@@ -13434,9 +12897,9 @@ complete -F _shiva_completions shiva
|
|
|
13434
12897
|
}
|
|
13435
12898
|
async function installBashCompletion() {
|
|
13436
12899
|
const fs15 = await import("fs");
|
|
13437
|
-
const
|
|
13438
|
-
const
|
|
13439
|
-
const bashrcPath =
|
|
12900
|
+
const os7 = await import("os");
|
|
12901
|
+
const path15 = await import("path");
|
|
12902
|
+
const bashrcPath = path15.join(os7.homedir(), ".bashrc");
|
|
13440
12903
|
const completionScript = generateBashCompletion();
|
|
13441
12904
|
const marker = "# SHIVA Code Bash Completion";
|
|
13442
12905
|
try {
|
|
@@ -13577,9 +13040,9 @@ compdef _shiva shiva
|
|
|
13577
13040
|
}
|
|
13578
13041
|
async function installZshCompletion() {
|
|
13579
13042
|
const fs15 = await import("fs");
|
|
13580
|
-
const
|
|
13581
|
-
const
|
|
13582
|
-
const zshrcPath =
|
|
13043
|
+
const os7 = await import("os");
|
|
13044
|
+
const path15 = await import("path");
|
|
13045
|
+
const zshrcPath = path15.join(os7.homedir(), ".zshrc");
|
|
13583
13046
|
const completionScript = generateZshCompletion();
|
|
13584
13047
|
const marker = "# SHIVA Code Zsh Completion";
|
|
13585
13048
|
try {
|
|
@@ -13682,10 +13145,10 @@ complete -c shiva -n "__fish_seen_subcommand_from stats" -l json -d "JSON Output
|
|
|
13682
13145
|
}
|
|
13683
13146
|
async function installFishCompletion() {
|
|
13684
13147
|
const fs15 = await import("fs");
|
|
13685
|
-
const
|
|
13686
|
-
const
|
|
13687
|
-
const fishCompletionsDir =
|
|
13688
|
-
const fishCompletionPath =
|
|
13148
|
+
const os7 = await import("os");
|
|
13149
|
+
const path15 = await import("path");
|
|
13150
|
+
const fishCompletionsDir = path15.join(os7.homedir(), ".config", "fish", "completions");
|
|
13151
|
+
const fishCompletionPath = path15.join(fishCompletionsDir, "shiva.fish");
|
|
13689
13152
|
const completionScript = generateFishCompletion();
|
|
13690
13153
|
try {
|
|
13691
13154
|
if (!fs15.existsSync(fishCompletionsDir)) {
|
|
@@ -14093,8 +13556,8 @@ dockerCommand.action(() => {
|
|
|
14093
13556
|
// src/commands/advanced/workflow.ts
|
|
14094
13557
|
import { Command as Command33 } from "commander";
|
|
14095
13558
|
import * as fs13 from "fs";
|
|
14096
|
-
import * as
|
|
14097
|
-
import * as
|
|
13559
|
+
import * as path14 from "path";
|
|
13560
|
+
import * as os6 from "os";
|
|
14098
13561
|
import ora20 from "ora";
|
|
14099
13562
|
import inquirer12 from "inquirer";
|
|
14100
13563
|
var builtInWorkflows = {
|
|
@@ -14253,7 +13716,7 @@ workflowCommand.command("delete").alias("rm").description("Workflow l\xF6schen")
|
|
|
14253
13716
|
log.success(`Workflow "${name}" gel\xF6scht`);
|
|
14254
13717
|
});
|
|
14255
13718
|
function getWorkflowsPath() {
|
|
14256
|
-
return
|
|
13719
|
+
return path14.join(os6.homedir(), ".shiva", "workflows.json");
|
|
14257
13720
|
}
|
|
14258
13721
|
function loadCustomWorkflows() {
|
|
14259
13722
|
const filepath = getWorkflowsPath();
|
|
@@ -14269,7 +13732,7 @@ function loadCustomWorkflows() {
|
|
|
14269
13732
|
}
|
|
14270
13733
|
function saveCustomWorkflow(name, workflow) {
|
|
14271
13734
|
const filepath = getWorkflowsPath();
|
|
14272
|
-
const dir =
|
|
13735
|
+
const dir = path14.dirname(filepath);
|
|
14273
13736
|
if (!fs13.existsSync(dir)) {
|
|
14274
13737
|
fs13.mkdirSync(dir, { recursive: true });
|
|
14275
13738
|
}
|
|
@@ -14372,9 +13835,9 @@ async function executeStep(step) {
|
|
|
14372
13835
|
// src/commands/advanced/hook.ts
|
|
14373
13836
|
import { Command as Command34 } from "commander";
|
|
14374
13837
|
import { existsSync as existsSync21, readFileSync as readFileSync10, writeFileSync as writeFileSync10, mkdirSync as mkdirSync6 } from "fs";
|
|
14375
|
-
import { homedir as
|
|
14376
|
-
import { join as
|
|
14377
|
-
var CLAUDE_SETTINGS_PATH =
|
|
13838
|
+
import { homedir as homedir7 } from "os";
|
|
13839
|
+
import { join as join12 } from "path";
|
|
13840
|
+
var CLAUDE_SETTINGS_PATH = join12(homedir7(), ".claude", "settings.json");
|
|
14378
13841
|
function getClaudeSettings() {
|
|
14379
13842
|
if (!existsSync21(CLAUDE_SETTINGS_PATH)) {
|
|
14380
13843
|
return {};
|
|
@@ -14387,7 +13850,7 @@ function getClaudeSettings() {
|
|
|
14387
13850
|
}
|
|
14388
13851
|
}
|
|
14389
13852
|
function saveClaudeSettings(settings) {
|
|
14390
|
-
const dir =
|
|
13853
|
+
const dir = join12(homedir7(), ".claude");
|
|
14391
13854
|
if (!existsSync21(dir)) {
|
|
14392
13855
|
mkdirSync6(dir, { recursive: true });
|
|
14393
13856
|
}
|
|
@@ -14408,7 +13871,7 @@ function removeShivaHooks(eventHooks) {
|
|
|
14408
13871
|
var hookCommand = new Command34("hook").description("Claude Code Hook Integration verwalten");
|
|
14409
13872
|
hookCommand.command("install").description("SHIVA Hooks in Claude Code installieren").option("--github", "GitHub Context Injection aktivieren").option("--sync", "Cloud Sync Hooks aktivieren (Standard)").option("--scan", "Package Security Scanning aktivieren").option("--all", "Alle Hooks aktivieren").action((options) => {
|
|
14410
13873
|
log.brand();
|
|
14411
|
-
const claudePath =
|
|
13874
|
+
const claudePath = join12(homedir7(), ".claude");
|
|
14412
13875
|
if (!existsSync21(claudePath)) {
|
|
14413
13876
|
log.error("Claude Code nicht gefunden");
|
|
14414
13877
|
log.newline();
|
|
@@ -14646,8 +14109,8 @@ hookCommand.command("inject-context").description("GitHub Context in Session inj
|
|
|
14646
14109
|
return;
|
|
14647
14110
|
}
|
|
14648
14111
|
if (hasShivaDir(projectPath)) {
|
|
14649
|
-
const
|
|
14650
|
-
if (!
|
|
14112
|
+
const config = getProjectConfig(projectPath);
|
|
14113
|
+
if (!config.autoInjectContext) {
|
|
14651
14114
|
console.log(JSON.stringify({}));
|
|
14652
14115
|
return;
|
|
14653
14116
|
}
|
|
@@ -14718,8 +14181,8 @@ hookCommand.command("branch-switch").description("Branch-Wechsel behandeln (f\xF
|
|
|
14718
14181
|
}
|
|
14719
14182
|
});
|
|
14720
14183
|
hookCommand.command("scan-command").description("Scanne Bash-Befehle auf Package-Installationen (f\xFCr Hook)").argument("<command>", "Der zu scannende Befehl").action(async (command) => {
|
|
14721
|
-
const
|
|
14722
|
-
if (!
|
|
14184
|
+
const config = packageScanner.getConfig();
|
|
14185
|
+
if (!config.enabled) {
|
|
14723
14186
|
console.log(JSON.stringify({ hookSpecificOutput: null }));
|
|
14724
14187
|
return;
|
|
14725
14188
|
}
|
|
@@ -14739,6 +14202,85 @@ hookCommand.command("scan-command").description("Scanne Bash-Befehle auf Package
|
|
|
14739
14202
|
console.log(JSON.stringify({ hookSpecificOutput: null }));
|
|
14740
14203
|
}
|
|
14741
14204
|
});
|
|
14205
|
+
hookCommand.command("push").description("Hooks in Cloud sichern").action(async () => {
|
|
14206
|
+
const { api: api2 } = await import("./client-Z6ZMO5QE.js");
|
|
14207
|
+
const { isAuthenticated: isAuthenticated2 } = await import("./config-FGMZONWV.js");
|
|
14208
|
+
if (!isAuthenticated2()) {
|
|
14209
|
+
log.error("Nicht angemeldet");
|
|
14210
|
+
log.info("Anmelden mit: shiva login");
|
|
14211
|
+
return;
|
|
14212
|
+
}
|
|
14213
|
+
const settings = getClaudeSettings();
|
|
14214
|
+
if (!settings.hooks) {
|
|
14215
|
+
log.warn("Keine lokalen Hooks konfiguriert");
|
|
14216
|
+
return;
|
|
14217
|
+
}
|
|
14218
|
+
try {
|
|
14219
|
+
await api2.updateHooks(settings.hooks);
|
|
14220
|
+
log.success("Hooks in Cloud gesichert");
|
|
14221
|
+
} catch (error) {
|
|
14222
|
+
log.error(error instanceof Error ? error.message : "Fehler beim Sichern");
|
|
14223
|
+
}
|
|
14224
|
+
});
|
|
14225
|
+
hookCommand.command("pull").description("Hooks aus Cloud laden").option("-f, --force", "Lokale Hooks \xFCberschreiben").action(async (options) => {
|
|
14226
|
+
const { api: api2 } = await import("./client-Z6ZMO5QE.js");
|
|
14227
|
+
const { isAuthenticated: isAuthenticated2 } = await import("./config-FGMZONWV.js");
|
|
14228
|
+
if (!isAuthenticated2()) {
|
|
14229
|
+
log.error("Nicht angemeldet");
|
|
14230
|
+
log.info("Anmelden mit: shiva login");
|
|
14231
|
+
return;
|
|
14232
|
+
}
|
|
14233
|
+
const settings = getClaudeSettings();
|
|
14234
|
+
if (settings.hooks && !options.force) {
|
|
14235
|
+
log.warn("Lokale Hooks existieren bereits");
|
|
14236
|
+
log.info("Mit --force \xFCberschreiben");
|
|
14237
|
+
return;
|
|
14238
|
+
}
|
|
14239
|
+
try {
|
|
14240
|
+
const result = await api2.getHooks();
|
|
14241
|
+
if (!result.hooks || Object.keys(result.hooks).length === 0) {
|
|
14242
|
+
log.info("Keine Hooks in Cloud gefunden");
|
|
14243
|
+
return;
|
|
14244
|
+
}
|
|
14245
|
+
settings.hooks = result.hooks;
|
|
14246
|
+
saveClaudeSettings(settings);
|
|
14247
|
+
log.success("Hooks aus Cloud geladen");
|
|
14248
|
+
log.newline();
|
|
14249
|
+
log.info("Aktive Hooks:");
|
|
14250
|
+
for (const [event, hooks] of Object.entries(result.hooks)) {
|
|
14251
|
+
log.tree.item(`${event}: ${Array.isArray(hooks) ? hooks.length : 1} Hook(s)`);
|
|
14252
|
+
}
|
|
14253
|
+
} catch (error) {
|
|
14254
|
+
log.error(error instanceof Error ? error.message : "Fehler beim Laden");
|
|
14255
|
+
}
|
|
14256
|
+
});
|
|
14257
|
+
hookCommand.command("sync").description("Hooks mit Cloud synchronisieren").action(async () => {
|
|
14258
|
+
const { api: api2 } = await import("./client-Z6ZMO5QE.js");
|
|
14259
|
+
const { isAuthenticated: isAuthenticated2 } = await import("./config-FGMZONWV.js");
|
|
14260
|
+
if (!isAuthenticated2()) {
|
|
14261
|
+
log.error("Nicht angemeldet");
|
|
14262
|
+
log.info("Anmelden mit: shiva login");
|
|
14263
|
+
return;
|
|
14264
|
+
}
|
|
14265
|
+
const settings = getClaudeSettings();
|
|
14266
|
+
try {
|
|
14267
|
+
if (settings.hooks) {
|
|
14268
|
+
await api2.updateHooks(settings.hooks);
|
|
14269
|
+
log.success("Lokale Hooks \u2192 Cloud");
|
|
14270
|
+
}
|
|
14271
|
+
const result = await api2.getHooks();
|
|
14272
|
+
if (result.hooks && Object.keys(result.hooks).length > 0) {
|
|
14273
|
+
const merged = { ...result.hooks, ...settings.hooks };
|
|
14274
|
+
settings.hooks = merged;
|
|
14275
|
+
saveClaudeSettings(settings);
|
|
14276
|
+
log.success("Cloud Hooks \u2192 Lokal (merged)");
|
|
14277
|
+
}
|
|
14278
|
+
log.newline();
|
|
14279
|
+
log.success("Hooks synchronisiert");
|
|
14280
|
+
} catch (error) {
|
|
14281
|
+
log.error(error instanceof Error ? error.message : "Fehler beim Synchronisieren");
|
|
14282
|
+
}
|
|
14283
|
+
});
|
|
14742
14284
|
|
|
14743
14285
|
// src/commands/advanced/package.ts
|
|
14744
14286
|
import { Command as Command35 } from "commander";
|
|
@@ -14929,7 +14471,7 @@ function listPackages() {
|
|
|
14929
14471
|
|
|
14930
14472
|
// src/index.ts
|
|
14931
14473
|
var program = new Command36();
|
|
14932
|
-
program.name("shiva").description("SHIVA Code - Control Station for Claude Code").version("0.5.
|
|
14474
|
+
program.name("shiva").description("SHIVA Code - Control Station for Claude Code").version("0.5.3");
|
|
14933
14475
|
program.addCommand(loginCommand);
|
|
14934
14476
|
program.addCommand(logoutCommand);
|
|
14935
14477
|
program.addCommand(sessionsCommand);
|